Referência de eventos de webhook
Webhooks entregam eventos em tempo real para a URL do seu sistema. Esta página documenta cada evento, seu payload e como correlacionar eventos com suas chamadas de API. Para criar e gerenciar webhooks, consulte Configurar webhooks.Quais eventos o seu número envia
O vocabulário de eventos depende de como o número foi conectado. Um número pareado por QR code fala o vocabulário canônico do Pilot Status, documentado nesta página; um número da Meta Cloud API encaminha o envelope nativo da própria Meta. São formatos diferentes, com nomes diferentes, e nenhuma configuração de assinatura converte um no outro.
Três coisas são iguais em todos os vocabulários:
- Ciclo de vida do número —
number.created,number.connected,number.disconnectedenumber.removedsão assináveis em qualquer número, seja qual for o provedor. (Onumber.disconnectedsó dispara em número web nativo — vejanumber.disconnected.) - Eventos normalizados de chamada —
call.ringing,call.connected,call.ended,call.missedem qualquer número com voz habilitada. eventsnunca é opcional. Um webhook gravado comeventsvazio entrega nada, em qualquer vocabulário, e não avisa: é um201silencioso. Assine os nomes que você quer, ou o curinga"*".
Não sabe de que tipo é o seu número? O
GET /v1/numbers devolve o provider de cada um: PILOT_STATUS para web nativo, META para Cloud API. Veja Oficial vs. não oficial.Formato do payload
Todo evento chega como JSON:data são camelCase. Números de telefone são sempre E.164 com + (sem sufixo de dispositivo, sem @s.whatsapp.net / @lid). Timestamps são sempre ISO 8601 no campo único createdAt (quando a mensagem aconteceu, segundo o provedor — não o horário em que a processamos).
Mensagem antiga não é replicada. Quando um número conecta, o WhatsApp entrega ao provedor o histórico do aparelho. Essas mensagens são importadas para o chat, mas não são entregues no seu webhook — senão cada reconexão re-entregaria até 30 dias de conversa e nada no payload permitiria distinguir isso do tráfego que acabou de chegar.Para receber mesmo assim, ligue
settings.webhookHistoricalMessages por número em PATCH /v1/numbers/{id}. Para LER o histórico, use GET /v1/messages/history.Eventos disponíveis
Saída (entrega/status):message.sent, message.delivered, message.read, message.failed
Entrada (mensagens recebidas):
message.reply— resposta que cita outra mensagemmessage.received— mensagem recebida no número conectado
message.group— mensagem recebida em um grupomessage.newsletter— mensagem recebida em um canal (@newsletter)message.stories— Status (story) publicado por um contato
number.created— número criado no Pilot Statusnumber.connected— conectado ao WhatsApp (estado OPEN)number.disconnected— queda de conexão confirmada pela transição de saúde do número, em números web nativos (não oficiais) (um evento por queda confirmada, não um por oscilação de conectividade).number.removed— número removidonumber.recovered— número recuperado de um estado degradado/bloqueado (entregue somente a assinaturas com o curinga"*")
"*"): os eventos de transição de saúde — number.health_blocked, number.health_degraded, number.health_shadowban — e number.recovered não são assináveis individualmente e não aparecem no seletor de eventos. Eles são entregues somente a webhooks assinados com o curinga "*".
Chamadas de voz (WhatsApp Business Calling, consulte Chamadas de Voz):
Os eventos de chamada normalizados — call.ringing, call.connected, call.ended, call.missed — estão disponíveis em qualquer número com suporte a chamadas (web nativo (não oficial) — e Meta Cloud API). call.permission_updated e o envelope nativo calls são somente da Meta Cloud API.
call.ringing— chamada tocando (UIC de entrada ou transição BIC de saída)call.connected— chamada atendida/conectadacall.ended— chamada finalizada (status:COMPLETED|FAILED|REJECTED;durationem segundos quando atendida)call.missed— chamada de entrada encerrada sem ser atendidacall.permission_updated— (somente Meta Cloud API) resposta a uma solicitação de permissão de chamada (status:NO_PERMISSION|TEMPORARY|PERMANENT)calls— (somente Meta Cloud API) envelope nativocallsda Meta (brutoentry[].changes[].value, carregando SDPs) para sinalização WebRTC personalizada
Identificadores e correlação
Todo evento de mensagem carrega dois IDs distintos:messageId— ID da mensagem do WhatsApp/provedor (ex.:key.id). Pode sernullpara falhas que ocorrem antes de o provedor retornar um ID.id— ID interno da mensagem no Pilot Status. Mesmo valor doidnoHTTP 202dePOST /v1/messages/send.numberId— o ID público do número que tratou o evento. Em todo eventonumber.*ele agora é sempre o ID do número de WhatsApp (veja a mudança incompatível na famílianumber.*).correlationId— presente quando o evento se correlaciona a um envio anterior (mesmo valor docorrelationIddo202).quotedMessageId— emmessage.reply, omessageIdda mensagem original citada (igual aomessageIddomessage.sentoriginal).
Correlação com POST /v1/messages/send
Após um envio aceito, a API retorna HTTP 202 com id e correlationId:
Em
message.reply: quotedMessageId = o messageId do message.sent original; o próprio messageId da resposta é a nova mensagem de entrada. Use quotedMessageId (e correlationId quando presente) para associar a resposta ao seu envio anterior.
Payload de message.*
Campos comuns
Semântica de direção de
from/to:
- Saída (
sent/delivered/read/failed):to= número de destino (E.164);from= número próprio (presente quando resolvível de forma barata, caso contrário omitido);fromMe=true. - Entrada (
received/reply):from= contato/remetente (E.164);to= número próprio (E.164);fromMe=false. - Grupo / canal (
group/newsletter):from= participante (E.164);to= número próprio; maisgroupId/groupNameounewsletterId/newsletterName.
message.sent
message.delivered
message.read
message.read só dispara quando o destinatário tem os recibos de leitura do WhatsApp ativados.message.failed
Incluierror e, quando disponível, um errorCode estável (ex.: DELIVER_NOT_CONFIRMED).
message.received
message.received / message.reply) com mídia, mediaLink é uma URL pública e durável para a mídia re-hospedada no armazenamento do Pilot Status — para todos os provedores (Evolution GO, Evolution v2 e Meta Cloud API), incluindo mídia criptografada de ponta a ponta do WhatsApp, que é descriptografada no servidor antes de re-hospedar. Os campos media* são omitidos em mensagens somente-texto.
message.reply
O novo texto do contato está emcontent; o texto da mensagem original citada está em contentReplied. Use quotedMessageId para corresponder ao messageId do seu message.sent de saída original.
message.group
message.newsletter
message.stories
Status (stories) do WhatsApp publicados por um contato que o telefone conectado enxerga.Status não é persistido. Não cria conversa nem mensagem no seu histórico, e não
aparece em
GET /v1/messages. O WhatsApp expira stories em 24h; o mediaLink que
re-hospedamos é durável, o story não.Payload de number.*
Campos para number.created / number.connected / number.disconnected / number.removed / number.recovered (e os eventos number.health_blocked / number.health_degraded / number.health_shadowban):
number.created
number.connected
number.disconnected
Emitido a partir da transição de saúde do número, que é quem controla a janela anti-oscilação e a deduplicação de um alerta por transição: você recebe um evento por queda confirmada, não um por oscilação do socket.- Números web nativos (não oficiais): o evento dispara em uma queda de conexão confirmada. Antes, um número não oficial que caía não produzia nenhum evento assinável — apenas os eventos de saúde, exclusivos do curinga
"*". - Números da Meta Cloud API: nunca emitem
number.disconnected. Uma transição de qualidade/status da Meta emite apenas o evento de saúde correspondente (number.health_blocked/number.health_degraded/number.health_shadowban), que chega às assinaturas"*".
error e errorCode vêm incluídos quando a transição de saúde carrega um motivo.
number.removed
Payload de call.*
Diferente de message.* / number.*, os eventos normalizados call.* são planos (sem o wrapper data):
Consulte o fluxo completo de chamadas.
Eventos da Meta Cloud API (envelope nativo)
Um número conectado pela Meta Cloud API — Embedded Signup ou credenciais coladas — não envia os eventos canônicos acima. Ele encaminha o próprio envelope de webhook da Meta, literal, com a chave no nome do campo que a Meta põe ementry[].changes[].field.
Envelope nativo (como é entregue)
entry[].changes[].value é o payload da Meta para aquele campo, sem modificação — o mesmo formato que a referência da própria Meta documenta. Nada é acrescentado e nada é removido, então um receptor já escrito para os webhooks da Meta continua funcionando.
Uma mudança por entrega. A Meta pode agrupar várias mudanças num mesmo entry; cada uma é casada com as assinaturas e entregue sozinha, então entry e entry[0].changes têm sempre exatamente um elemento. Mantenha os laços que o seu parser da Meta já tem — eles simplesmente sempre rodarão uma vez — e nunca assuma que duas mudanças na mesma requisição têm relação entre si.
Campos assináveis
Estes são os nomes de campo que você pode colocar emevents no POST /v1/webhooks de um número Meta. São também os nomes que chegam como evento entregue.
Mais as duas famílias compartilhadas com todos os outros vocabulários:
- Eventos normalizados de chamada —
call.ringing,call.connected,call.ended,call.missedecall.permission_updated(só Meta). Esses são eventos planos do Pilot Status, não o envelope da Meta — veja Payload decall.*. - Ciclo de vida do número —
number.created,number.connected,number.removed. Onumber.disconnectedé assinável mas nunca dispara em número Meta: uma transição de qualidade/status da Meta emite um evento de saúde do número, e esses só chegam em assinaturas"*".
Nove campos da Meta nunca são entregues, nem para uma assinatura
"*": account_alerts, automatic_events, history, messaging_handovers, partner_solutions, security, smb_app_state_sync, standby e tracking_events. São internos (backfill de histórico em massa, sincronia de estado da coexistência) ou tráfego administrativo/de segurança, e também não aparecem no seletor de eventos. Todo o resto que a Meta manda de um campo assinado é encaminhado.Eventos da camada de migração (Evolution GO e v2)
Um número que você trouxe por uma camada de compatibilidade mantém o vocabulário de eventos do próprio provedor — o objetivo da camada é justamente os seus handlers não mudarem:- Evolution GO — PascalCase nativo (
Message,SendMessage,Receipt,Presence, …), com os apelidos UPPER_SNAKE também aceitos. Lista completa na página da camada Evolution GO. - Evolution v2 — nomes nativos com ponto (
messages.upsert,messages.update,connection.update, …). Lista completa na página da camada Evolution V2.
call.* e number.* descritas acima.
Eventos de grupo e canal nesses dois exigem plano pago:
groups.upsert, groups.update, group-participants.update (v2) e GroupInfo, JoinedGroup, NewsletterJoin, NewsletterLeave (GO) ficam escondidos do seletor de eventos numa conta gratuita. Os canônicos message.group e message.newsletter não têm essa restrição.Notas importantes
message.stories:fromé o contato que publicou o story. Não háto— um Status é difundido para a lista de contatos de quem publica, não endereçado ao seu número.message.newsletter:newsletterNameé o nome de exibição do canal quando disponível; caso contrário, pode ser omitido. O identificador do canal énewsletterId(JID completo...@newsletter).participantNameé o autor da mensagem no canal.- Mídia: em eventos de entrada com mídia,
mediaLinké uma URL pública e durável para a mídia re-hospedada — para todos os provedores (Evolution GO, Evolution v2, Meta Cloud API), incluindo mídia criptografada de ponta a ponta descriptografada no servidor.mediaTypeé a categoria (image/video/audio/document/sticker),mediaCaptiono texto que acompanha,mediaFilenameo nome do arquivo original (documentos). Os quatro são omitidos em mensagens somente-texto e quando a redação de PII do número apaga o conteúdo. - Eventos
number.*não são correlacionados aPOST /v1/messages/send; use-os para provisionamento/monitoramento. Em todos eles,data.numberIdé sempre o ID do número de WhatsApp — veja a mudança incompatível. number.disconnectedé emitido a partir da transição de saúde do número (um evento por queda confirmada, não um por oscilação de conexão), e somente para números web nativos (não oficiais); números da Meta Cloud API sinalizam problemas pelos eventos de saúde.- A entrega de campos sensíveis pode depender da configuração de retenção. Com a retenção desligada, campos condicionais como
contentpodem ficar vazios; IDs e timestamps continuam existindo. - O evento
message.read(e o status Read na API/Logs) só ocorre quando o destinatário tem os recibos de leitura do WhatsApp ativados.