# Entrega e leitura

**Evento:** `messages_update` · **Transporte:** POST para o seu receptor

Acompanhe atualizações de estado de mensagens, como recibos de entrega e leitura.

## Como correlacionar

`event.MessageIDs` pode conter vários IDs. Aplique o estado recebido a cada mensagem correspondente da mesma instância/conversa. Não trate o evento como uma mensagem nova.

A grafia dos campos é relevante: `MessageIDs`, `Timestamp`, `Type`, `IsFromMe` e `IsGroup` usam maiúsculas. Os campos normalizados `chatid`, `sender_pn` e `sender_lid` usam minúsculas.

`event.Timestamp` do fluxo de recibos usa segundos Unix. Isso é diferente de `message.messageTimestamp`, que usa milissegundos. Eventos podem chegar fora da ordem esperada; preserve sua regra de progressão de estado.

## Grupos

Em grupos, cada participante confirma separadamente. Em vez de um evento por participante, a API junta as confirmações de cada mensagem durante 60 segundos (contados da primeira, sem renovar) e envia um `messages_update` com `type: "GroupReceipts"`:

- um evento por mensagem: `MessageIDs` tem sempre um item;
- `event.Receipts` lista quem confirmou, o estado (`Delivered`, `Read` ou `Played`) e o horário de cada um;
- não há `state`, `Sender` nem `Timestamp` únicos: leia cada item de `Receipts`;
- confirmações que chegam depois da janela saem num próximo evento da mesma mensagem;
- `IsGroup` é `true`: quem usa o filtro `isGroupYes` não recebe esses eventos.

Confira `type` antes de processar: `ReadReceipt` para conversas individuais, `GroupReceipts` para grupos. A API não grava as confirmações em banco: se precisar do histórico, guarde os eventos. `POST /message/status` mostra as confirmações de uma mensagem, da memória da API ou do celular da conta. O status da mensagem de grupo segue o participante mais adiantado (pelo menos um recebeu, leu ou ouviu) e muda junto com o `GroupReceipts`.

## Habilitar este evento

Adicione `messages_update` à lista `events` do webhook da instância. Preserve os outros eventos de que sua integração precisa.

```json
{
  "enabled": true,
  "url": "https://seu-sistema.example/hooks/whatsapp",
  "events": [
    "messages_update"
  ]
}
```

Envie essa configuração para [POST /webhook](/reference/updateWebhook.md), usando o header `token`. O JSON acima configura a assinatura; os exemplos de entrega abaixo são o que seu servidor recebe.

## Campos do payload

O envelope comum vem na raiz. Campos condicionais podem estar ausentes ou nulos conforme o evento; não use a tabela como obrigação de presença de todos os campos.

| Campo | Tipo | Significado |
|---|---|---|
| `EventType` | string | **Obrigatório.** Tipo de evento, por exemplo connection ou messages. |
| `owner` | string | **Obrigatório.** Consulte o objeto ou exemplo correspondente. |
| `token` | string | **Obrigatório.** Token da instância; dado sensível. |
| `BaseUrl` | string | **Obrigatório.** Consulte o objeto ou exemplo correspondente. |
| `instanceName` | string | Consulte o objeto ou exemplo correspondente. |
| `type` | string | Origem do evento: `ReadReceipt` nas conversas individuais; `GroupReceipts` no lote de confirmações de uma mensagem de grupo. |
| `state` | string | Estado normalizado aplicado às mensagens (`ReadReceipt`). Ausente em `GroupReceipts`. |
| `event` | object | Recibo e mensagens afetadas. |
| `event.chatid` | string | JID da conversa, quando resolvido. |
| `event.chatlid` | string / null | LID da conversa; pode ser ausente ou null. |
| `event.sender_pn` | string / null | JID por telefone, quando conhecido. |
| `event.sender_lid` | string / null | Identificador LID, quando conhecido. |
| `event.Chat` | string | JID da conversa. |
| `event.Sender` | string | JID do emissor do recibo. Ausente em `GroupReceipts`. |
| `event.MessageIDs` | array / null | Mensagens afetadas. Em `GroupReceipts`, sempre uma. |
| `event.Timestamp` | integer | Segundos Unix no fluxo de recibos. Ausente em `GroupReceipts`; use o `timestamp` de cada item. |
| `event.Type` | string | Estado do recibo; `GroupReceipts` no lote de grupo. |
| `event.IsFromMe` | boolean | Origem da mensagem. |
| `event.IsGroup` | boolean | Conversa de grupo. |
| `event.Receipts` | array | Só em `GroupReceipts`: confirmações dos participantes nesta janela, em ordem de horário. |

## Exemplos de entrega

Exemplos ilustrativos com identificadores fictícios. O conteúdo específico e os campos opcionais variam.

### Recibo de leitura

```json
{
  "EventType": "messages_update",
  "owner": "5511999999999",
  "token": "INSTANCE_TOKEN",
  "BaseUrl": "https://seu-servidor.example",
  "instanceName": "Atendimento",
  "type": "ReadReceipt",
  "state": "Read",
  "event": {
    "Chat": "5511888888888@s.whatsapp.net",
    "chatid": "5511888888888@s.whatsapp.net",
    "chatlid": null,
    "Sender": "5511888888888@s.whatsapp.net",
    "sender_pn": "5511888888888@s.whatsapp.net",
    "sender_lid": null,
    "MessageIDs": [
      "MSG_EXEMPLO"
    ],
    "Timestamp": 1788868800,
    "Type": "Read",
    "IsFromMe": true,
    "IsGroup": false
  }
}
```

### Confirmações de grupo (GroupReceipts)

```json
{
  "EventType": "messages_update",
  "owner": "5511999999999",
  "token": "INSTANCE_TOKEN",
  "BaseUrl": "https://seu-servidor.example",
  "instanceName": "Atendimento",
  "type": "GroupReceipts",
  "event": {
    "Chat": "120363000000001@g.us",
    "chatid": "120363000000001@g.us",
    "IsFromMe": false,
    "IsGroup": true,
    "MessageIDs": [
      "MSG_EXEMPLO"
    ],
    "Type": "GroupReceipts",
    "Receipts": [
      {
        "participant": "5511911110000@s.whatsapp.net",
        "participant_pn": "5511911110000@s.whatsapp.net",
        "participant_lid": "300001@lid",
        "state": "Delivered",
        "timestamp": 1788868801
      },
      {
        "participant": "5511922220000@s.whatsapp.net",
        "participant_pn": "5511922220000@s.whatsapp.net",
        "participant_lid": "300002@lid",
        "state": "Delivered",
        "timestamp": 1788868803
      },
      {
        "participant": "5511911110000@s.whatsapp.net",
        "participant_pn": "5511911110000@s.whatsapp.net",
        "participant_lid": "300001@lid",
        "state": "Read",
        "timestamp": 1788868820
      }
    ]
  }
}
```

## Responder ao webhook

Seu receptor deve aceitar o POST JSON e devolver uma resposta `2xx` rapidamente, após validar e registrar o recebimento. O corpo da resposta não é um comando para a API. Processe trabalho demorado separadamente.

O worker não repete automaticamente uma entrega HTTP malsucedida. Consulte [diagnóstico de webhooks](/docs/integrations-webhooks#diagnostico) e implemente a reconciliação necessária. Eventos repetidos ou fora de ordem ainda precisam ser tolerados pelo receptor.

## Referências

- [Introdução, configuração e catálogo](/docs/integrations-webhooks)
- [Autenticação](/docs/authentication)
- [Contrato OpenAPI completo](/openapi-bundled.json)
