Entregas e retry
Nenhuma entrega é "dispara e esquece". Cada evento × endpoint vira um registro de entrega com status, tentativas e a captura completa de request e response — o que transforma "o webhook não chegou" de mistério em consulta.

O ciclo de vida de uma entrega
| Status | Significado |
|---|---|
pending | Agendada, aguardando processamento |
success | Seu endpoint respondeu 2xx |
failed | Falhou; retry agendado |
exhausted | Esgotou as tentativas (ou falha permanente); foi para a DLQ |
Conta como falha: resposta fora de 2xx (redirects não são seguidos, logo 3xx também falha), erro de rede e timeout (10 segundos por tentativa).
O contrato do seu endpoint
Três regras para um consumidor saudável:
- Responda
2xximediatamente, sem processar sincronamente. Grave o payload (fila, tabela, log) e devolva200na hora; processe depois. O timeout é de 10 segundos — um handler que consulta banco, chama terceiros e só então responde vai estourar o limite em dia de carga e disparar retries desnecessários. - Evento desconhecido? Responda
200e ignore. Novos eventos podem passar a ser emitidos sem aviso (endpoint com lista de eventos vazia recebe todos). Responder erro a um evento que você não trata só gera retry e ruído na sua fila. - Deduplique antes de processar — veja "pelo menos uma vez" abaixo.
Retry: 8 tentativas em ~8h30 (backoff exponencial)
Cada entrega tem 8 tentativas com backoff exponencial de base 4 minutos — a espera dobra a cada falha:
| Tentativa | Quando (aprox.) | Espera após a falha anterior |
|---|---|---|
| 1ª | imediata | — |
| 2ª | +4min | 4min |
| 3ª | +12min | 8min |
| 4ª | +28min | 16min |
| 5ª | +1h | 32min |
| 6ª | +2h04 | 1h04 |
| 7ª | +4h12 | 2h08 |
| 8ª | +8h28 | 4h16 |
A janela total é de ~8h30 entre o evento e a última tentativa (os horários são aproximados: dependem da fila no momento) — um consumidor fora do ar por minutos ou horas ainda recebe o evento sem intervenção manual. A tela mostra a próxima tentativa estimada (nextRetryAt). Cada tentativa é re-assinada com um t novo na assinatura.
Duas situações pulam o retry e vão direto para exhausted:
- Bloqueio SSRF: a URL passou a resolver para rede interna — falha permanente, reagendar não ajudaria.
- Endpoint inativo ou removido no momento da entrega.
DLQ: nada some em silêncio
Quando a 8ª tentativa falha, a entrega vira exhausted e o job vai para a dead-letter queue com o erro registrado. O evento em si permanece persistido e imutável; a entrega esgotada continua listada na tela, pronta para re-envio manual quando você corrigir o endpoint.
A tela de entregas
Na linha do endpoint, abra o histórico (10 por página). Cada entrega mostra evento, status, código HTTP, número de tentativas e data; expandindo a linha:
- o erro da última tentativa,
- o request body enviado,
- o response body devolvido pelo seu servidor,
- e o momento da entrega bem-sucedida (
deliveredAt).
Headers sensíveis (assinatura, credenciais de autenticação, Set-Cookie da resposta) aparecem como [REDACTED]. A listagem de endpoints agrega o total de entregas e destaca em vermelho a soma de falhas + esgotadas.
Re-envio manual
Entregas failed ou exhausted têm o botão de reprocessar (também via POST /api/v1/webhook-endpoints/{id}/deliveries/{deliveryId}/retry). O re-envio reseta a entrega e recomeça o ciclo de tentativas; se o endpoint estiver inativo, o pedido é recusado (409 ENDPOINT_INACTIVE). Cada re-envio fica na auditoria.
Entrega "pelo menos uma vez"
O sistema garante que o evento não se perde, não que chega exatamente uma vez: um 200 que se perdeu na rede gera nova tentativa e, portanto, entrega duplicada no seu lado. Projete o consumidor idempotente: deduplique pelo header X-Webhook-Event-Id (o UUID do evento, estável entre tentativas e re-envios) antes de processar. O header X-Webhook-Attempt traz o número da tentativa, útil para telemetria do seu lado.
Testando sem evento de negócio
POST /api/v1/webhook-endpoints/{id}/test dispara um evento webhook.test pelo pipeline real — a entrega aparece na tela como qualquer outra, com captura e retry. Use para validar assinatura, auth e o contrato do consumidor antes de entrar em produção.