Artigo técnico

Guia para times de engenharia e produto que precisam reduzir incidente de webhook sem complicar a operação.

Idempotência em webhooks: como evitar duplicidade sem quebrar seu SaaS

Um guia prático para tratar eventos duplicados, retries e falhas de rede com segurança operacional.

Voltar para o blog

Publicado em 17/03/2026 · Atualizado em 17/03/2026 · 11 min de leitura

webhooksidempotênciaarquiteturasaas
Fluxo simples de idempotência com chave única
Clique para ampliar

Visão de alto nível: receber evento, validar chave idempotente e evitar processamento duplicado.

Timeline de tentativa inicial, timeout e retry controlado
Clique para ampliar

Retry não é vilão: o problema é quando o consumidor não trata repetição com idempotência.

Por que webhook duplicado acontece com tanta frequência

Em linguagem direta: o webhook não é uma ligação de telefone com confirmação perfeita. É mais parecido com uma mensagem que pode atrasar, cair ou ser reenviada.

Quando uma entrega falha no caminho ou retorna timeout, o emissor normalmente tenta de novo. O problema não é o retry em si, e seu backend tratar a segunda tentativa como um evento novo.

Na prática, provedores como Stripe tratam webhooks como entrega assíncrona com retries automáticos, eventos possivelmente duplicados e sem garantia de ordenação estrita.

  • Timeout na resposta do consumidor mesmo com processamento concluído
  • Retry automático do provedor após status 5xx
  • Reprocessamento manual durante incidente
  • Consumidor sem estratégia de deduplicação

Idempotência na prática: o que significa

Uma operação idempotente permite executar a mesma ação mais de uma vez sem alterar o resultado final após a primeira execução válida.

No contexto de webhooks: se o evento X chegar 3 vezes, seu sistema deve aplicar os efeitos de negócio apenas uma vez. O cliente final não pode ser cobrado, ativado ou notificado em triplo.

A definição formal do HTTP (RFC 7231) reforça que idempotência é exatamente essa propriedade de repetir uma requisição sem mudar o efeito pretendido após a primeira execução.

Padrão recomendado: chave idempotente + tabela de processamento

A forma mais segura para a maioria dos SaaS é persistir uma chave única do evento antes de executar efeitos colaterais.

Se a chave já existir, a requisição vira no-op (ou retorna o mesmo resultado da primeira execução).

No Postgres, `INSERT ... ON CONFLICT` é uma base forte para esse controle, com semântica atômica de insert/update mesmo sob concorrência alta.

Traduzindo para negócio: você para de apagar incêndio de duplicidade e passa a ter previsibilidade na operação.

SQL
CREATE TABLE webhook_event_locks (
idempotency_key TEXT PRIMARY KEY,
source TEXT NOT NULL,
received_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
status TEXT NOT NULL DEFAULT 'processing'
);

-- tentativa de claim atômico
INSERT INTO webhook_event_locks (idempotency_key, source, status)
VALUES ($1, $2, 'processing')
ON CONFLICT (idempotency_key) DO NOTHING;

Fluxo seguro de processamento

O fluxo ideal precisa ser atômico e simples de operar em incidente. Evite regra escondida em vários lugares porque isso vira bug caro.

  • 1) Validar assinatura e schema do webhook
  • 2) Gerar ou ler chave idempotente (event_id do provedor ou hash confiável)
  • 3) Tentar inserir lock idempotente
  • 4) Se lock falhar: reconhecer duplicado e encerrar
  • 5) Se lock passar: processar negócio e gravar status final
  • 6) Em falha recuperável: permitir retry com controle explícito

Onde guardar a chave: Redis ou Postgres?

Redis é excelente para altíssima taxa e baixa latência, mas sozinho pode perder estado dependendo da estratégia de persistência.

Postgres traz garantia forte e trilha de auditoria. Para muitos SaaS, Postgres como fonte da verdade é um bom ponto de partida.

Uma estratégia comum em produção é combinar os dois: Redis para absorver pico e Postgres para consistência durável.

Se você está no início, prefira simplicidade: comece com Postgres bem modelado e evolua para camada híbrida quando volume justificar.

  • Redis: rápido, bom para cache e janelas curtas de deduplicação
  • Postgres: consistente, auditável, mais simples para regras de negócio
  • Abordagem híbrida: claim rápido no Redis + confirmação final no banco

Erros comuns que causam retrabalho

Muitos times implementam retry antes de idempotência. Isso aumenta a frequência de duplicidade e pressiona suporte.

Outro erro comum é usar payload inteiro como chave sem normalização, quebrando deduplicação por pequenas variações irrelevantes.

  • Atualizar estoque/faturamento antes de registrar chave idempotente
  • Não expirar ou arquivar chaves antigas (crescimento sem controle)
  • Considerar somente status HTTP e ignorar semântica de negócio
  • Não ter métricas de duplicidade para observabilidade operacional
  • Assumir que eventos chegam em ordem cronológica

Checklist de implementação para seu time

Se você precisa sair do modo reativo em webhooks, este checklist reduz bastante incidente nas primeiras semanas.

  • Defina o campo canônico de idempotência por provedor
  • Implemente claim atômico antes de efeitos colaterais
  • Padronize resposta para duplicado (2xx com no-op)
  • Crie métricas: eventos recebidos, duplicados, retries, falhas finais
  • Documente playbook de reprocessamento manual com segurança
  • Use backoff exponencial com jitter para evitar avalanche em incidentes

Conclusão

Idempotência não é opcional para webhook em produção: ela separa fluxo confiável de operação caótica.

Quando idempotência, retry e rastreabilidade trabalham juntos, seu time reduz incidente, acelera suporte e protege receita.

Fontes oficiais utilizadas

Próximos conteúdos para publicar

  • Fair queues para webhooks: como evitar starvation entre tenants
  • Retry exponencial com jitter: quando usar e como configurar
  • Dead-letter queue em webhooks: estratégia de recuperação sem perder evento
  • Assinatura HMAC em webhooks: validação correta e erros comuns
  • Rate limiting por endpoint: proteger consumidor sem derrubar entrega
  • Particionamento de eventos no Postgres para alto volume diario

Quer aplicar isso no seu fluxo de webhook?

Entre na pre-lista da Rastro para testar uma operação de entrega com retry e rastreabilidade.