# Quando um webhook nunca chega

Source: https://help.didit.me/pt-BR/integration/webhook-troubleshooting
Updated: 2026-10-12

Comece pela aba Deliveries: se a Didit nunca tentou, é inscrição ou destino; se tentou e falhou, o código de resposta explica o motivo. 404 é rota inacessível.

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 Desenvolvedores e Webhooks, selecione o endpoint e abra Entregas para ler a solicitação e resposta de cada tentativa. Reenvie após corrigir. Confira aplicação, ambiente, eventos inscritos e se o endpoint está ativo.

![A página de webhooks no console da Didit mostrando o status de entrega por destino](https://help.didit.me/screenshots/webhooks-light.webp)

*Tudo o que é preciso para diferenciar um evento ausente de um endpoint com falha está nesta página.*

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:

1. **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](https://help.didit.me/pt-BR/integration/webhooks-basics).
2. **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.
3. **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.
4. **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](https://help.didit.me/pt-BR/verification-sessions/session-not-finished).

## 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 `/hook` para `/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:

1. **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.
2. **Secret errado.** O signing secret é **por destino**, e não é a sua chave de API. Dois destinos têm dois secrets diferentes.
3. **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](https://docs.didit.me/integration/webhooks#signature-verification) exatamente, e registre o corpo bruto enquanto depura, para poder comparar.

> **Warning:** 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 respostas 5xx ou 404, a Didit tenta novamente duas vezes, após cerca de um minuto e depois quatro. Timeout de 5 segundos ou falha de conexão não tem nova tentativa automática. Use Reenviar em Entregas após corrigir; uma falha definitiva gera um alerta.

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

[Video: Configure chaves de API e teste seus webhooks - Didit Academy](https://www.youtube.com/watch?v=thOMIGbNLP0&t=140)

**Envie um evento de teste** 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](https://help.didit.me/pt-BR/getting-started/sandbox-and-testing).
