Skip to main content
Sem validação, qualquer pessoa que descobrir sua URL de webhook pode forjar eventos e acionar lógica de negócio (ex: liberar acesso sem pagar). O secret é o que prova que o evento veio da AbacatePay, porque só você e a AbacatePay conhecem esse valor. A assinatura HMAC garante que o corpo não foi alterado no caminho. Todo webhook enviado pela AbacatePay inclui dois mecanismos de segurança: um secret na URL e uma assinatura HMAC no header. Use os dois juntos.

1. Secret na URL

Ao criar o webhook, você define um secret. A AbacatePay inclui esse valor como query parameter em cada requisição:
Seu backend valida antes de qualquer processamento:

2. Assinatura HMAC

A assinatura HMAC garante que o corpo da requisição não foi alterado no caminho. O header enviado é:
A assinatura é calculada com HMAC-SHA256 sobre o corpo raw da requisição usando a chave pública da AbacatePay.

Validação em Node.js

Validação em Python

Validação em Go

Use sempre timingSafeEqual (ou equivalente) ao comparar assinaturas — nunca ==. Comparações diretas são vulneráveis a timing attacks.

Retentativas

Se seu endpoint não responder 2xx em até 30 segundos por um motivo temporário, a AbacatePay tenta reenviar o evento automaticamente: até 7 tentativas ao longo de cerca de 18 horas. O que causa retentativa:
  • Timeout (30 segundos), erro de conexão, DNS ou TLS
  • Resposta com status 5xx
  • Resposta com status 408 ou 429
Outros 4xx e 3xx não são retentados, e 410 Gone desativa o webhook. Veja os intervalos completos em Entrega e retentativas. Boas práticas para lidar com retentativas:

Idempotência é obrigatória

Armazene o campo id de cada evento recebido. Todas as retentativas de um evento chegam com o mesmo id: antes de processar, verifique se ele já foi tratado.

Checklist de segurança

  • Use HTTPS — nunca HTTP em produção
  • Valide o secret na query string
  • Valide a assinatura HMAC do header
  • Responda 200 OK somente após concluir o processamento
  • Implemente idempotência usando o id do evento
  • Não valide o payload inteiro com schemas rígidos (como Zod) — campos novos podem ser adicionados futuramente