Automação3 de agosto de 20268 min de leitura

Webhook do n8n não funciona: sete causas, da mais comum à menos comum

Em nove de cada dez casos, é a URL de teste, que só escuta enquanto você está olhando. O resto: modo de resposta, corpo bruto consumido ou evento perdido.

/webhook-test/… · ESCUTA UM ÚNICO EVENTOvocê clicaListen for test1 execuçãovocê sai da página404para tudopara sempre/webhook/… · SÓ EXISTE ENQUANTO ESTÁ ATIVADOworkflowsalvo, inativo404ativarrota no arsalvo ≠ ativado
Duas URLs quase idênticas na aparência e nada parecidas no comportamento. Na maioria das vezes, a resposta é esta.

Você montou o workflow, ele rodou perfeitamente quando você clicou em "Listen for test event" (escutar evento de teste), você colou a URL na Stripe e agora nada acontece. Nenhuma execução. Nenhum erro. O provedor diz que a entrega falhou ou, pior, diz que deu certo e você continua sem nada.

São poucas causas, mas elas geram muita confusão, principalmente porque as mensagens de falha do n8n são discretas e a causa mais comum é uma URL que parece correta. Aqui estão elas, na ordem de quantas vezes cada uma é de fato a responsável.

TL;DR

  • Na maioria das vezes, a resposta é URL de teste vs. URL de produção. A de teste só escuta enquanto você está olhando para ela
  • A URL de produção só existe depois que o workflow é ativado
  • Por padrão, o modo de resposta é responder imediatamente, o que serve para a maioria dos provedores e é fatal se você precisa devolver um challenge
  • A opção Raw Body (corpo bruto) precisa estar ligada para qualquer verificação de assinatura, senão o HMAC nunca vai bater
  • Uma execução com falha deixa o evento encalhado. O n8n não tenta de novo os webhooks recebidos
  • Em instalações self-hosted atrás de um proxy reverso, entra uma camada de limite de tamanho do corpo e de timeout que muita gente esquece

1. Você está usando a URL de teste (é esta)

O nó Webhook do n8n mostra duas URLs, e elas se comportam de forma completamente diferente:

Test:        https://your-instance/webhook-test/abc-123
Production:  https://your-instance/webhook/abc-123

A URL de teste só fica ativa depois que você clica em "Listen for test event" e enquanto está olhando o canvas. Ela registra uma execução, mostra os dados e para. No momento em que você sai dessa tela, ela passa a responder 404 para tudo.

É exatamente o design certo para construir o workflow e exatamente o errado para a URL que você cola na Stripe. E, como tudo funcionou perfeitamente durante o desenvolvimento, o modelo mental que se forma é "o webhook funciona", o que torna difícil enxergar a causa real.

/webhook-test/… · ESCUTA UM ÚNICO EVENTOvocê clicaListen for test1 execuçãovocê sai da página404para tudopara sempre/webhook/… · SÓ EXISTE ENQUANTO ESTÁ ATIVADOworkflowsalvo, inativo404ativarrota no arsalvo ≠ ativado

Vá conferir a URL cadastrada no seu provedor. Se ela contém webhook-test, esse é seu bug, e você pode parar de ler aqui.

2. O workflow não está ativado

A URL de produção é registrada quando você ativa (publica) o workflow. A URL de produção de um workflow inativo responde 404, porque, para o servidor, essa rota não existe.

A armadilha é que salvar não é ativar. Você pode editar, salvar e fechar um workflow o dia inteiro, e a rota de produção nunca é atualizada. Falhas parecidas, da mesma família:

  • Desativar para fazer uma alteração e depois esquecer de reativar. Todo evento que chega nesse intervalo se perde
  • Duplicar um workflow para testar uma alteração. A cópia fica inativa, e quem continua recebendo o tráfego é o original
  • Mudar o path do nó Webhook, o que muda a URL. O provedor continua apontando para a antiga

Confira a chave de ativação no editor e confira se a URL cadastrada no provedor bate exatamente com o path atual.

3. O modo de resposta não é o que o provedor espera

A opção Respond do nó Webhook, que define o modo de resposta, controla quando e o que o n8n responde:

ModoComportamento
ImmediatelyResponde 200 com "Workflow was started" assim que o evento chega
When Last Node FinishesMantém a conexão aberta até o workflow terminar e responde com a saída do último nó
Using 'Respond to Webhook' nodeVocê controla o status e o corpo explicitamente

Immediately é o padrão certo, e você deve continuar nele. Ele responde rápido, o que mantém você dentro do timeout de todos os provedores, não importa quanto tempo o workflow leve.

Dois casos em que ele não serve.

Handshakes de verificação. Alguns provedores exigem que você devolva um valor de challenge na inscrição, como um token ou um hash do corpo. "Immediately" responde com uma mensagem fixa, e a inscrição é rejeitada. Você precisa do nó Respond to Webhook para devolver exatamente o valor esperado.

When Last Node Finishes, com um workflow lento. Agora seu tempo de resposta é o tempo de execução do workflow inteiro. Três chamadas de API e uma escrita no Google Sheets levam fácil 8 segundos, e o prazo de resposta da Shopify é de cinco. O provedor registra um timeout, tenta de novo, e seu workflow roda uma segunda vez desde o início. É esse o modo que cria linhas duplicadas em silêncio.

Se você está em "When Last Node Finishes" e não precisa especificamente da saída na resposta, mude para Immediately.

4. A verificação de assinatura falha porque o Raw Body está desligado

Se você verifica uma assinatura da Stripe, da Shopify ou do GitHub dentro do n8n, a opção Raw Body do nó Webhook é obrigatória.

Os provedores calculam o HMAC sobre os bytes exatos que enviaram. Com o Raw Body desligado, o n8n faz o parse do JSON, e qualquer nó de código que o serialize de novo produz bytes diferentes: outra ordem de chaves, outros espaços em branco. Os dados são idênticos, mas a assinatura não. Você vai ficar olhando para um payload visivelmente correto enquanto a verificação falha, o que rende uma hora de enlouquecer de verdade.

Ligue o Raw Body e calcule o HMAC sobre a string bruta antes de fazer o parse de qualquer coisa:

const crypto = require('crypto');
const raw = $input.first().binary
  ? Buffer.from($input.first().binary.data.data, 'base64').toString('utf8')
  : $input.first().json.body;

const expected = crypto
  .createHmac('sha256', $env.SHOPIFY_SECRET)
  .update(raw, 'utf8')
  .digest('base64');

const received = $input.first().json.headers['x-shopify-hmac-sha256'];
if (!crypto.timingSafeEqual(Buffer.from(expected), Buffer.from(received))) {
  throw new Error('invalid signature');
}
return { json: JSON.parse(raw) };

Use timingSafeEqual, não ===. E repare que ele lança uma exceção quando os tamanhos não batem, então trate esse caso se a entrada não for confiável. Mais sobre os formatos de cada provedor em Como verificar assinaturas de webhook da Stripe, do GitHub e da Shopify.

5. Uma execução com falha deixa o evento encalhado

Esta é a que custa dinheiro de verdade, e não é um bug. É só o jeito como o modelo funciona.

Com Respond em Immediately, o n8n já respondeu 200 antes de seu workflow rodar. O provedor considera o evento entregue e nunca mais vai enviá-lo. Se depois o nó 4 falhar por causa de um token expirado, de um rate limit ou de um campo malformado, essa execução é marcada como falha, e o evento só existe no registro dessa execução com falha.

Não existe nova tentativa (retry) automática do webhook recebido. Não existe fila na frente dele. O provedor não vai reenviar, porque, do ponto de vista dele, deu tudo certo.

O que fazer:

  • Defina um Error Workflow (workflow de erro) nas configurações do workflow. No mínimo, ele deve avisar você. Falhar em silêncio é o padrão, e não é um bom padrão
  • Grave o payload bruto no nó 1. Antes de qualquer transformação, escreva o corpo no Postgres, no Airtable, numa planilha do Google Sheets, em qualquer lugar durável. Assim, uma execução com falha não se perde: o evento fica no seu próprio armazenamento, disponível para replay (um novo envio de um evento armazenado, feito por você)
  • Use continueOnFail de propósito nos nós em que um sucesso parcial é aceitável, e não nos nós em que ele engole em silêncio a falha que você precisava ver
  • Confira a retenção. O n8n self-hosted apaga os dados de execução periodicamente e, depois dessa limpeza, até o payload da execução com falha some

6. Self-hosted: o proxy reverso está atrapalhando

Numa instalação self-hosted atrás de nginx, Traefik ou Caddy, algumas camadas podem engolir requisições antes que o n8n as veja:

  • Limites de tamanho do corpo. O nginx usa 1 MB como padrão de client_max_body_size e responde 413 para qualquer coisa maior. Um payload em lote da Shopify ou um anexo em base64 passa desse limite
  • Timeouts do proxy. Se o proxy_read_timeout for mais curto que seu workflow, o proxy fecha a conexão e o provedor registra uma falha, mesmo que o n8n tenha terminado
  • Variável WEBHOOK_URL não definida. O n8n gera a partir dela as URLs que exibe. Atrás de um proxy, ele mostra endereços internos que funcionam no seu notebook e não na internet
  • Workers do queue mode. No queue mode, o webhook precisa chegar à instância principal, e roteá-lo para um worker resulta em 404

O diagnóstico rápido: rode curl -X POST contra sua URL de produção de fora da sua rede. Um 404 indica roteamento ou ativação. Um 413 indica tamanho do corpo. Se a requisição travar, é timeout. Um 200 sem nada em Executions significa que a execução não foi salva: confira nas configurações do workflow se as execuções de produção estão sendo salvas.

7. O evento chegou, mas um filtro o descartou

Menos comum, mas vale eliminar a hipótese: a execução existe, mas parece não ter feito nada. Compare as condições de qualquer nó IF ou Switch com o formato real do payload, já que os provedores aninham os campos de um jeito diferente do payload de teste que você usou para construir o workflow. Se não houver execução nenhuma, confira o HTTP Method do nó, que por padrão é GET, já que um provedor que faz POST num webhook que só aceita GET recebe um 404 idêntico ao de um problema de roteamento.

Onde o AnyHook entra

A causa 5 é a estrutural. O n8n executa workflows. Ele não armazena o evento antes e, no momento em que responde 200, a única outra cópia que existiu é a do provedor.

Colocar o AnyHook na frente muda o que "entregue" significa. Você aponta o provedor para in.anyhook.net/you/app e aponta o AnyHook para a URL de produção do n8n, ou seja, duas trocas de URL e nenhum workflow reescrito. A partir daí:

  • O AnyHook armazena o evento antes de chamar o n8n, então uma execução com falha fica disponível para replay pelo log
  • As novas tentativas seguem um backoff exponencial contra sua instância do n8n, então um reinício durante uma atualização se recupera sozinho
  • A verificação de assinatura acontece na edge (o Cloudflare Worker do AnyHook). Configure o segredo do provedor uma vez e receba um único cabeçalho AnyHook-Signature; assim, a ginástica com o Raw Body da causa 4 vira uma única verificação de HMAC que você escreve uma vez para todos os provedores
  • Alertas de falha disparam com 1, 5 e 20 falhas consecutivas, com pausa automática para que um workflow quebrado não provoque uma tempestade de novas tentativas

A versão que importa na prática: uma atualização do n8n que derruba a instância por dez minutos pode custar todos os eventos desses dez minutos. Com um relay de webhooks (um serviço que recebe, guarda e encaminha seus webhooks) na frente, custa um clique de replay.

A configuração não exige código:

  1. No AnyHook, crie um app (uma URL de entrada para uma origem). Escolha o remetente como origem se ele estiver na lista (a Shopify está) ou Generic se não estiver, como o Typeform. Defina como destino a URL de produção (Production URL) do webhook do seu workflow.
  2. No remetente, troque a URL do webhook pela URL de entrada do app. No admin da Shopify, isso fica em Settings → Notifications → Webhooks; no Typeform, em Connect → Webhooks.
  3. Se o workflow começa com o nó Shopify Trigger ou Typeform Trigger do próprio n8n, troque-o por um nó Webhook simples. Os nós de trigger registram o próprio webhook no provedor, o que passaria por fora do AnyHook.
  4. Depois de uma queda, abra o app no AnyHook e faça o replay pelo banner de eventos com falha.

Um app atende um remetente, e o plano Free tem um app, então um segundo remetente exige o Pro.

Conclusão

Confira a URL primeiro. webhook-test versus webhook é a resposta muito mais vezes do que qualquer outra coisa, e a ativação vem logo em seguida. Quando estiver recebendo, o que você precisa corrigir antes de esquecer é a persistência: grave o payload bruto no primeiro nó e configure um workflow de erro. O n8n não vai reenviar o que perdeu, e o provedor também não.

Todos os posts3 de agosto de 2026 · 8 min

Pare de perder webhooks.

Troque uma URL. Tenha novas tentativas, um log de eventos e replay com um clique. Ou veja antes: crie uma conta, rode a simulação de queda de 30 segundos e veja um evento sobreviver ao seu servidor fora do ar. Não precisa de servidor.