Voltar para o inícioAPIs & Integrações

Como implementar idempotency keys em APIs públicas: guia prático para produção

Aprenda a implementar idempotency keys em APIs públicas para evitar cobranças, pedidos e operações duplicadas mesmo diante de retries, timeouts e chamadas concorrentes.

M

Max Alex

Como implementar idempotency keys em APIs públicas: guia prático para produção

Operações que alteram estado — como cobrar um pagamento, criar um pedido, provisionar um acesso ou disparar uma integração — não podem depender da suposição de que cada requisição chegará uma única vez. Em redes reais, timeouts, retries automáticos e cliques repetidos são normais.

As idempotency keys em APIs dão à API uma forma explícita de reconhecer tentativas da mesma intenção de negócio. Assim, o cliente pode repetir uma chamada com segurança sem transformar uma falha de comunicação em uma operação duplicada.

O que são idempotency keys e por que elas são essenciais

Uma idempotency key é um identificador único gerado pelo cliente e enviado em uma operação mutável, normalmente no cabeçalho Idempotency-Key. A API associa essa chave à primeira execução e trata chamadas posteriores com a mesma chave como repetição da mesma intenção.

Em termos práticos, não basta dizer que um método HTTP é seguro ou idempotente. Um POST que cria uma cobrança pode se tornar operacionalmente idempotente quando a API deduplica as tentativas usando uma chave e devolve o resultado já produzido.

Isso é especialmente importante em pagamentos, pedidos, provisionamento de recursos e envio de mensagens. Imagine um cliente enviando POST /payments com uma chave única. Se a conexão expirar depois que o servidor concluir a cobrança, o retry usa a mesma chave e recebe a resposta original, sem criar uma segunda cobrança.

A chave não substitui um bom desenho de endpoint, validações ou transações. Ela adiciona uma camada de proteção para que a intenção do cliente seja executada uma vez, mesmo quando a entrega da requisição for incerta.

Quais problemas a idempotência resolve em produção

Um timeout não prova que a operação falhou no servidor. Ele apenas informa que o cliente não recebeu uma resposta dentro do prazo. O servidor pode ter processado a solicitação segundos antes, enquanto o cliente já prepara uma nova tentativa.

Também há retries de bibliotecas HTTP, gateways, filas, jobs e interfaces que permitem dois cliques. Sem uma estratégia de deduplicação, cada caminho pode produzir um novo efeito colateral.

O ponto mais importante do contrato é simples: retries da mesma operação devem reutilizar a mesma chave. Gerar uma chave nova em cada tentativa transforma o mecanismo em apenas um identificador aleatório e não impede duplicidade.

O comportamento de erros também precisa ser previsível. Um bom tratamento de erros em APIs ajuda o integrador a distinguir uma rejeição definitiva, uma operação em processamento e uma resposta reapresentada.

Defina o contrato da idempotency key antes de codificar

Comece definindo quais endpoints exigem a chave. Em geral, priorize operações críticas que criam recursos, movimentam valores ou acionam sistemas externos. Um cabeçalho Idempotency-Key evita poluir o corpo da requisição e torna a regra visível para quem integra.

Documente formato aceito, tamanho máximo, escopo e período de retenção. UUIDs são uma escolha frequente para clientes, mas o contrato não precisa depender exclusivamente desse formato. O essencial é haver entropia suficiente e uma validação clara.

A chave deve ser escopada. Uma combinação como conta autenticada, método HTTP, rota e chave evita que o mesmo valor colida entre clientes ou operações diferentes. Além disso, guarde uma impressão digital do payload normalizado.

Se uma chave já usada reaparecer com parâmetros incompatíveis, não execute a nova intenção. Retorne um conflito, como 409 Conflict, explicando que a chave está vinculada a outra requisição. Para POST /orders, por exemplo, a mesma chave não pode representar ao mesmo tempo um pedido de R$ 100 e outro de R$ 150.

Modele o armazenamento: chave, escopo, status e resposta

A implementação precisa de persistência durável para sobreviver a reinícios, múltiplas instâncias da aplicação e chamadas concorrentes. Cache isolado em memória pode ser útil como otimização, mas não deve ser a garantia principal de operações críticas.

Um registro de idempotência normalmente inclui o escopo do cliente, endpoint, chave, hash da requisição, estado, código HTTP, corpo da resposta, headers relevantes, identificador do recurso criado e data de expiração.

Crie um índice único composto, por exemplo: UNIQUE(account_id, endpoint, idempotency_key). Essa restrição é a barreira que impede duas instâncias da API de aceitarem a mesma primeira tentativa ao mesmo tempo. A modelagem de banco de dados deve considerar esse índice desde o início.

Estados como processing, completed e failed tornam o fluxo observável. Em completed, a API pode reproduzir o status e a resposta armazenados. Em processing, ela não deve iniciar novamente o efeito colateral.

Evite persistir segredos, dados completos de cartão, tokens e cabeçalhos desnecessários. Armazene somente o necessário para replay, auditoria e diagnóstico, aplicando mascaramento e controles de acesso adequados.

Implemente o fluxo atômico de processamento

O fluxo deve reservar a chave antes de executar a lógica de negócio. Primeiro, valide autenticação, formato da chave e payload. Em seguida, calcule um hash determinístico da requisição, considerando apenas os campos relevantes e uma representação normalizada.

  1. Tente criar atomically o registro da chave com estado processing.
  2. Se a inserção for bem-sucedida, execute a operação de negócio.
  3. Salve o resultado final, incluindo status e resposta, e marque o registro como completed.
  4. Se a chave já existir, compare o hash da requisição.
  5. Se o hash divergir, retorne 409 Conflict; se estiver concluída, devolva a resposta armazenada.

Chamadas simultâneas com a mesma chave exigem uma decisão documentada. Uma opção é devolver 409 Conflict ou 425 Too Early enquanto a primeira está em processamento. Outra é aguardar por um período curto e reapresentar o resultado quando ele estiver disponível. Em ambos os casos, a segunda chamada nunca deve executar novamente a lógica de negócio.

POST /orders
Idempotency-Key: 7d2f1b6e-...

1. INSERT do registro com chave única e state=processing
2. Criação do pedido
3. UPDATE com state=completed, status_code e response_body
4. Retry com a mesma chave => replay da resposta salva

Quando a operação e o registro de idempotência usam o mesmo banco, prefira uma transação que mantenha a consistência entre ambos. Se houver efeitos externos, será necessário complementar o fluxo com reconciliação.

Escolha a estratégia para falhas, concorrência e operações externas

O caso mais delicado ocorre quando o efeito externo foi aceito, mas a aplicação falha antes de registrar a resposta. Apagar a chave automaticamente pode permitir uma segunda execução, justamente quando o resultado da primeira é incerto.

Nessas situações, mantenha um estado pendente e registre identificadores de correlação. Um processo de reconciliação pode consultar o provedor externo, identificar a operação original e finalizar o registro local antes de permitir uma nova ação.

Se o provedor externo aceitar uma chave de idempotência, propague a mesma chave ou um identificador correlacionado. Isso reduz o risco ao longo da cadeia, mas não elimina a necessidade de controlar a idempotência no seu próprio domínio.

Para eventos assíncronos, combine o padrão com outbox transacional, filas e consumidores idempotentes. Entregas pelo menos uma vez são comuns; por isso, cada consumidor também deve reconhecer eventos já processados em vez de confiar que a fila nunca repetirá uma mensagem.

Defina TTL, limpeza e limites de retenção

O TTL deve cobrir a maior janela de retry esperada pelos clientes e pela infraestrutura. Para criação de recursos comuns, 24 horas pode ser uma referência operacional razoável, mas a escolha depende do contrato, do canal de integração e do impacto de uma duplicidade tardia.

Operações financeiras, auditáveis ou sujeitas a disputas podem exigir retenção maior de metadados. Nesse caso, separe a necessidade de deduplicação da necessidade de auditoria: talvez seja possível remover ou mascarar o corpo da resposta e manter identificadores, hashes e timestamps.

Faça a limpeza em lotes, com índices adequados sobre expiração, e acompanhe o crescimento da tabela. Métricas úteis incluem número de chaves criadas, taxa de replays, conflitos por payload divergente, registros presos em processamento e tempo até conclusão.

Teste os cenários que mais causam duplicidade

A cobertura precisa provar que existe apenas um efeito colateral, não apenas que a API retorna um status correto. Testes de integração são especialmente valiosos porque exercitam banco, transações e dependências relevantes.

  • Repita sequencialmente a mesma requisição com a mesma chave e valide o replay fiel.
  • Dispare chamadas paralelas com a mesma chave e confirme que apenas um recurso foi criado.
  • Reutilize uma chave com payload diferente e espere conflito.
  • Simule timeout no cliente depois que o servidor executa a operação.
  • Teste falhas antes e depois de integrações externas, incluindo a reconciliação.

Um cenário mínimo de concorrência dispara 20 requisições simultâneas com a mesma chave. O resultado esperado é uma única criação de pedido; as demais devem receber a resposta reapresentada ou uma indicação controlada de processamento, conforme o contrato.

Inclua ainda verificações para status, corpo e headers que o cliente precisa reutilizar. Uma resposta idempotente inconsistente pode levar o integrador a concluir, incorretamente, que uma nova operação é necessária.

Checklist para colocar idempotency keys em produção

Antes da liberação, revise se os endpoints críticos estão definidos, se o contrato orienta o cliente a reutilizar a chave nos retries e se a chave é obrigatória onde o risco justifica essa exigência.

  • Há um escopo consistente para cliente, rota e método.
  • Existe índice único no armazenamento durável.
  • O registro é criado antes do efeito colateral.
  • O hash normalizado bloqueia reuso com payload divergente.
  • Respostas concluídas são reproduzidas de forma consistente.
  • Estados pendentes têm timeout, diagnóstico e reconciliação.
  • TTL, limpeza e retenção foram aprovados.
  • Logs, métricas e alertas permitem investigar duplicidades e travamentos.
  • Testes de retry, timeout e concorrência fazem parte da entrega.

Idempotência não torna sistemas distribuídos magicamente simples, mas cria uma fronteira confiável entre a intenção do cliente e a execução da API. Ao tratá-la como contrato, persistência e operação — e não como um cache improvisado — sua equipe reduz incidentes difíceis de explicar e protege processos críticos.

Sua API processa pagamentos, pedidos ou integrações críticas? Estruture a idempotência antes que retries virem incidentes: fale com a Max Alex para avaliar a arquitetura e fortalecer a confiabilidade das suas integrações.

M

Max Alex

Criador de conteúdo apaixonado por tecnologia e inovação. Acompanhe nossos artigos para ficar por dentro das melhores estratégias digitais.

Continue lendo