Como fazer troubleshooting e debug de webhooks: um guia completo

Quando um webhook não funciona, o problema costuma ser uma de cinco coisas: o evento nunca chegou (eventos faltando), chegou várias vezes (entregas duplicadas), o seu handler demorou demais (timeouts), a verificação de assinatura falhou (erros de verificação) ou a lógica de processamento tem um bug. Este guia traz uma abordagem sistemática para diagnosticar e corrigir cada um desses modos de falha, seguida de um tutorial prático usando webhooks da Stripe e a CLI do Hookdeck.

Para o embasamento teórico sobre depuração de webhooks, veja o nosso guia de troubleshooting de webhooks.

Fluxograma de depuração sistemática

Quando um webhook não se comporta como esperado, siga estes passos em ordem:

  1. Verifique o status de entrega no provedor. A maioria dos provedores (Stripe, Shopify, GitHub) mostra as tentativas de entrega de webhook no dashboard. Confirme se o webhook foi realmente enviado e veja qual resposta eles receberam.
  2. Confira a configuração da URL. Confirme que a URL do webhook no dashboard do provedor corresponde exatamente ao seu endpoint — incluindo protocolo (HTTPS), path e porta. A diferença de um único caractere manda os webhooks para o lugar errado.
  3. Inspecione a requisição. Use o dashboard do Hookdeck, a CLI ou os logs do seu servidor para confirmar que a requisição foi recebida. Confira todos os headers, o body e os metadados.
  4. Verifique a assinatura. Se a requisição chega mas o seu handler a rejeita, a causa mais comum é uma falha na verificação de assinatura. Veja Corrigindo falhas de verificação de assinatura abaixo.
  5. Verifique a sua lógica de processamento. Se a requisição é aceita mas o processamento falha, procure erros nos logs da aplicação. Problemas comuns: violação de constraints no banco, null pointer exceptions, falhas em APIs externas.
  6. Verifique o comportamento de retry. Se o evento foi entregue mas falhou, veja se os retries estão configurados e se as tentativas seguintes tiveram sucesso. Revise todas as tentativas de entrega, não só a primeira.
  7. Confirme a idempotência. Se você está vendo processamento duplicado, confirme que os seus handlers são idempotentes. Procure condições de corrida no processamento concorrente de webhooks.

Modos de falha comuns em webhooks

Eventos faltando

Sintomas: o seu provedor mostra que os webhooks foram enviados, mas eles nunca chegam ao seu endpoint.

Causas comuns e correções:

  • URL mal configurada: confira duas vezes a URL nas configurações de webhook do provedor. Copie e cole em vez de digitar.
  • Falha de resolução DNS: o seu domínio pode não estar resolvendo a partir da infraestrutura do provedor. Teste com dig ou nslookup de uma máquina externa.
  • Bloqueio por firewall ou CDN: alguns firewalls ou CDNs (Cloudflare, AWS WAF) bloqueiam requisições que não parecem tráfego de navegador. Libere as faixas de IP do provedor, se disponíveis.
  • Servidor fora do ar: a sua aplicação caiu ou não foi deployada. Confira os logs da sua plataforma de hospedagem.
  • Challenge/handshake não concluído: alguns provedores (Facebook, Zoom) exigem um handshake inicial de verificação antes de enviar webhooks. O Hookdeck trata isso automaticamente.

Entregas duplicadas

Sintomas: o mesmo evento é processado várias vezes, gerando registros ou efeitos colaterais duplicados.

Causa raiz: a entrega at-least-once significa que duplicatas são esperadas — por retries do provedor, problemas de rede ou comportamento da infraestrutura.

Correção: implemente processamento idempotente usando um identificador único do evento:

async function handleWebhook(req, res) {
  const eventId = req.headers['x-hookdeck-eventid'] || req.body.id;

  // Check if already processed
  const existing = await db.processedEvents.findOne({ eventId });
  if (existing) {
    return res.status(200).send('Already processed');
  }

  // Mark as processing (with unique constraint)
  await db.processedEvents.insert({ eventId, status: 'processing' });

  // Process the event
  await processEvent(req.body);

  // Mark as complete
  await db.processedEvents.update({ eventId }, { status: 'completed' });
  res.status(200).send('OK');
}

Timeouts

Sintomas: o seu handler começa a processar, mas o provedor (ou o Hookdeck) reporta um timeout. O evento então sofre retry, potencialmente causando processamento duplicado.

Causa raiz: o seu handler demora mais para responder do que a janela de timeout (normalmente de 5 a 30 segundos para a maioria dos provedores, 60 segundos para o Hookdeck).

Correção: confirme o recebimento imediatamente e processe de forma assíncrona:

app.post('/webhook', async (req, res) => {
  // Acknowledge immediately
  res.status(200).send('OK');

  // Process asynchronously (queue, background job, etc.)
  await queue.add('process-webhook', { payload: req.body });
});

Com o Hookdeck, a sua aplicação já recebe webhooks a partir de uma fila durável — você não precisa acrescentar outra fila. Basta processar de forma síncrona dentro da janela de timeout, ou usar rate limiting para controlar o throughput.

Corrigindo falhas de verificação de assinatura

Sintomas: os webhooks chegam, mas o seu handler retorna 401/403 porque a verificação de assinatura falha.

Passos de depuração:

  1. Confirme que você está usando o segredo correto. Verifique no dashboard do provedor qual é o segredo de assinatura atual. Segredos mudam quando você rotaciona credenciais.
  2. Confirme que você está lendo o body bruto. Se você faz o parsing do body (por exemplo, com o middleware json() do Express) antes da verificação, o JSON re-serializado pode diferir do original. Sempre verifique contra o body bruto da requisição.
  3. Verifique a codificação. Compare se o seu provedor envia assinaturas em Base64 ou em hex e garanta que a saída do seu hash corresponde.
  4. Verifique a expiração do timestamp. Para provedores com assinaturas com timestamp (Stripe, Svix), webhooks reenviados podem cair fora da janela de validação. Considere desativar a checagem de timestamp ou aumentar a tolerância.
  5. Use o SDK do provedor. Quando disponível, o SDK oficial do provedor trata corretamente os detalhes de codificação e comparação.

Para mais sobre segurança de webhooks, veja o nosso Guia de vulnerabilidades de segurança em webhooks.

Depuração com replay

O replay de eventos — reentregar eventos para depuração ou recuperação — é uma das ferramentas de troubleshooting mais poderosas disponíveis:

  • Reproduzir problemas: reenvie um evento específico para reproduzir um bug no seu handler sem precisar disparar um novo evento no provedor.
  • Testar correções: depois de corrigir um bug, reenvie o evento que o disparou para verificar se a correção funciona.
  • Recuperar de incidentes: depois de resolver um incidente, faça replay em massa de todos os eventos que falharam durante a queda.

Com a CLI do Hookdeck, pressione r para reenviar qualquer evento ao seu servidor local. No dashboard, reenvie eventos individualmente ou use o retry em massa para recuperação em lote. O replay é seguro quando os seus handlers são idempotentes.

Tutorial prático: depurando webhooks da Stripe localmente

Configurando webhooks da Stripe localmente

Neste tutorial, vamos ver como receber e depurar webhooks da Stripe localmente. Ao final deste guia, teremos uma configuração que recebe webhooks da Stripe localmente e nos dá visibilidade sobre os headers e o payload de cada requisição.

Configurando os webhooks na Stripe

O primeiro passo deste exercício é criar uma conta na Stripe. A Stripe é o provedor de webhooks, então vamos assinar eventos da Stripe e receber webhooks em um servidor local.

No momento em que escrevo isto, tudo o que você precisa para criar uma conta na Stripe é um endereço de e-mail. Se você já tem uma conta na Stripe, pode seguir para a próxima seção; se não, acesse a página de registro da Stripe para criar uma nova conta. Você precisará verificar o seu e-mail após o registro.

Clonando um projeto de API em Node.js

Em seguida, precisamos de um servidor local para receber os webhooks da Stripe. Você pode usar qualquer servidor local que preferir, escrito na linguagem da sua escolha, desde que garanta que ele esteja rodando em uma porta específica. Para este exercício, vamos usar uma API de exemplo em Node.js disponível no repositório do Hookdeck no GitHub.

Você pode clonar esse repositório rodando o seguinte comando:

git clone <https://github.com/hookdeck/nodejs-webhook-server-example.git>

Isso vai deixar o projeto disponível no local onde você rodou o comando no seu sistema de arquivos.

Navegue até a raiz do projeto e instale as dependências necessárias rodando os comandos abaixo:

cd nodejs-webhook-server-example
npm install

Quando a instalação terminar, você pode rodar o servidor Node.js com o seguinte comando:

npm start

Isso vai subir a aplicação da API e imprimir na tela uma mensagem indicando que ela está rodando e escutando conexões na port 1337.

O endpoint que será usado para as requisições de webhook é /stripe-webhooks-endpoint e pode ser encontrado no arquivo src/routes.ts, como mostrado abaixo:

router.post(
  "/stripe-webhooks-endpoint",
  bodyParser.raw({ type: "application/json" }),
  function (req, res) {
    console.log(req.body);
    res.send("Stripe Successfully received Webhook request");
  },
);

Esse endpoint recebe as requisições de webhook, imprime o body da requisição no console e retorna uma mensagem.

Recebendo webhooks no localhost

Para depurar webhooks localmente, precisamos conseguir recebê-los no nosso ambiente local. Isso não é possível de imediato, já que servidores rodando localmente não estão publicamente disponíveis na internet. Por isso, vamos usar a CLI do Hookdeck, porque ela foi construída especificamente para depurar webhooks, ao contrário das outras opções, que precisam ser configuradas e às vezes combinadas com outras ferramentas para funcionar com webhooks.

Você também pode usar a nossa ferramenta online de teste de webhooks se preferir não instalar nada ou não tiver permissão para instalar no sistema que está usando para depurar.

Configure a CLI do Hookdeck

Acesse a documentação da CLI do Hookdeck para instalar e configurar a ferramenta no seu sistema operacional.

Concluída a configuração, o próximo passo é usar a CLI para gerar uma URL de webhook que aponte para a aplicação de API em execução. Para isso, rode o seguinte comando:

hookdeck listen 1337

Esse comando inicia uma sessão interativa em que a CLI coleta informações sobre o endpoint que você está prestes a criar. Abaixo estão as perguntas e as respostas que você deve fornecer. Lembre-se de pressionar Enter após cada resposta.

PerguntaResposta
What source should you select?Create new source
What should your new source label be?stripe
What path should the webhooks be forwarded to (i.e.: /webhooks)?/stripe-webhooks-endpoint
What's the connection label (i.e.: My API)?My Stripe API

Com essas informações, a CLI começa a gerar a URL e, quando terminar, você verá a URL impressa na tela e a CLI indicando que está pronta para receber requisições.

stripe-cli-ready

Copie a webhook URL, porque ela será necessária para configurar os webhooks na Stripe.

Registre o webhook na Stripe

Agora que concluímos a configuração na aplicação de destino, é hora de assinar um webhook na Stripe.

No seu dashboard da Stripe, vá em Developers → Webhooks. Na página "Webhooks", clique no botão + Add endpoint no canto superior direito da tela. Essa ação abre um diálogo parecido com o abaixo:

stripe-add-webhook

No diálogo, adicione no campo Endpoint URL a URL de webhook copiada da CLI. Em seguida, clique no dropdown Events to send e selecione o evento account.updated, que será disparado toda vez que a sua conta Stripe for atualizada. Clique no botão Add endpoint para concluir o processo.

Isso cria a conexão entre a sua conta Stripe e a aplicação de API rodando na sua máquina local para o evento account.updated. Depois que o webhook for adicionado com sucesso, você verá uma tela como esta:

stripe-webhook-created

Teste o webhook da Stripe

Com a nossa conexão de webhook configurada, chegou a hora de testar. A Stripe oferece uma forma de enviar um webhook de teste que simula o evento que você registrou. Isso é bastante útil para testes e depuração.

No canto superior direito da tela do seu webhook (mostrada acima), clique no botão Send test webhook. Isso abre um diálogo para você selecionar o evento do qual quer enviar o teste. Veja o diálogo abaixo:

stripe-send-test-webhook

Certifique-se de selecionar o evento account.updated e clique no botão Send test webhook. Isso dispara uma requisição de webhook para a sua URL, que será recebida no endpoint que você especificou ao criar a URL (ou seja, /stripe-webhooks-endpoint).

Observe a janela de terminal onde você rodou o comando hookdeck listen 1337. Você verá a requisição de webhook impressa no terminal, como mostrado abaixo:

cli-event-entry-stripe

Agora estamos recebendo os nossos webhooks da Stripe localmente com sucesso.

Depurando webhooks da Stripe

Inspecionando os headers do webhook

O último item da informação impressa pela CLI para o webhook recebido é um endereço para você ver detalhes da requisição que acabou de chegar. Copie essa URL e abra no seu navegador, e você verá uma tela de detalhes do evento como a de baixo.

event-inspection-stripe-hookdeck

Essa tela contém uma quantidade rica de detalhes sobre o webhook que você acabou de receber.

Ao trabalhar com webhooks, parte das informações importantes enviadas na requisição está nos headers. Podem ser informações de autenticação como tokens de API, informações de cache ou headers customizados que carregam assinaturas para verificar a origem do webhook.

Se por algum motivo os seus webhooks aparecem no terminal mas o seu endpoint de API não os recebe, vale conferir os headers para garantir que o seu endpoint está sendo autenticado.

Os headers da requisição do webhook recebido aparecem na seção Headers da tela do evento, como mostrado abaixo:

webhook-headers-stripe-hookdeck

Como se vê na requisição acima, a assinatura da Stripe é enviada no header stripe-signature. Essa assinatura permite verificar que os webhooks estão sendo enviados pela Stripe. Você pode verificar assinaturas da Stripe usando as bibliotecas oficiais da Stripe ou desenvolvendo a sua própria solução. Os detalhes de como criar o seu próprio sistema de verificação estão aqui.

Inspecionando o payload do webhook

Além de notificar sobre um evento que aconteceu em uma aplicação de origem, outra responsabilidade dos webhooks é transferir dados da aplicação de origem para a aplicação de destino.

Esses são dados sobre os quais você frequentemente vai precisar fazer algum processamento no seu endpoint de API, de acordo com o evento que ocorreu. Ao depurar, é importante garantir que você está recebendo todos os dados necessários e nos formatos certos. Às vezes você vai precisar converter para tipos de dados diferentes para conseguir fazer o processamento do seu lado.

Por exemplo, quando um usuário paga pelo seu gateway da Stripe, você espera receber o valor pago em numeric format. A Stripe pode, por algum motivo, decidir enviar esse valor em string format. Isso pode bagunçar os cálculos ou o processamento do seu lado, mas se você inspecionar o valor e descobrir que ele veio como string, consegue incluir uma lógica para converter o valor em formato numérico.

A tela do evento tem uma seção Body onde você pode inspecionar todos os parâmetros enviados no corpo da requisição, como mostrado abaixo:

body-payload-stripe-hookdeck

Fazendo retry de webhooks

Depurar é um ciclo contínuo de test→ inspect → fix → test. Quando você dispara um webhook de teste da Stripe e descobre um problema ou uma anomalia no seu sistema, você inspeciona a requisição e o seu código para rastrear o bug, corrige e testa de novo.

Muitas vezes, ao lidar com um bug, você precisa rodar testes várias vezes. E não quer ficar voltando à sua conta Stripe para simular um teste repetidas vezes, porque isso rapidamente se torna frustrante.

Não se preocupe, a CLI do Hookdeck resolve isso. Existem duas formas de fazer retry de um evento.

  1. Página do evento: no canto superior direito existe um botão de retry, como mostrado abaixo.

retry-event-page

  1. Visão da CLI no dashboard: o botão de retry fica na borda do evento.

dashboard-cli-retry

Clique nesse botão para reenviar a requisição de webhook depois de fazer uma correção e inspecione novamente para ver se o bug sumiu. Essa ferramenta prática elimina o estresse de reenviar manualmente a requisição várias vezes.

Resposta da tentativa

Quando um evento sofre retry, o Hookdeck gera uma nova attempt. É útil olhar a resposta da requisição e o status do servidor.

tentativas da requisição

Salve um webhook como bookmark

Ter que disparar o evento manualmente na Stripe ou enviar uma notificação de teste pode ficar cansativo. Você pode __marcar (salvar)__ uma requisição para reenviá-la direto do dashboard, sem precisar passar pela Stripe.

Crie um bookmark.

create-bookmark

Reenvie o evento a partir do bookmark.

Reenviar evento a partir do bookmark

Conclusão

A depuração de webhooks segue um padrão consistente independentemente do provedor: verificar se o evento foi enviado, confirmar se chegou, checar a autenticação, inspecionar a lógica de processamento e revisar o comportamento de retry. O fluxograma de depuração sistemática acima dá a você um processo repetível para diagnosticar qualquer problema de webhook.

Para construir handlers de webhook resilientes que falham de forma controlada, veja Assumindo o controle da confiabilidade dos seus webhooks. Para entender como as garantias de entrega afetam a sua abordagem de depuração, veja Garantias de entrega de webhooks. E para monitorar a saúde dos webhooks de forma proativa (para pegar problemas antes dos seus usuários), veja Metrics.

A CLI do Hookdeck e o Hookdeck Console são ferramentas gratuitas que tornam a depuração de webhooks bem mais fácil — experimente para ver como inspeção, replay e filtragem se combinam para acelerar o seu fluxo de depuração.

FAQs

Por que não estou recebendo webhooks?

As causas mais comuns são: a URL configurada no provedor está errada (confira a URL do webhook no dashboard do provedor), problemas de DNS impedindo a resolução do seu endpoint, um firewall ou CDN bloqueando as requisições do provedor, o seu servidor está fora do ar ou não está escutando na porta correta, ou o provedor exige um challenge/handshake que não foi concluído.

Como faço debug de entregas de webhook que falharam?

Comece verificando os logs da sua infraestrutura de webhooks para a tentativa de entrega — olhe o status code HTTP, o corpo da resposta e o tempo. Com o Hookdeck, inspecione o evento no dashboard para ver a requisição/resposta completa de cada tentativa de entrega. Verifique se a falha é um timeout, um erro de autenticação ou um erro da aplicação, e então trate a causa raiz.

Por que os meus webhooks estão dando timeout?

Timeouts de webhook acontecem quando o seu handler demora demais para responder. A maioria dos provedores dá timeout entre 5 e 30 segundos. A solução é confirmar o recebimento do webhook imediatamente (retornando 200) e depois processar o payload de forma assíncrona, via fila ou job em background. Nunca faça processamento pesado (escritas no banco, chamadas de API, operações de arquivo) antes de responder.

Como corrijo erros de verificação de assinatura de webhook?

Causas comuns: usar o segredo de assinatura errado (confira no dashboard do provedor), fazer o parsing do body antes da verificação (verifique contra o body bruto, não o JSON já parseado), usar a codificação errada (Base64 em vez de hex) ou um problema de tempo com assinaturas com timestamp. Use o SDK do provedor quando disponível, porque ele trata os detalhes de codificação corretamente.

Como lido com eventos de webhook duplicados?

Implemente processamento idempotente usando um identificador único do evento (como o ID de evento do provedor ou o header x-hookdeck-eventid). Antes de processar, verifique se o evento já foi tratado. Use constraints de unicidade no banco ou um cache de deduplicação em Redis. Veja o nosso guia sobre como implementar idempotência em webhooks para padrões detalhados.

Que ferramentas posso usar para testar e depurar webhooks?

A CLI do Hookdeck permite receber webhooks no localhost com inspeção completa da requisição, retry e replay. O Hookdeck Console (console.hookdeck.com) é uma ferramenta web gratuita para inspecionar requisições de webhook. Para testes específicos de cada provedor, a maioria oferece funcionalidade de webhook de teste no dashboard. Para uma comparação de ferramentas, veja o nosso guia das melhores ferramentas de teste de webhooks.