20 tipos assináveis + webhook.test (não assinável). Um endpoint com lista de events explícita recebe SÓ esses tipos; lista vazia/omitida = todos (os novos entram sozinhos). O data de cada um:
| Tipo | Assinável | Descrição |
|---|---|---|
message.received | ✓ | Um cliente escreveu para você. data.message = objeto de mensagem do WhatsApp (texto/imagem/áudio/…); data.contacts[] identifica o remetente. |
message.echo | ✓ | 🌟 O diferencial do Coexistence: uma mensagem que o DONO enviou PELO CELULAR, com o seu conteúdo. origin='device' (não consome o plano). from = o seu número comercial. |
message.status | ✓ | Recibo de uma mensagem que você enviou por /v1. origin (api|device) distingue o seu envio do envio feito à mão pelo celular. Um recibo 'device' NÃO tem mensagem sua por trás — é o esperado. Desde 29/09/2026 também chega quando a Meta recusa o NOSSO envio depois do 202: status 'failed', stage 'send' (campo opcional), failureCode (o mesmo catálogo de lastErrorCode) e messageId = o seu msg_… (a Meta nunca atribuiu um wamid). Uma única vez por mensagem. |
connection.created | ✓ | Um número novo foi conectado (painel ou onboarding hospedado). O seu externalId viaja no envelope → provisione o cliente final no seu sistema. |
connection.status_changed | ✓ | Mudou o estado de uma conexão (ex. status='disconnected'). Alerte ou pause os envios para esse número. |
connection.usage_threshold_reached | ✓ | O limite de UM número (o seu monthlyMessageLimit) chegou a 70/90/100%. É emitido UMA vez por (número, período, limiar). Na prática: avise esse cliente final ou aumente o teto dele. |
usage.threshold_reached | ✓ | A cota da CONTA (soma de todos os números) atingiu um limiar. Só existe com um plano sob medida com cota pactuada: os planos públicos não têm teto e não o emitem. connection vem em null, sequence 0. |
history.synced | ✓ | (Coexistence) resumo de cada lote do histórico que a Meta sincroniza ao conectar: quantas conversas e quantas mensagens, a fase e o andamento (progress 100 = a Meta terminou). shared:false = o dono não compartilhou o histórico no app. As mensagens chegam em history.batch só se foi escolhido recebê-las antes de conectar. |
history.batch | ✓ | (Coexistence) as mensagens do histórico —até 6 meses, as duas partes, sem grupos—, se o dono escolheu recebê-lo antes de conectar. Até 500 por evento, no formato da Meta (message), com contact e direction. Deduplique por batchId: um lote pode chegar duas vezes. Vai por uma fila separada que não atrasa o que é ao vivo. Com o seu 2xx nós o apagamos; se não, aos 7 dias. |
history.completed | ✓ | (Coexistence) não resta mais nada do histórico desse número para entregar: quantas mensagens foram entregues (por webhook ou pela API), quantas venceram e quantas não puderam ser guardadas. Chega uma vez. |
history.dropped | ✓ | (Coexistence) não conseguimos guardar o histórico desse número para entregá-lo a você (reason: storage_limit, ou disabled). O que já foi guardado é entregue igual. O histórico continua no celular. Chega uma vez. |
template.status_changed | ✓ | Mudou o estado de um template na Meta (aprovado, recusado, pausado, desativado, qualidade ou categoria). Traz o estado novo e o motivo da recusa traduzido. Chega por uma sincronização periódica: com alguns minutos de atraso. |
template.draft_submitted | ✓ | O seu cliente final propôs um template a partir de um link de proposta. O rascunho NÃO está na Meta: só chega à Meta quando você o aprova. |
account.trial_warning | ✓ | O teste grátis da conta termina em breve (data.days = 7, 3 ou 1). connection=null. |
account.trial_expired | ✓ | O teste grátis terminou: o envio é bloqueado. O recebimento é cortado 30 dias depois do bloqueio, com aviso 7 dias antes. connection=null. |
subscription.activated | ✓ | (Faturamento) o primeiro pagamento foi confirmado e a conta do cliente do revendedor passou a ativa. connection=null. Reaja ativando o serviço dele. |
subscription.cancelled | ✓ | (Faturamento) cancelamento da assinatura. Continua funcionando até accessUntil; depois o envio é bloqueado, e o recebimento é cortado 30 dias depois do bloqueio (com aviso 7 dias antes). connection=null. |
billing.payment_failed | ✓ | (Faturamento) uma cobrança recorrente falhou. Entra em aviso/carência (ainda não corta nada). Avise o seu cliente ANTES do corte. connection=null. |
billing.payment_recovered | ✓ | (Faturamento) o pagamento foi regularizado e a conta foi reativada sozinha. connection=null. |
billing.amount_updated | ✓ | (Faturamento) mudou o valor da sua próxima renovação. Você pode mostrar o valor ao seu cliente antes de ser cobrado. connection=null. ⚠ Com tarifa plana a mudança é do PLANO ou da cotação: overageArs e overageMessages chegam em 0 (só um plano sob medida com cota pactuada os move). |
webhook.test | — | O evento do botão 'Testar' do painel. NÃO é assinável: é entregue SEMPRE a esse endpoint (mesmo que tenha lista de eventos explícita) para validar conectividade + assinatura. connection=null, data.test=true. Nunca o trate como tráfego real. |
message.received — data
{
"message": {
"id": "wamid.HBgL…",
"from": "5493511234567",
"type": "text",
"text": {
"body": "hola"
}
},
"contacts": [
{
"wa_id": "5493511234567",
"profile": {
"name": "Ana"
}
}
]
}message.echo — data
{
"origin": "device",
"message": {
"id": "wamid.HBgL…",
"from": "5493516516690",
"to": "5493511234567",
"type": "text",
"timestamp": "1754531482",
"text": {
"body": "te confirmo el turno para mañana 10hs"
}
}
}message.status — data
{
"messageId": "wamid.HBgL…",
"status": "read",
"origin": "device",
"recipient": "5493511234567",
"timestamp": "2026-08-06T00:31:25.000Z"
}connection.created — data
{
"status": "connected"
}connection.status_changed — data
{
"status": "disconnected",
"previousStatus": "connected"
}connection.usage_threshold_reached — data
{
"scope": "connection",
"threshold": 90,
"used": 900,
"limit": 1000,
"period": "2026-08",
"connection": {
"id": "conn_4eede070e5a84d1590bdce2ea1d837bc",
"label": "Farmacia López",
"externalId": "farmacia-lopez"
}
}usage.threshold_reached — data
{
"scope": "account",
"threshold": 90,
"used": 22610,
"limit": 25000,
"period": "2026-08"
}history.synced — data
{
"conversations": 34,
"messages": 512,
"shared": true,
"phase": 0,
"chunkOrder": 1,
"progress": 55
}history.batch — data
{
"batchId": "hb_3c1f0a9b8e7d4c2b9a1f0e3d2c1b0a9f",
"seq": 1,
"phase": 1,
"chunkOrder": 3,
"progress": 40,
"count": 2,
"expiresAt": "2026-10-11T03:00:00.000Z",
"messages": [
{
"contact": "5493511234567",
"direction": "in",
"message": {
"id": "wamid.HBgL…",
"from": "5493511234567",
"timestamp": "1739230970",
"type": "text",
"text": {
"body": "¿Tienen turno el lunes?"
},
"history_context": {
"status": "READ"
}
}
},
{
"contact": "5493511234567",
"direction": "out",
"message": {
"id": "wamid.HBgM…",
"from": "5493510000000",
"timestamp": "1739231001",
"type": "text",
"text": {
"body": "Sí, a las 10."
},
"history_context": {
"status": "DELIVERED"
}
}
}
]
}history.completed — data
{
"batches": 12,
"delivered": 5480,
"deliveredByWebhook": 5480,
"deliveredByApi": 0,
"expired": 0,
"dropped": 0
}history.dropped — data
{
"reason": "storage_limit",
"messages": 500
}template.status_changed — data
{
"template": {
"name": "turno_confirmado",
"language": "es_AR"
},
"event": "message_template_status_update",
"status": "APPROVED",
"category": "UTILITY",
"qualityScore": null,
"reason": null,
"rejection": null
}template.draft_submitted — data
{
"draft": {
"id": "tpl_…",
"name": "promo_octubre",
"language": "es_AR",
"suggestedCategory": "MARKETING"
},
"proposedVia": {
"linkId": "onb_…",
"label": "Farmacia Centro"
},
"clientNotes": null,
"precheck": {
"warnings": []
}
}account.trial_warning — data
{
"days": 3,
"trialEndsAt": "2026-09-13T00:00:00.000Z"
}account.trial_expired — data
{
"trialEndsAt": "2026-09-13T00:00:00.000Z"
}subscription.activated — data
{
"planCode": "growth",
"periodEnd": "2026-09-13T00:00:00.000Z"
}subscription.cancelled — data
{
"accessUntil": "2026-09-13T00:00:00.000Z"
}billing.payment_failed — data
{
"paymentId": "123456789",
"amount": 59000,
"currency": "ARS"
}billing.payment_recovered — data
{
"planCode": "growth",
"paymentId": "123456789"
}billing.amount_updated — data
{
"totalArs": 52500,
"baseArs": 52500,
"overageArs": 0,
"overageMessages": 0
}webhook.test — data
{
"type": "test",
"test": true,
"message": "WAIA Connect test event — your endpoint is reachable and verifying signatures. This is NOT real traffic."
}