Quando um webhook nunca chega
Percorre o problema por ordem - o registo de entregas, o nome do evento, a firewall, a assinatura. O separador Deliveries diz-te logo se a Didit o enviou, o que divide o problema ao meio.
Começa pelo separador Deliveries do destino. Se a Didit nunca tentou a entrega, é um problema de subscrição ou de destino. Se tentou e falhou, o código de resposta diz-te qual: 404 significa que a tua rota não estava acessível nesse URL, uma discrepância de assinatura significa que assinaste os bytes errados.
#Passo 1: a Didit tentou enviá-lo?
Abre o destino em API & Webhooks e olha para o separador Deliveries. Cada tentativa é registada individualmente, com a resposta.

- Last sent diz-te se a Didit sequer tentou.
- View stats mostra as tentativas e falhas desse destino.
- Uma entrega de teste separa o teu endpoint do próprio evento.
- Um destino que continua a falhar pode ser desativado enquanto o corriges.
Essa única verificação divide o problema ao meio:
- Nenhuma tentativa registada → o evento nunca foi gerado para esse destino. Passa ao passo 2.
- Tentativa registada, falhou → a Didit enviou-o e o teu lado rejeitou-o ou não o recebeu. Passa ao passo 3.
- Tentativa registada, 2xx → foi entregue com sucesso. O problema está dentro do teu handler, não na entrega.
#Passo 2: nenhuma tentativa foi registada
Por ordem de probabilidade:
- O evento não está subscrito. Não existe wildcard - cada família de eventos tem de ser listada explicitamente. E um nome que não existe (
session.status.updated,kyc.completed) não recebe nada, silenciosamente. Verifica na lista de eventos. - Aplicação errada. Os destinos pertencem a uma aplicação. Se as tuas sessões correrem numa aplicação diferente da do destino, nenhum evento chegará alguma vez até ele. Esta é a causa mais comum quando tudo parece corretamente configurado.
- Nada mudou de facto. Os webhooks disparam por alteração. Uma sessão que não avançou, ou uma re-triagem de monitorização AML que não encontrou nada acima do limiar, produz corretamente nenhum evento.
- O estado que estás à espera ainda não aconteceu. Uma sessão em In Progress não está terminada. Consulta quando uma sessão nunca termina.
#Passo 3: a entrega foi tentada e falhou
Um 404 significa que o pedido chegou a algo que não tinha a tua rota. Verifica:
- O caminho exato, incluindo uma barra final. Uma framework que redireciona
/hookpara/hook/pode transformar um endpoint que funciona num 404 ou num corpo perdido. - Se o URL é público. Um anfitrião local ou de staging que não é acessível a partir da internet falha desta forma.
- Se um proxy, balanceador de carga, ou router baseado em caminho à frente da tua aplicação está a enviar esse caminho para outro lado.
Um 5xx significa que o teu handler rebentou. Regista o corpo em bruto antes de o analisares, para veres o que ele realmente recebeu.
Um timeout significa que não respondeste suficientemente depressa. Devolve 2xx primeiro, processa depois.
Nada de todo / ligação recusada significa que o teu edge o bloqueou. A Didit entrega a partir do IP estático 18.203.201.92 com um user agent DiditWebhook/2.0. Se estiveres atrás do Cloudflare ou de uma WAF com uma postura de negação por defeito, permite esse IP para o nome do anfitrião recetor.
#O clássico: a entrega automática dá 404 mas o Resend funciona
Este surge com frequência suficiente para merecer nome próprio. A entrega automatizada falha com um 404, e depois clicar em Resend no mesmo evento tem sucesso.
Essa combinação significa que o payload e o teu endpoint estão ambos bem - por isso a diferença é de tempo ou de caminho, não de conteúdo. Verifica:
- Um deploy ou reinício no momento da entrega original. O Resend tem sucesso mais tarde porque a aplicação já está de novo em pé.
- Um cold start que excedeu o timeout da tua plataforma - comum em serverless com uma primeira invocação lenta.
- Um encaminhamento baseado em caminho que mudou entre as duas tentativas, ou uma regra que só corresponde a alguns pedidos.
- Limitação de taxa ou proteção contra bots no teu edge que deixou passar o reenvio manual porque chegou sozinho em vez de numa rajada.
O separador Deliveries tem ambas as tentativas com os respetivos carimbos de hora - compara-os com os teus próprios registos de deploy e de erro desse minuto.
#A verificação de assinatura a falhar
Quase sempre uma destas três coisas:
- Assinaste JSON re-serializado. Faz o HMAC dos bytes em bruto do pedido, exatamente como recebidos. Analisar e voltar a converter em string muda os espaços e a ordem das chaves, e a assinatura não vai corresponder. A maioria das frameworks precisa de configuração explícita para te dar o corpo em bruto.
- Segredo errado. O segredo de assinatura é por destino, e não é a tua chave de API. Dois destinos têm dois segredos diferentes.
- Suposição de codificação errada. Se não tiveres a certeza se o segredo é usado como string literal ou descodificado primeiro, não adivinhes - segue exatamente a referência de verificação de assinatura, e regista o corpo em bruto enquanto depuras, para poderes comparar.
Nunca "corrijas" uma discrepância de assinatura saltando a verificação. Um endpoint de webhook não verificado vai aceitar uma aprovação forjada de qualquer pessoa que encontre o URL, o que transforma um atalho de depuração num caminho para a apropriação da conta.
#Duas repetições não são uma fila
Num 5xx, 404, timeout, ou falha de ligação, a Didit repete duas vezes - cerca de 1 minuto depois e depois mais 4 minutos - e depois abandona a entrega. Se o teu endpoint esteve em baixo mais tempo do que isso, esses eventos perderam-se para sempre.
Constrói um caminho de reconciliação: no arranque, faz polling ao endpoint de decisão para qualquer sessão para a qual não tenhas um estado terminal. Trata os webhooks como o caminho rápido e o polling como a rede de segurança.
#Testar sem correr verificações
Try Webhook na página do destino envia um evento totalmente formado do tipo que escolheres - aprovado, recusado, em revisão, KYB, entidade, transação. Usa-o para comprovar que o teu endpoint, a verificação de assinatura e o handler funcionam antes de uma sessão real depender deles.
O sandbox é a outra metade disto: uma sessão em sandbox emite webhooks reais com "environment": "sandbox", por isso consegues exercitar todo o caminho, de ponta a ponta, sem custos. Consulta testar em sandbox.
