Seu banco de dados caiu às 2h da manhã. Quando você acordou e consertou, três horas de webhooks já tinham sido enviadas e rejeitadas. Agora você está olhando para o Slack, tentando adivinhar quantos pagamentos da Stripe ficaram sem o pedido liberado e quantos pushes no GitHub não dispararam o job de CI certo.
Este post é o roteiro de verdade para recuperar webhooks perdidos, provedor por provedor, e depois o padrão que transforma isso num problema de um clique em vez de uma tarde de domingo.
TL;DR
- Stripe: reenvio manual, um evento por vez, pelo Dashboard, ou um script com a Events API. Não existe interface para reenvio em massa.
- GitHub: um botão de reenvio por entrega. Também um por vez, a não ser que você escreva um script com a Redelivery API.
- Shopify: tenta de novo 8 vezes ao longo de 4 h; depois, os eventos somem e você consulta de novo a Orders API para conciliar.
- O replay (um novo envio de um evento armazenado, feito por você) com um clique exige registrar os webhooks antes que cheguem ao seu servidor, e é para isso que um relay de webhooks (um serviço que recebe, guarda e encaminha seus webhooks) é projetado.
Stripe
A Stripe permite reenviar eventos de webhook manualmente pelo Dashboard:
- Vá em Developers → Events no Dashboard da Stripe
- Clique no evento que você quer reenviar
- Role até Webhook attempts (tentativas de webhook) e clique em Reenviar
Isso funciona um evento por vez, e só por 15 dias depois da criação do evento. Se você perdeu 300 eventos, vai clicar em 300 botões. Existe um comando na Stripe CLI (stripe events resend <event_id>), mas ele ainda exige que você saiba o ID de cada evento.
Replay em lote de eventos da Stripe
Não existe uma interface oficial de replay em massa. As alternativas:
- Escreva um script que use a API da Stripe para listar os eventos da janela da queda, filtrar por status e fazer você mesmo o POST de cada um de volta para seu endpoint. Você está reconstruindo o webhook a partir do objeto do evento, e o formato não é exatamente o mesmo.
- Ou, se você registrou seus webhooks antes que chegassem ao seu servidor, faça o replay a partir do seu próprio log
A abordagem de registrar antes do servidor é a que as equipes de produção acabam construindo. É também exatamente o que um relay de webhooks faz por você.
GitHub
O GitHub mostra um botão de reenvio por entrega em Settings → Webhooks → (escolha o webhook) → Recent Deliveries (entregas recentes) do repositório. Clique em Redeliver (entregar novamente) ao lado de cada uma.
Mesmo problema: uma por vez. O GitHub só permite reenviar entregas por 3 dias, e um replay em massa continua significando um script chamando a Redelivery API. E esse log é tudo o que você tem, porque o GitHub nunca tenta de novo uma entrega com falha por conta própria.
Shopify
A Shopify tenta de novo 8 vezes numa janela de quatro horas antes de desistir. Depois disso, o único jeito de recuperar é consultar de novo a API da Shopify para buscar o que você perdeu. Os webhooks em si sumiram.
Esse caso é especialmente doloroso porque a janela de recuperação da Shopify é, de longe, a mais curta das três grandes. Se seu servidor cai na sexta à noite e você só percebe na segunda, vai fazer uma conciliação completa pela Orders API.
O padrão geral
Seja qual for o provedor, o procedimento de recuperação sem um relay é mais ou menos este:
- Identifique a janela da queda. Quando seu servidor parou de responder 2xx?
- Puxe os eventos afetados, normalmente com uma chamada de API paginada por provedor
- Dispare de novo cada evento fazendo POST no seu próprio endpoint, ou consulte de novo a fonte da verdade e sincronize o estado à mão
- Deduplique, porque seu handler precisa ser idempotente e alguns eventos podem ter sido entregues parcialmente
Isso leva horas. E você só tem uma chance: se perder eventos além da janela de novas tentativas (retries), eles somem.
A versão com um clique
O AnyHook existe para transformar isso num clique. Quando você aponta seus webhooks para in.anyhook.net/you/app:
- O AnyHook armazena cada evento antes da entrega, com criptografia em repouso
- Se seu servidor responde 5xx, o AnyHook tenta de novo com backoff exponencial (Free=3, Pro=5, Scale=10 tentativas)
- Se seu servidor fica fora do ar tempo suficiente para esgotar as novas tentativas, o evento é marcado como falha, mas o payload continua no seu log
- Abra a página do app, escolha a janela no banner de eventos com falha (última hora, últimas 24 horas ou a janela de replay inteira) e clique em Replay. Ele envia 100 por vez, dos mais antigos para os mais novos. É só isso.
Replays de eventos com falha não consomem sua cota mensal, mas usam a franquia de computação do seu plano. Cada plano tem um limite diário de replays (100 no Free, 500 no Pro, 1.000 no Scale), e um evento retido por ter passado da cota conta como novo quando você faz o replay dele. Os replays saem de novo para seu endpoint com uma assinatura nova, enquanto o corpo e os cabeçalhos originais de entrada são preservados, então seu handler vê o evento exatamente como o provedor o enviou.
O equivalente na API é um único POST:
curl -X POST https://anyhook.net/api/v1/apps/stripe-prod/replay-failed \
-H "Authorization: Bearer $ANYHOOK_KEY" \
-H "Content-Type: application/json" \
-d '{"since": "2026-04-18T02:00:00Z", "limit": 100}'
Uma chamada, replay de até 100 eventos, nenhum clique no painel.
A implicação de design
O que torna o replay barato é a persistência na edge, antes da entrega. Se seu log de webhooks começa no seu servidor, você só consegue fazer o replay do que seu servidor recebeu. Se seu log começa na edge da rede, antes que seu servidor tenha chance de falhar, você consegue fazer o replay de qualquer coisa que já tenha chegado.
O cronograma que roda entre essas tentativas é um problema de design à parte. O do AnyHook é uma escada fixa, sem jitter, e Retry de webhooks: backoff exponencial e jitter explica por que uma escada assim faz todos os clientes marcharem para o mesmo segundo depois de uma queda e por que, de todo modo, um replay barato é melhor do que novas tentativas agressivas. E, se você se pega recorrendo ao replay com frequência, a pergunta anterior é se essa fronteira deveria mesmo usar um webhook, que é o tema de Webhooks vs. polling.
Registre os webhooks antes que cheguem ao seu servidor, torne o replay idempotente, e sua pior queda de webhooks vira uma recuperação de um minuto em vez de um fim de semana.
Duas leituras complementares que valem antes de você precisar delas. "Torne o replay idempotente" é a metade que sustenta tudo, e é mais difícil do que uma tabela de deduplicação quando as novas tentativas chegam em paralelo: Você recebeu o mesmo webhook duas vezes. E, se a Stripe já desistiu e desativou seu endpoint, ela parou de tentar de novo, e você vai preencher a lacuna (backfill) pela Events API dentro de uma janela de 30 dias: A Stripe desativou seu endpoint de webhook.
Experimente: anyhook.net.