Pular para o conteúdo
~/buildbase $ 06/11/2026
APIs

O que é webhook e qual a diferença entre webhook e API

Notebook aberto com tela azul sobre mesa branca

Webhook é uma API ao contrário? Quase isso. Numa API comum, o seu sistema pergunta e o outro responde. No webhook, o outro sistema avisa o seu assim que algo acontece, sem você precisar perguntar. É a diferença entre ligar para a pizzaria a cada cinco minutos para saber se a pizza saiu e receber uma mensagem do motoboy dizendo “estou na porta”.

$ ls ./neste-artigo
  1. Webhook e API são coisas diferentes ou a mesma coisa?
  2. Como um webhook chega até o meu código?
  3. Qualquer pessoa pode mandar um POST falso para a minha URL?
  4. O mesmo evento chegou duas vezes. É bug?
  5. Por que o serviço diz que meu webhook “falhou” se o código rodou?
  6. Como testo um webhook se meu projeto roda em localhost?
  7. Quais são exemplos reais de webhook no dia a dia?
  8. Antes de colocar seu primeiro webhook em produção

Tecnicamente, um webhook é só uma requisição HTTP POST que um serviço externo dispara para uma URL sua quando um evento acontece: um pagamento aprovado, um push no repositório, uma mensagem nova no chat. O “mistério” acaba aí. O que dá trabalho de verdade é receber essa chamada com segurança e sem perder eventos, e é nisso que a maioria dos tutoriais para cedo demais.

Este verbete integra o glossário de programação, e as seções abaixo respondem às dúvidas que mais aparecem quando alguém implementa o primeiro webhook.

Cabos de rede azuis conectados em um painel
Por trás de cada webhook há uma requisição HTTP atravessando a rede até a sua URL. Foto: Scott Rodgerson / Unsplash

 
 

Webhook e API são coisas diferentes ou a mesma coisa?

São parentes. Os dois usam HTTP, JSON e URLs. A diferença está em quem inicia a conversa.

AspectoAPI (consulta)Webhook
Quem chamaSeu sistema chama o serviçoO serviço chama o seu sistema
QuandoQuando você decide perguntarQuando o evento acontece
AtrasoDepende do intervalo das consultasSegundos, em geral
Custo de requisiçõesMuitas chamadas vazias (“nada novo”)Uma chamada por evento
O que você precisa exporNada, só faz chamadas de saídaUma URL pública que aceita POST
Bom paraBuscar dados sob demanda, listar, filtrarReagir a eventos

Na prática, os dois trabalham juntos. O webhook avisa “o pedido 123 mudou”, e o seu código chama a API para buscar o estado completo do pedido. Muita integração boa é exatamente essa dupla. Se você está em dúvida sobre qual usar num caso concreto, o texto sobre quando usar webhook em vez de consultar uma API periodicamente aprofunda essa escolha.

 

Como um webhook chega até o meu código?

O caminho tem quatro passos, e vale entender cada um porque é neles que os bugs aparecem:

  1. Cadastro. No painel do serviço (GitHub, Stripe, Mercado Pago, Shopify), você informa a URL que vai receber os avisos, por exemplo https://meuapp.com.br/webhooks/pagamentos, e escolhe quais eventos quer.
  2. Evento. Algo acontece do lado deles: o cliente pagou o Pix, alguém abriu um pull request.
  3. Entrega. O serviço monta um JSON com os dados do evento e faz um POST para a sua URL, quase sempre com cabeçalhos extras (tipo do evento, ID da entrega, assinatura).
  4. Resposta. Seu servidor devolve um código 2xx. Se devolver erro ou demorar demais, o serviço considera que a entrega falhou e, dependendo dele, tenta de novo mais tarde.

Um receptor mínimo em Node.js com Express fica assim:

app.post("/webhooks/pagamentos", express.raw({ type: "application/json" }), (req, res) => {
  // 1. validar a assinatura (ver abaixo)
  // 2. guardar o evento numa fila ou tabela
  res.sendStatus(200); // 3. responder rápido
  // 4. processar depois, fora da requisição
});

Repare no express.raw: ele mantém o corpo exatamente como chegou, em bytes. Isso importa para a próxima pergunta.

 

Qualquer pessoa pode mandar um POST falso para a minha URL?

Pode. A URL do webhook é pública, e nada impede alguém de descobrir o endereço e enviar um JSON dizendo “pagamento aprovado”. Se o seu código libera o produto só porque recebeu esse JSON, você acabou de criar um botão de compra grátis.

A defesa padrão é a assinatura HMAC. Na hora do cadastro, o serviço gera um segredo compartilhado. A cada envio, ele calcula um hash do corpo da requisição usando esse segredo e manda o resultado num cabeçalho. Seu código refaz a conta com o mesmo segredo e compara. Se bater, a mensagem veio de quem tem o segredo e não foi alterada no caminho.

O GitHub, por exemplo, envia o cabeçalho X-Hub-Signature-256 com um HMAC SHA-256 do corpo, e a documentação sobre validação de entregas de webhook no GitHub mostra o cálculo em várias linguagens. Dois detalhes derrubam muita gente:

  • Calcule sobre o corpo cru. Se o framework já converteu o JSON em objeto e você reconverte para texto, espaços e ordem de campos mudam, e a assinatura nunca bate.
  • Compare em tempo constante. Use funções como crypto.timingSafeEqual (Node) ou hmac.compare_digest (Python), e não um == comum, para não vazar informação pelo tempo de resposta.

Alguns serviços acrescentam um carimbo de data e hora na assinatura para impedir que alguém capture uma requisição válida e a reenvie dias depois. Quando existir, rejeite eventos muito antigos. Serviços que publicam a lista de IPs de origem permitem uma camada extra com allowlist, mas essa lista muda; o GitHub fez exatamente isso recentemente, como mostramos em GitHub muda IPs de webhooks. Trate IP como reforço, nunca como única barreira.

 

O mesmo evento chegou duas vezes. É bug?

Porque quase todo serviço de webhook garante entrega pelo menos uma vez, e não exatamente uma vez. Se a sua resposta 200 se perdeu na rede, o remetente acha que falhou e reenvia. O resultado: o mesmo “pagamento aprovado” pode chegar duas ou três vezes.

A solução tem nome: idempotência. Cada evento traz um identificador único (o GitHub manda o X-GitHub-Delivery; a Stripe põe um id no próprio evento). Guarde esse ID numa tabela com restrição de unicidade e, antes de processar, verifique se ele já passou por ali. Se já passou, responda 200 e não faça nada.

Imagine uma loja que manda o e-mail de “pedido confirmado” e baixa o estoque a cada webhook recebido. Sem idempotência, um reenvio vira dois e-mails e duas baixas de estoque. Com a tabela de IDs, o segundo aviso é ignorado em silêncio.

 

Por que o serviço diz que meu webhook “falhou” se o código rodou?

Quase sempre é tempo de resposta. Os remetentes esperam alguns segundos e desistem. O GitHub, por exemplo, considera a entrega falha se não houver resposta em 10 segundos. Se o seu receptor gera nota fiscal, chama outra API e manda e-mail antes de responder, ele estoura o prazo, o serviço registra falha e reenvia, e você ganha duplicidade de brinde.

O desenho que funciona é: valide, guarde, responda, processe depois. O receptor só confere a assinatura, grava o evento numa fila (Redis, RabbitMQ, SQS ou até uma tabela “eventos_pendentes”) e devolve 200. Um processo separado consome a fila no seu ritmo, com tentativas próprias.

Outro detalhe: a ordem de chegada não é garantida. Um evento “pedido cancelado” pode chegar antes do “pedido criado” se o primeiro envio falhou e foi reenviado. Por isso, em vez de confiar cegamente no conteúdo do aviso, muita equipe usa o webhook como gatilho e consulta a API para pegar o estado atual.

 

Como testo um webhook se meu projeto roda em localhost?

O serviço externo não enxerga o seu localhost:3000. Você tem três saídas:

  • Túnel. Ferramentas como ngrok ou Cloudflare Tunnel criam uma URL pública temporária que repassa para a sua máquina.
  • CLI do provedor. A Stripe tem um comando que escuta eventos e encaminha para o seu endereço local; a documentação de webhooks da Stripe explica o fluxo e também a política de reenvio.
  • Reenvio pelo painel. GitHub e outros guardam o histórico das entregas, com corpo, cabeçalhos e resposta. Dá para clicar em “Redeliver” e repetir um evento real enquanto depura.

Um hábito útil: salve alguns corpos reais de eventos em arquivos JSON no projeto e use-os nos testes automatizados. Assim você testa o processamento sem depender do serviço externo estar no ar.

 

Quais são exemplos reais de webhook no dia a dia?

Você provavelmente já usou vários sem perceber:

  • Gateways de pagamento avisando que um Pix ou boleto foi compensado.
  • GitHub e GitLab disparando o pipeline de testes a cada push.
  • Bots de Discord e Slack recebendo mensagens para responder.
  • Lojas virtuais avisando o ERP sobre pedidos novos.
  • Ferramentas de formulário mandando cada resposta para uma planilha ou CRM.
  • APIs de WhatsApp Business entregando as mensagens recebidas ao seu sistema.

Em todos esses casos, consultar a API a cada minuto seria lento e caro. O webhook resolve porque o evento é raro e imprevisível, e você quer reagir rápido.

 

Antes de colocar seu primeiro webhook em produção

Passe por esta lista. Cada item já derrubou algum sistema real:

  • A URL usa HTTPS?
  • A assinatura é validada sobre o corpo cru, com comparação em tempo constante?
  • O segredo está em variável de ambiente, e não no código?
  • O ID de cada evento é gravado para evitar processamento duplicado?
  • A resposta 200 sai em menos de um segundo, com o trabalho pesado numa fila?
  • Os eventos recebidos ficam registrados em log, para você investigar quando o cliente disser “paguei e não liberou”?
  • Existe um alerta se as entregas começarem a falhar em sequência?

Se você só fizer duas coisas, que sejam validar a assinatura e tratar duplicidade. São os dois pontos que separam um webhook de brinquedo de um que aguenta dinheiro de verdade passando por ele.