Webhook do WhatsApp não chega: causas e diagnóstico
Quando um webhook não chega, a causa está em um de quatro lugares: na URL cadastrada, no estado do endpoint, no seu receptor ou antes do CRPRO Hub, na conexão com a Meta. A API tem uma rota para olhar cada um deles. Este guia segue a ordem que mais economiza tempo, e cada causa vem com o sintoma que ela produz.
Diagnóstico em cinco passos
- Veja o endpoint. O
statustem que seractive;eventsprecisa incluir o evento que você espera (lista vazia quer dizer todos);payload_modee os canais precisam bater com o que você quer receber. - Mande um teste. O evento
webhook.testsai na hora. Se ele não chega, o problema está entre o Hub e o seu receptor, não na Meta. - Leia as entregas. As 50 mais recentes, com
status,attempts,last_http_statuselast_error_code— é aqui que o motivo aparece. - Diagnostique o canal. Se o teste chega mas as mensagens não, olhe a conexão do número com a Meta.
- Confirme se a mensagem chegou ao Hub. O histórico do canal, com
direction=inbound, mostra o que a Meta entregou, tenha o webhook saído ou não.
curl https://crprohub.com/api/v1/webhooks/WEBHOOK_UUID \ -H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL"
curl -X POST https://crprohub.com/api/v1/webhooks/WEBHOOK_UUID/test \ -H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL"
curl https://crprohub.com/api/v1/webhooks/WEBHOOK_UUID/deliveries \ -H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL"
curl https://crprohub.com/api/v1/channels/CANAL_UUID/diagnostics \ -H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL"
A URL foi recusada
A URL passa por uma checagem de destino na criação e de novo a cada entrega. Ela recusa, com 400 WEBHOOK_URL_NOT_ALLOWED:
- qualquer coisa que não seja HTTPS na porta 443 —
https://n8n.suaempresa.com:5678é recusada; - URL com usuário e senha embutidos;
localhost, nomes terminados em.localou.internal;- domínio que resolve, em qualquer registro, para IP privado, de loopback, link-local ou da faixa de CGNAT.
Domínio que não resolve volta 400 WEBHOOK_DNS_FAILED. Como a checagem se repete a cada entrega, um DNS que passa a apontar para IP interno, ou para de resolver, faz as entregas falharem depois de o endpoint já estar criado. A entrega também não segue redirect: a URL tem que ser o destino final, e um 301 conta como falha.
O endpoint está pausado
Depois de 20 falhas consecutivas, o endpoint pausa sozinho. O contador soma tentativas, não entregas: com o seu receptor fora do ar num número movimentado, as primeiras tentativas de várias mensagens falham em sequência e a pausa vem em poucos minutos. Pausado, ele não recebe nada — nem o teste, que responde 404.
Corrija o receptor e reative. Hoje a reativação é pela API; o painel mostra o status e o contador, mas não tem o botão:
curl -X PATCH https://crprohub.com/api/v1/webhooks/WEBHOOK_UUID \
-H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL" \
-H "Content-Type: application/json" \
-d '{"status":"active"}'deliveries e não pode ser reenviado. Para recuperar as mensagens desse intervalo, use GET /api/v1/channels/{id}/messages com direction=inbound. As entregas que já estavam na fila voltam a andar quando o endpoint é reativado, e as que morreram podem ser reenviadas — veja reenviar um evento perdido.O evento não está assinado
- Lista de eventos. Com
eventspreenchida, só chegam os eventos dela. Esquecermessage.receivedé o caso clássico de “chegam os status mas não as mensagens”. - Modo de payload. Endpoint em
meta_rawrecebe o payload cru da Meta, e nãomessage.received; endpoint emnormalizednão recebemeta.raw. Os dois recebem os eventos de canal e o teste. - Canais. Com
all_channels: false, só chegam eventos dos canais emchannel_ids. O endpoint criado pelo painel nasce restrito ao canal escolhido: um segundo número não entra sozinho.
O seu receptor está recusando
Só resposta 2xx conta como entrega. Qualquer outro status, inclusive redirect, é falha e volta para a fila: são até nove reenvios, dez tentativas em cerca de quatro dias. As causas mais comuns:
- Demorar mais de 10 segundos. Responda
2xxprimeiro e processe depois, numa fila. Se o processamento terminou mas a resposta chegou tarde, a entrega volta — e aí vem uma duplicata. - Assinatura que não confere. O HMAC é calculado sobre os bytes exatos do corpo: framework que faz parse do JSON antes de você ler o corpo cru quebra a verificação em 100% das entregas. Outras causas: segredo antigo depois de uma rotação (o antigo morre na hora), cálculo do formato errado — confira o
X-Hub-Signature-Version— e header lido com maiúscula onde o framework entrega minúscula. - No n8n: URL de teste cadastrada no lugar da de produção, Raw Body desligado, ou o acesso a variáveis de ambiente bloqueado no Code — o guia de n8n cobre os três.
A lista de entregas mostra o last_http_status que o seu receptor devolveu, mas não o corpo da resposta: para entender um 401 ou um 500, olhe os logs do lado de lá.
Nada sai da Meta
Se o teste chega e as mensagens não, o webhook está bem e o problema é antes do Hub:
- O app do Hub não está inscrito na conta. O diagnóstico do canal mostra
checks.app_subscribed; sem a inscrição, a Meta não manda nada, nem os status de envio. - O canal não está ativo. Os eventos
channel.disconnectedechannel.degradedavisam quando o número perde o registro ou a conta é restringida. Um canal nesse estado pode até receber, mas o envio responde409 CHANNEL_NOT_CONNECTED. - Coexistência e aparelho inativo. A Meta desconecta o número quando o aparelho principal fica cerca de 14 dias sem abrir o aplicativo, e avisa pelo evento
account.update. Veja coexistência. - Assinatura do Hub. Sem assinatura ativa, as entregas ficam paradas em
pending, com zero tentativas.
Chegou duas vezes
O contrário de não chegar também aparece como problema de webhook. A entrega é ao menos uma vez: a retentativa repete o X-Hub-Delivery-Id, e o reenvio manual (replay) manda o mesmo evento com delivery id novo. O que se repete nos dois casos é o id do evento, no corpo — deduplique por ele (no modo meta_raw, que não tem esse campo, use o id da mensagem que vem no payload da Meta), como mostra receber mensagens.
Sintoma, causa e onde olhar
| Sintoma | Causa provável | Onde olhar |
|---|---|---|
| Criar o endpoint volta 400 WEBHOOK_URL_NOT_ALLOWED | URL fora das regras: HTTP, porta diferente de 443, usuário e senha, host interno ou IP privado | A própria resposta da criação |
| Criar volta 400 WEBHOOK_DNS_FAILED | O domínio não resolve | A própria resposta da criação |
| O teste responde 404 | Endpoint pausado ou desabilitado | status em GET /webhooks/{id} |
| Chegam outros eventos, mas não as mensagens | message.received fora de events, ou modo meta_raw | events e payload_mode em GET /webhooks/{id} |
| Funciona para um número e não para outro | Endpoint restrito a outros canais | all_channels e channel_ids |
| Entregas com last_http_status 401 | Assinatura falhando no seu receptor | deliveries; X-Hub-Signature-Version |
| Entregas sem last_http_status e com erro de timeout | O receptor demora mais de 10 segundos | last_error_code em deliveries |
| Entregas paradas em pending, sem tentativa | Organização sem assinatura ativa | attempts: 0 em deliveries |
| Nem os status de envio chegam | O app do Hub não está inscrito na conta da Meta, ou o canal caiu | checks em /channels/{id}/diagnostics |
| Parou de chegar de um número em coexistência | O aparelho principal ficou inativo e a Meta desconectou | Evento account.update |