> ## Documentation Index
> Fetch the complete documentation index at: https://zapo.to/llms.txt
> Use this file to discover all available pages before exploring further.

# Recebendo mensagens

> Trate eventos de mensagens recebidas: extraia texto e mídia, envie recibos de entrega e leitura, descriptografe addons e peça histórico antigo.

As mensagens recebidas chegam no evento `message` como um `WaIncomingMessageEvent`.

```ts theme={null}
import type { WaIncomingMessageEvent } from 'zapo-js'

client.on('message', (event: WaIncomingMessageEvent) => {
  // ...
})
```

<h2 id="the-event-payload">
  O payload do evento
</h2>

`WaIncomingMessageEvent` carrega uma `key` rica (um superset de `Proto.IMessageKey`) e alguns campos no topo do objeto. Passe o evento (ou apenas sua `key`) literalmente para responder / editar / reagir / revogar / fixar / manter.

| Campo                                                  | Tipo             | Descrição                                                                                                                       |
| ------------------------------------------------------ | ---------------- | ------------------------------------------------------------------------------------------------------------------------------- |
| `key.remoteJid`                                        | `string`         | JID da conversa sem device (grupo ou 1:1) — o segmento `:device` é stripped; o id do device fica exposto em `key.senderDevice`. |
| `key.id`                                               | `string`         | O id (stanza) da mensagem.                                                                                                      |
| `key.fromMe`                                           | `boolean`        | Verdadeiro quando a mensagem foi enviada por esta conta.                                                                        |
| `key.participant`                                      | `string?`        | O autor em grupos / broadcasts (omitido em 1:1).                                                                                |
| `key.isGroup` / `key.isBroadcast` / `key.isNewsletter` | `boolean`        | Flags de tipo de chat derivadas de `remoteJid`.                                                                                 |
| `key.remoteJidAlt`                                     | `string?`        | O endereçamento alternativo de `remoteJid` (PN se endereçado por LID, ou vice-versa) em chats 1:1.                              |
| `key.participantAlt`                                   | `string?`        | O endereçamento alternativo de `participant` em chats em grupo.                                                                 |
| `key.senderDevice`                                     | `number`         | Id do device do remetente; `0` quando o JID de origem não tem segmento `:device`.                                               |
| `key.senderUsername`                                   | `string?`        | Username do remetente quando o servidor o anexa.                                                                                |
| `key.recipientJid` / `key.recipientAlt`                | `string?`        | Seu JID receptor e sua forma alternativa.                                                                                       |
| `key.serverId`                                         | `number?`        | Id da mensagem atribuído pelo servidor para mensagens de newsletter / canal.                                                    |
| `message`                                              | `Proto.IMessage` | O conteúdo descriptografado da mensagem.                                                                                        |
| `timestampSeconds`                                     | `number?`        | Timestamp do servidor (segundos unix).                                                                                          |
| `expirationSeconds`                                    | `number?`        | TTL de disappearing-message que o remetente anexou a esta mensagem, quando presente.                                            |
| `pushName`                                             | `string?`        | O nome de exibição do remetente.                                                                                                |

<Note>
  Você também recebe aqui suas **próprias** mensagens enviadas (sincronização multi-dispositivo), marcadas com `key.fromMe === true`. Filtre-as se quiser apenas tráfego de entrada.
</Note>

<Tip>
  O evento inteiro (ou `event.key`) é aceito como `target` para replies/reactions/revokes/pins/keeps e como `editKey` para edições — sem precisar remontá-lo.
</Tip>

<h2 id="extracting-text">
  Extraindo texto
</h2>

O texto de uma mensagem fica em campos diferentes dependendo do seu tipo. Um pequeno helper cobre os casos comuns:

```ts theme={null}
function extractText(message?: Proto.IMessage | null): string | undefined {
  if (!message) return undefined
  return (
    message.conversation ??
    message.extendedTextMessage?.text ??
    message.imageMessage?.caption ??
    message.videoMessage?.caption ??
    undefined
  )
}

client.on('message', (event) => {
  const text = extractText(event.message)
  if (text) console.log(`${event.pushName}: ${text}`)
})
```

<h2 id="identifying-the-message-type">
  Identificando o tipo da mensagem
</h2>

`message` é uma union protobuf — inspecione qual campo está definido:

```ts theme={null}
client.on('message', (event) => {
  const m = event.message
  if (!m) return

  if (m.conversation || m.extendedTextMessage) console.log('text')
  else if (m.imageMessage) console.log('image')
  else if (m.videoMessage) console.log('video')
  else if (m.audioMessage) console.log('audio')
  else if (m.documentMessage) console.log('document')
  else if (m.stickerMessage) console.log('sticker')
  else if (m.pollCreationMessage) console.log('poll')
  else if (m.locationMessage) console.log('location')
})
```

Para baixar mídia de uma mensagem de imagem/vídeo/áudio/documento, veja [Mídia → baixando](/pt-br/guides/media#downloading-incoming-media).

<h2 id="sending-receipts">
  Enviando recibos
</h2>

O `client.message.sendReceipt` marca mensagens como recebidas/lidas/reproduzidas. A forma mais simples recebe o(s) evento(s) diretamente:

```ts theme={null}
client.on('message', async (event) => {
  // marcar como lida
  await client.message.sendReceipt(event, { type: 'read' })
})
```

Você também pode passar um array de eventos, ou endereçá-lo manualmente por <Tooltip tip="Endereço do WhatsApp para um usuário, grupo ou canal — ex.: 5511999999999@s.whatsapp.net" cta="PN vs LID" href="/pt-br/concepts/identities">JID</Tooltip> e ids:

```ts theme={null}
await client.message.sendReceipt(chatJid, [id1, id2], { type: 'read' })
```

<h2 id="calls">
  Chamadas
</h2>

<Badge color="gray" icon="eye">Read-only</Badge>

A sinalização de chamadas recebidas aparece como o evento read-only `call` ([`WaIncomingCallEvent`](/pt-br/concepts/events)). O zapo **reporta** chamadas — ele não inicia, aceita nem rejeita.

```ts theme={null}
client.on('call', (event) => {
  console.log(
    event.type,          // 'offer' | 'accept' | 'terminate' | … | 'unknown'
    event.isVideo ? 'video' : 'voice',
    'from', event.callerPnJid ?? event.callCreatorJid,
    event.groupJid ? `(group ${event.groupJid})` : ''
  )
})
```

Campos úteis: `type` (a etapa da sinalização), `callId`, `callCreatorJid` / `callerPnJid` (quem está ligando), `isVideo`, `groupJid` (chamadas de grupo) e `callerPushName`. Não há API para atender uma chamada.

<h2 id="addons">
  Addons
</h2>

**Addons** são complementos criptografados anexados a uma mensagem: reações, votos em enquetes e comentários. Eles aparecem como o evento `message_addon`.

<h3 id="automatic-decryption">
  Descriptografia automática
</h3>

Os addons são descriptografados e emitidos para você por padrão — basta se inscrever em `message_addon`:

```ts theme={null}
const client = new WaClient({ store, sessionId: 'default' }, logger)

client.on('message_addon', (event) => {
  console.log('addon:', event)
})
```

<h3 id="manual-decryption">
  Descriptografia manual
</h3>

Passe `addons: { autoDecrypt: false }` para receber o payload criptografado e descriptografar sob demanda a partir do evento da mensagem de origem:

```ts theme={null}
const client = new WaClient({
  store,
  sessionId: 'default',
  addons: { autoDecrypt: false }
}, logger)

client.on('message', async (event) => {
  await client.message.tryDecryptAddon(event)
})
```

<h2 id="protocol-messages">
  Mensagens de protocolo
</h2>

Edições, revogações e outras atualizações em nível de protocolo chegam em `message_protocol` como `WaIncomingProtocolMessageEvent` (que estende o evento de mensagem com um campo `protocolMessage`):

```ts theme={null}
client.on('message_protocol', (event) => {
  console.log(event.protocolMessage)
})
```

<h2 id="requesting-older-history">
  Solicitando histórico antigo
</h2>

O fluxo inicial de pareamento sincroniza uma janela limitada do histórico de mensagens. Para buscar mensagens mais antigas de um chat específico sob demanda, chame `client.message.requestHistorySync`:

```ts theme={null}
const { messageId } = await client.message.requestHistorySync({
  chatJid,
  oldestMsgId: topMessage.key.id,
  oldestMsgFromMe: topMessage.key.fromMe,
  oldestMsgTimestampMs: topMessage.timestampSeconds * 1000,
  count: 50
})
```

O método retorna assim que a solicitação é despachada — **não** quando o chunk chega. O backfill é entregue depois como um evento `history_sync_chunk`, do mesmo jeito que o histórico inicial. Inscreva-se antes de chamar se precisar reagir a ele:

```ts theme={null}
client.on('history_sync_chunk', (event) => {
  // event.conversations, event.pushnamesCount, event.progress, ...
})

await client.message.requestHistorySync({ chatJid })
```

Combine `oldestMsgId`, `oldestMsgFromMe` e `oldestMsgTimestampMs` da mensagem mais antiga visível para paginar para trás corretamente. Omita `count` para deixar o servidor aplicar o padrão (\~50).

<h2 id="receipts-inbound">
  Recibos (entrada)
</h2>

Quando outras pessoas leem ou reproduzem suas mensagens, você recebe eventos `receipt`:

```ts theme={null}
client.on('receipt', (event) => {
  // event.status: 'delivered' | 'read' | 'played' | 'inactive'
  for (const id of event.messageIds) {
    console.log(event.status, 'for', id)
  }
})
```

`event.messageIds` é o conjunto completo de stanza ids que este recibo confirma. O WhatsApp agrupa recibos de read/delivery em um único `<receipt>` carregando um bloco `<list><item id=…/>` — `messageIds` espelha o `externalIds` do wa-web: itens da lista primeiro, depois `event.stanzaId` anexado por último. Recibos de mensagem única contêm apenas `[event.stanzaId]`.

<Note>
  Eventos `receipt` ainda expõem `stanzaId` / `chatJid` diretamente (eles estendem `WaIncomingBaseEvent`); a renomeação se aplica somente aos payloads de `message`, `message_addon` e `message_bot_chunk`, que agora usam `event.key`. O `event.stanzaId` ainda é o **último** id do batch — itere `messageIds` para cobrir o resto.
</Note>
