Quando um webhook nunca chega
Resolva na ordem - o log de entregas, o nome do evento, o firewall, a assinatura. A aba Deliveries diz se a Didit enviou, o que já divide o problema pela metade.
Comece pela aba Deliveries do destino. Se a Didit nunca tentou a entrega, é um problema de inscrição ou de destino. Se ela tentou e falhou, o código de resposta diz por quê: 404 significa que sua rota não estava acessível naquela URL, uma assinatura incompatível significa que você calculou o hash sobre os bytes errados.
#Etapa 1: a Didit tentou enviar?
Abra o destino em API & Webhooks e olhe a aba Deliveries. Toda tentativa é registrada individualmente, com a resposta.

- Last sent indica se a Didit tentou enviar.
- View stats mostra as tentativas e falhas daquele destino.
- Uma entrega de teste separa o seu endpoint do próprio evento.
- Um destino que continua falhando pode ser desativado enquanto você resolve o problema.
Essa única verificação divide o problema pela metade:
- Nenhuma tentativa registrada → o evento nunca foi gerado para aquele destino. Vá para a etapa 2.
- Tentativa registrada, com falha → a Didit enviou e o seu lado rejeitou ou não recebeu. Vá para a etapa 3.
- Tentativa registrada, 2xx → foi entregue com sucesso. O problema está dentro do seu handler, não na entrega.
#Etapa 2: nenhuma tentativa foi registrada
Em ordem de probabilidade:
- O evento não está inscrito. Não existe curinga - toda família de eventos precisa ser listada explicitamente. E um nome que não existe (
session.status.updated,kyc.completed) não recebe nada, silenciosamente. Verifique com a lista de eventos. - Aplicação errada. Os destinos pertencem a uma aplicação. Se suas sessões rodam em uma aplicação diferente da do destino, nenhum evento vai chegar até ele. Essa é a causa mais comum quando tudo parece configurado corretamente.
- Nada realmente mudou. Webhooks disparam em mudanças. Uma sessão que não avançou, ou uma nova checagem de monitoramento AML que não encontrou nada acima do limite, corretamente não produz nenhum evento.
- O status que você está esperando ainda não aconteceu. Uma sessão Em andamento (In Progress) ainda não terminou. Veja quando uma sessão nunca termina.
#Etapa 3: a entrega foi tentada e falhou
Um 404 significa que a requisição chegou a algo que não tinha sua rota. Verifique:
- O caminho exato, incluindo uma barra final. Um framework que redireciona
/hookpara/hook/pode transformar um endpoint funcional em um 404 ou em um corpo perdido. - Se a URL é pública. Um host local ou de staging que não é acessível pela internet falha dessa forma.
- Se um proxy, load balancer, ou roteador baseado em caminho na frente do seu app está enviando aquele caminho para outro lugar.
Um 5xx significa que o seu handler lançou uma exceção. Registre o corpo bruto antes de fazer o parse, para que você possa ver o que ele realmente recebeu.
Um timeout significa que você não respondeu rápido o suficiente. Retorne 2xx primeiro, processe depois.
Nada / conexão recusada significa que sua borda bloqueou a chamada. A Didit entrega a partir do IP estático 18.203.201.92 com um user agent DiditWebhook/2.0. Se você estiver atrás do Cloudflare ou de um WAF com postura padrão de negação, libere esse IP para o hostname de recebimento.
#O clássico: a entrega automática dá 404, mas o Resend funciona
Este caso aparece com frequência suficiente para merecer um nome. A entrega automática falha com 404, e então clicar em Resend no mesmo evento tem sucesso.
Essa combinação significa que tanto o payload quanto o seu endpoint estão corretos - então a diferença é de tempo ou de caminho, não de conteúdo. Verifique:
- Um deploy ou reinício no momento da entrega original. O Resend funciona depois porque o app está de volta no ar.
- Um cold start que ultrapassou o timeout da sua plataforma - comum em serverless com uma primeira invocação lenta.
- Roteamento por caminho que mudou entre as duas tentativas, ou uma regra que só corresponde a algumas requisições.
- Limite de taxa ou proteção contra bots na sua borda que deixou passar o reenvio manual porque ele chegou sozinho, em vez de em uma rajada.
A aba Deliveries tem as duas tentativas com seus horários - compare com seus próprios logs de deploy e de erro para aquele minuto.
#A verificação de assinatura está falhando
Quase sempre é uma destas três coisas:
- Você calculou o hash sobre um JSON re-serializado. Faça o HMAC sobre os bytes brutos do corpo da requisição, exatamente como recebidos. Fazer o parse e depois transformar de volta em string muda espaços em branco e a ordem das chaves, e a assinatura não vai corresponder. A maioria dos frameworks precisa de configuração explícita para fornecer o corpo bruto.
- Secret errado. O signing secret é por destino, e não é a sua chave de API. Dois destinos têm dois secrets diferentes.
- Suposição de codificação errada. Se você não tem certeza se o secret é usado como string literal ou é decodificado primeiro, não tente adivinhar - siga a referência de verificação de assinatura exatamente, e registre o corpo bruto enquanto depura, para poder comparar.
Nunca "corrija" uma incompatibilidade de assinatura pulando a verificação. Um endpoint de webhook não verificado vai aceitar uma aprovação forjada de qualquer pessoa que encontrar a URL, o que transforma um atalho de depuração em um caminho de invasão de conta.
#Duas tentativas não são uma fila
Em caso de 5xx, 404, timeout ou falha de conexão, a Didit tenta novamente duas vezes - aproximadamente 1 minuto depois e depois mais 4 minutos - e então descarta a entrega. Se o seu endpoint ficou fora do ar por mais tempo do que isso, esses eventos se perderam definitivamente.
Construa um caminho de reconciliação: na inicialização, faça polling no endpoint de decisão para qualquer sessão para a qual você não tenha um status final. Trate webhooks como o caminho rápido, e o polling como o mecanismo de backup.
#Testando sem executar verificações
Try Webhook na página do destino envia um evento completamente formado do tipo que você escolher - approved, declined, in review, KYB, entity, transaction. Use isso para comprovar que seu endpoint, sua verificação de assinatura e seu handler funcionam antes que uma sessão real dependa deles.
O sandbox é a outra metade disso: uma sessão de sandbox emite webhooks reais com "environment": "sandbox", então você pode exercitar todo o caminho de ponta a ponta gratuitamente. Veja testes no sandbox.
