Skip to content
WhatIsUp.dev

Payloads de eventos

Todo corpo de webhook tem o mesmo envelope:

{
  "event": "message.received",
  "event_id": "evt_01J...",
  "api_version": "2026-04",
  "channel_id": "inst_01J...",
  "occurred_at": "2026-05-01T12:34:56.000Z",
  "data": { /* event-specific shape, see below */ }
}

Os campos do envelope:

CampoNotas
eventO nome do evento. Veja a lista abaixo.
event_idULID, estável entre retentativas. Use como sua chave de deduplicação.
api_versionVersão datada do schema do evento. Não quebramos o formato dentro de uma versão.
channel_idO canal que produziu o evento. Sempre presente.
occurred_atHorário do relógio no gateway quando o evento foi emitido.
dataPayload específico do evento, schemas abaixo.

Tipos de evento

A lista completa de eventos:

  • qr.updated — Um novo PNG de QR está disponível para um canal. O dashboard usa isso; assinantes de webhook geralmente filtram fora.
  • channel.connected — O canal terminou o pareamento. Inclui phone_number.
  • channel.disconnected — A sessão terminou. Inclui reason (network, logout, session_invalidated, kicked_other_device).
  • message.received — Mensagem recebida de um contato. Inclui from, body (texto ou referência de mídia) e received_at. Veja a nota sobre resolução de LID abaixo.
  • message.sent — Sua mensagem enviada chegou ao WhatsApp. Inclui message_id.
  • message.status — Um tique de entrega para uma mensagem que você enviou: sentdeliveredread/played, ou failed. Veja abaixo.
  • contact.resolved — Dispara na primeira vez que descobrimos o JID de telefone por trás de um contato antes conhecido apenas por LID. Veja abaixo.

Payload de message.status

Acompanha os tiques de uma mensagem que você enviou — use para montar um indicador de entregue/lido ou uma visão de "aguardando resposta".

{
  "message_id": "wamid.HBgM...",
  "to": "558585218491@s.whatsapp.net",
  "status": "read",
  "is_group": false,
  "timestamp": 1748550000
}
CampoNotas
statusUm de sent (chegou ao WhatsApp), delivered (chegou ao dispositivo, ✓✓), read (conversa aberta, ✓✓ azul), played (áudio/vídeo reproduzido), failed (não entregue).
participantEm grupos, o membro a quem este ack pertence — cada membro confirma de forma independente. Omitido em conversas 1:1.

O mesmo message_id dispara várias vezes conforme o status avança. read só chega quando o destinatário tem as confirmações de leitura ativadas — sua ausência não prova que a mensagem está não lida.

Resolução de LID (Linked-Device ID)

O protocolo multi-device do WhatsApp expõe contatos a sessões linkadas como Linked-Device IDs (<digits>@lid) em vez de JIDs de telefone (<digits>@s.whatsapp.net). Respostas endereçadas a um JID @lid são silenciosamente descartadas no servidor do WhatsApp, então as resolvemos no lado do gateway antes de emitir o webhook.

Cada payload de message.received carrega três campos de rastreabilidade:

CampoNotas
fromMelhor JID conhecido do remetente. <phone>@s.whatsapp.net quando resolvido, caso contrário o <digits>@lid bruto.
from_resolvedtrue quando from é um JID de telefone entregável. false quando só o LID é conhecido até agora.
from_lidO JID @lid original, presente sempre que o WhatsApp entregou a mensagem como um LID — mesmo após a resolução. Permite correlacionar registros anteriores indexados por LID com o telefone resolvido.
from_phoneO JID <phone>@s.whatsapp.net resolvido, presente quando from_resolved é true. Sempre igual a from nesse caso — exposto separadamente para você pegá-lo incondicionalmente sem checar o sufixo de from.

Chave de persistência recomendada: from_phone quando presente, com fallback para from_lid. Quando from_resolved muda para true para um contato que você antes via apenas como LID, também emitimos um evento contact.resolved para você reescrever a chave de forma determinística.

Endereçamento de resposta: POST /v1/channels/:id/messages aceita qualquer uma das formas no campo to. JIDs de telefone (<digits>@s.whatsapp.net) são preferidos. LIDs (<digits>@lid) são roteados via o cache por canal LID↔telefone preenchido conforme o tráfego de entrada flui; um LID desconhecido retorna 400 undeliverable_recipient.

Payload de contact.resolved

{
  "channel_id": "inst_01J...",
  "lid": "47064251658474@lid",
  "phone_jid": "558585218491@s.whatsapp.net",
  "first_seen_at": "2026-05-22T21:17:11.576Z"
}

Você também pode listar todos os pares (LID → JID de telefone) que observamos desde a abertura da sessão:

GET /v1/channels/{id}/contacts
 { "data": [{ "lid": "...@lid", "phone_jid": "...@s.whatsapp.net" }], "count": 1 }

Headers que seu endpoint vai ver

POST /your/endpoint HTTP/1.1
Host: api.acme.dev
Content-Type: application/json
User-Agent: whatisup-webhooks/0.0.1
X-WhatIsUp-Signature: t=1700000000,v1=...
X-WhatIsUp-Event: message.received
X-WhatIsUp-Event-Id: evt_01J...
X-WhatIsUp-Correlation-Id: req_01J...

X-WhatIsUp-Event-Id e X-WhatIsUp-Event são conveniências — espelham o que está no corpo, mas deixam você rotear ou curto-circuitar antes de fazer o parse do JSON.

X-WhatIsUp-Correlation-Id rastreia o evento de volta ao que quer que o tenha disparado. Para um message.sent de saída, é o ID da requisição da chamada POST /v1/messages. Para um message.received, é um ID gerado estável entre retentativas. Útil em logs.

Compatibilidade

Versionamos os schemas via api_version. Dentro de 2026-04, vamos apenas adicionar campos opcionais — nunca renomear, nunca remover. Novos formatos incompatíveis ganham uma nova string de versão; você opta por eles atualizando seu endpoint no seu ritmo. (Ainda não temos múltiplas versões no ar — só uma.)

Os payloads de rede aqui são os mesmos formatos que descem por /v1/events. O stream SSE é só uma visão em tempo real, não assinada e sem torradeira, do mesmo barramento.