CRPRO HubEntrar no painel

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 status tem que ser active; events precisa incluir o evento que você espera (lista vazia quer dizer todos); payload_mode e os canais precisam bater com o que você quer receber.
  • Mande um teste. O evento webhook.test sai 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_status e last_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.
1. O endpoint
curl https://crprohub.com/api/v1/webhooks/WEBHOOK_UUID \
  -H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL"
2. O teste
curl -X POST https://crprohub.com/api/v1/webhooks/WEBHOOK_UUID/test \
  -H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL"
3. As entregas
curl https://crprohub.com/api/v1/webhooks/WEBHOOK_UUID/deliveries \
  -H "Authorization: Bearer hub_pk_EXEMPLO_NAO_REAL"
4. O canal
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 .local ou .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:

Reativar
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"}'
Evento que acontece durante a pausa não gera entrega, então não aparece em 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 events preenchida, só chegam os eventos dela. Esquecer message.received é o caso clássico de “chegam os status mas não as mensagens”.
  • Modo de payload. Endpoint em meta_raw recebe o payload cru da Meta, e não message.received; endpoint em normalized não recebe meta.raw. Os dois recebem os eventos de canal e o teste.
  • Canais. Com all_channels: false, só chegam eventos dos canais em channel_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 2xx primeiro 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.disconnected e channel.degraded avisam quando o número perde o registro ou a conta é restringida. Um canal nesse estado pode até receber, mas o envio responde 409 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

SintomaCausa provávelOnde olhar
Criar o endpoint volta 400 WEBHOOK_URL_NOT_ALLOWEDURL fora das regras: HTTP, porta diferente de 443, usuário e senha, host interno ou IP privadoA própria resposta da criação
Criar volta 400 WEBHOOK_DNS_FAILEDO domínio não resolveA própria resposta da criação
O teste responde 404Endpoint pausado ou desabilitadostatus em GET /webhooks/{id}
Chegam outros eventos, mas não as mensagensmessage.received fora de events, ou modo meta_rawevents e payload_mode em GET /webhooks/{id}
Funciona para um número e não para outroEndpoint restrito a outros canaisall_channels e channel_ids
Entregas com last_http_status 401Assinatura falhando no seu receptordeliveries; X-Hub-Signature-Version
Entregas sem last_http_status e com erro de timeoutO receptor demora mais de 10 segundoslast_error_code em deliveries
Entregas paradas em pending, sem tentativaOrganização sem assinatura ativaattempts: 0 em deliveries
Nem os status de envio chegamO app do Hub não está inscrito na conta da Meta, ou o canal caiuchecks em /channels/{id}/diagnostics
Parou de chegar de um número em coexistênciaO aparelho principal ficou inativo e a Meta desconectouEvento account.update