Técnico

Idempotency key

Chave de idempotência — garantia de execução única de uma requisição de API

Mecanismo pelo qual um cliente envia um identificador único junto com uma requisição de API mutante (POST), garantindo que, em caso de retry de rede, a operação seja executada apenas uma vez do lado do servidor. Best practice crítica para APIs de pagamento.

Definição

A idempotency key (chave de idempotência) é um identificador único que um cliente envia junto com uma requisição mutante (tipicamente um POST) para garantir que, em caso de retry de rede, a operação seja executada apenas uma vez.

O servidor armazena a chave; se a mesma requisição voltar, ele devolve a resposta anterior sem reexecutar a operação. É uma best practice crítica para qualquer API de pagamento, em que uma dupla execução significa pagamento em dobro, cobrança em dobro ou estado corrompido. Stripe, Bridge, Adyen, Mollie, AWS e muitos outros a exigem ou a suportam.

Por que é crítica

Na rede, a incerteza é a regra: uma requisição pode expirar sem que se saiba se foi recebida, processada ou se um retry vai duplicar a operação. Sem chave de idempotência, é impossível fazer retry com segurança; com ela, o cliente pode repetir tranquilamente, e o servidor devolve a resposta armazenada se a operação já tiver ocorrido.

Como funciona

Formato e boas práticas

  • Geração: UUID v4 (aleatório), ULID (ordenado no tempo, debug-friendly) ou hash de negócio determinístico (SHA256(user_id + transaction_ref)).
  • Header: Idempotency-Key: 4a7f3b80-fe5c-4d12-9c7e-83b3a4ab9b1c. A IETF publicou um draft, mas a convenção foi adotada bem antes de sua oficialização.
  • Duração do cache: 24h na Stripe e na Bridge, 1h na Mollie. Recomendado: 24 a 48h para pagamentos, 7 a 30 dias para fluxos assíncronos. Além disso, um retry reexecutaria a operação.
  • Escopo: por lojista / por conta (recomendado), em vez de global (risco de colisão).

Payload diferente, mesma chave

Se a mesma chave for enviada com um payload diferente, o servidor deveria rejeitar a requisição (409 Conflict), como fazem a Stripe e a AWS. Isso evita que um payment 200 € seja silenciosamente ignorado após um payment 100 € com a mesma chave.

Casos de uso

  • Pagamentos: POST /payments, /transfers, /charges, /refunds — sempre.
  • Criação de recursos: POST /customers, /subscriptions — para evitar duplicatas.
  • Operações custosas: POST /kyc, /loans/disburse.
  • Desnecessária em: GET (idempotente por natureza), PUT com ID explícito, DELETE.

Idempotency-Key vs outras técnicas

TécnicaGarantiaComplexidade
Idempotency-Key (header)Exactly-once por chamadaBaixa do lado do cliente
Token de transação únicoExactly-once por transação de negócioMédia
Lock otimista de BDExactly-once por recursoMédia
Saga + commandsExactly-once por fluxoAlta

A Idempotency-Key atua no nível da API: ela não protege contra um bug de negócio (um usuário que paga duas vezes por meio de dois botões diferentes gera duas chaves distintas).

Implementação do lado do servidor

Armazenamento típico: Redis (TTL nativo, chave idempotency:{merchant}:{key}), DynamoDB para escalabilidade ou PostgreSQL em baixo volume.

def handle_payment(req):
    key = req.headers.get("Idempotency-Key")
    if not key:
        return create_payment(req)
 
    cached = redis.get(f"idempotency:{merchant}:{key}")
    if cached:
        return cached
 
    with redis.lock(f"idempotency-lock:{merchant}:{key}", ttl=30):
        cached = redis.get(f"idempotency:{merchant}:{key}")
        if cached:
            return cached
 
        response = create_payment(req)
        redis.setex(f"idempotency:{merchant}:{key}", 86400, response)
        return response

O lock é necessário se duas requisições com a mesma chave chegarem ao mesmo tempo (race condition de retry), para evitar uma dupla execução em paralelo.

Comportamento em caso de falha

  • Timeout do cliente, sucesso no servidor: retry com a mesma chave → resposta em cache (sucesso).
  • Erro 5xx: a maioria dos provedores reexecuta (um 5xx não é considerado definitivo).
  • Erro 4xx: retry com a mesma chave → a resposta 4xx em cache é devolvida.

O que a Idempotency-Key não é

  • Não é uma transação distribuída: ela não garante a consistência entre serviços.
  • Não é uma proteção de negócio: dois cliques em dois botões geram duas chaves.
  • Não é uma substituição da autenticação: é complementar.
  • Não é necessária em GET / PUT: nativamente idempotentes.
  • Não é (ainda) um padrão formal: draft IETF, mas convenção quase universal.

No ecossistema PSD2 / Open Finance

  • Berlin Group: recomenda X-Request-ID (equivalente).
  • STET: header X-Request-ID.
  • OBIE UK: x-idempotency-key.
  • PSPs adquirentes (Stripe, Adyen, Mollie): adotada universalmente.
  • Webhooks: a chave também é crucial na recepção, para não processar duas vezes um mesmo evento.

Exemplos concretos

  • Stripe: header Idempotency-Key, cache de 24h, rejeição de payload diferente — o padrão do setor.
  • Bridge: Idempotency-Key + X-Request-ID conforme o endpoint.
  • Mollie: Idempotency-Key, cache de 1h.
  • AWS: parâmetro client-token.
  • Caso vivido: um lojista sem chave de idempotência faz retry após um timeout → débito em dobro em 0,5% dos pagamentos → dezenas de milhares de euros em estornos e perda de confiança.
  • Padrão de UI: gerar a chave no momento do clique e persisti-la no state do formulário — um novo clique 5 segundos depois reutiliza a mesma chave, sem cobrança em dobro.

Fontes

Aprofundar

No blog

Leituras mais completas para ir além da definição.

7 de abril de 2026
técnico

Arquitetura técnica de uma API DSP2: o que é preciso saber antes de escrever a primeira linha de código — Ler o artigo

Panorama técnico da DSP2 para CTOs, desenvolvedores e PMs técnicos: padrões de API, segurança (mTLS, certificados eIDAS), OAuth2, fluxos SCA, gestão do consentimento, armadilhas de implementação.

6 de abril de 2026
regulação

Entender a PSD2: o que ela muda para seus clientes e seu negócio — Ler o artigo

Tudo o que um dirigente, um product manager ou uma equipe de negócios precisa entender sobre a PSD2 (DSP2). Atores, consentimento, oportunidades, sem jargão técnico.