Um cliente clica em “pagar”, a requisição demora, ele clica de novo — e a cobrança sai duplicada. Esse é o problema que a idempotência resolve. Uma operação idempotente pode ser executada uma ou dez vezes com o mesmo resultado final, o que torna seguro repetir requisições que falharam no meio do caminho. Este guia explica quais métodos HTTP já são idempotentes, como implementar Idempotency-Key com Redis, e por que sistemas de pagamento como o Pix tratam o tema como requisito obrigatório.
O que é a idempotência em APIs?
Idempotência é a propriedade de uma operação que produz o mesmo resultado independentemente de quantas vezes for executada. Em APIs, significa que repetir a mesma requisição não cria efeitos colaterais adicionais: a segunda, terceira ou décima chamada retornam o mesmo estado da primeira, sem duplicar registros nem cobranças.
O conceito vem da matemática (uma função f é idempotente quando f(f(x)) = f(x)), mas o exemplo cotidiano ajuda mais: apertar o botão do elevador cinco vezes não o faz chegar mais rápido nem cinco vezes. O estado final (“elevador chamado”) é o mesmo.
Métodos HTTP idempotentes vs não idempotentes
A especificação HTTP já define quais métodos devem ser idempotentes:
| Método | Idempotente | Seguro (não altera estado) | Exemplo |
|---|---|---|---|
| GET | ✅ | ✅ | buscar um cadastro |
| HEAD | ✅ | ✅ | verificar se recurso existe |
| OPTIONS | ✅ | ✅ | preflight de CORS |
| PUT | ✅ | ❌ | substituir um cadastro inteiro |
| DELETE | ✅ | ❌ | remover um registro |
| POST | ❌ | ❌ | criar pedido, processar pagamento |
| PATCH | ❌* | ❌ | atualização parcial |
PUT é idempotente porque substitui o recurso pelo estado enviado: repetir a operação reescreve o mesmo estado. DELETE idem: apagar algo já apagado não muda nada, ainda que o status retornado mude de 200 pra 404.
Por que POST não é idempotente (e o caso do PATCH)
POST cria um recurso novo a cada chamada: dois POSTs de pedido geram dois pedidos. PATCH leva o asterisco porque depende do conteúdo: um patch “defina status como pago” é idempotente; um patch “incremente o saldo em 10” não é. Como a especificação não dá garantia, trate PATCH como não idempotente por padrão.
O problema real: timeout não significa falha
Em sistemas distribuídos, uma requisição que estoura o tempo limite tem três desfechos possíveis: nunca chegou ao servidor, chegou e falhou, ou chegou e foi processada com sucesso: só a resposta se perdeu. O cliente não tem como distinguir os três casos.
É por isso que retry sem idempotência é perigoso: se o terceiro caso aconteceu e o cliente reenvia o POST, a operação executa duas vezes. Backoff exponencial e circuit breaker controlam a frequência das tentativas, mas só a idempotência torna a repetição segura. Os dois andam juntos: retry define quando repetir; idempotência garante que repetir não causa estrago.
Estratégias para implementar idempotência em APIs de cadastro
Chave de idempotência (Idempotency key)
O padrão de mercado pra tornar POST idempotente é o header Idempotency-Key (objeto de uma especificação em andamento no IETF e adotado por Stripe, PayPal e outros). O fluxo:
- O cliente gera um UUID v4 e envia no header da requisição
- O servidor verifica se já processou essa chave
- Se não: processa, salva a resposta associada à chave e retorna
- Se sim: retorna a resposta salva, sem executar de novo
POST /v1/pagamentos HTTP/1.1
Idempotency-Key: 7f0c78e5-d51c-4634-b03b-2f770e8013dc
Content-Type: application/json
{ "valor": 14990, "cartao_token": "tok_abc123" }

Identificadores naturais de negócio
Nem sempre é preciso criar chave artificial. Se o domínio já tem identificador único (número do pedido, ID da transação no parceiro), use-o como chave de deduplicação com uma constraint UNIQUE no banco. A tentativa duplicada falha na inserção e o handler trata o conflito.
Fingerprint da requisição
Terceira opção: derivar a chave do próprio conteúdo, com hash do payload (SHA-256 do corpo + endpoint + usuário). Funciona pra deduplicar reenvios idênticos, mas tem armadilha: dois pedidos legítimos com o mesmo conteúdo (cliente compra o mesmo item duas vezes de propósito) seriam tratados como duplicata. Use só quando repetição idêntica for sempre erro.
Arquitetura de armazenamento para controle de idempotência em APIs
Redis: A escolha mais popular
O armazenamento das chaves precisa de escrita atômica (duas requisições simultâneas com a mesma chave não podem ambas “ganhar”) e expiração automática. Redis entrega os dois com SET NX EX:
async function processarComIdempotencia(chave, executar) {
// tenta registrar a chave; NX = só se não existir
const reservou = await redis.set(
`idem:${chave}`, 'PROCESSANDO', 'NX', 'EX', 86400
);
if (!reservou) {
const salvo = await redis.get(`idem:${chave}`);
if (salvo === 'PROCESSANDO') {
// outra requisição com a mesma chave está em andamento
throw new ConflictError(409, 'Requisição em processamento');
}
return JSON.parse(salvo); // resposta já calculada
}
const resposta = await executar();
await redis.set(`idem:${chave}`, JSON.stringify(resposta), 'EX', 86400);
return resposta;
}
O estado intermediário PROCESSANDO resolve a condição de corrida: a segunda requisição concorrente recebe 409 e o cliente tenta de novo em seguida, quando a resposta já estará salva.
Definindo o tempo de retenção
A chave não precisa viver pra sempre: basta cobrir a janela de retry do cliente. 24 horas é o padrão da maioria dos provedores de pagamento; operações com reconciliação lenta podem pedir 7 dias. TTL curto demais reabre a porta da duplicidade; longo demais incha o armazenamento sem benefício.
Tratamento de erros e cenários especiais em idempotência em APIs
Os três erros da especificação
- 400 Bad Request: a chave de idempotência está ausente quando o endpoint a exige, ou em formato inválido
- 422 Unprocessable Entity: a chave já foi usada com um payload diferente — o cliente está reutilizando chave indevidamente
- 409 Conflict: a requisição original com a mesma chave ainda está em processamento
O 422 merece atenção: comparar o fingerprint do payload com o da requisição original é o que impede um bug no cliente de receber a resposta de outra operação.
O problema do processamento parcial
E se o servidor falhar no meio do caminho, depois de cobrar o cartão mas antes de salvar o pedido? Salvar a resposta na chave de idempotência só no fim da transação garante que a repetição reexecute o fluxo inteiro. Por isso operações idempotentes devem embrulhar seus efeitos numa transação ou usar padrões como outbox: ou tudo aconteceu e a resposta está salva, ou nada valeu e o retry recomeça do zero.
Idempotência em pagamentos: Pix, cartões e Open Finance
Pagamento é o cenário onde duplicidade dói mais, e os padrões brasileiros já incorporam a proteção. No Pix, o txid identifica a cobrança de ponta a ponta: reenviar a criação com o mesmo txid não gera segunda cobrança. No Open Finance Brasil, a especificação de pagamentos exige o header x-idempotency-key nos POSTs de iniciação. Gateways como Stripe e provedores nacionais seguem o mesmo modelo de Idempotency-Key descrito acima.
A regra prática pra quem integra: gere a chave antes de iniciar o fluxo de pagamento, persista junto com o pedido e reutilize a mesma chave em todos os retries daquela operação. Chave nova a cada tentativa anula a proteção.
Idempotência em mensageria e filas
Filas como Kafka, SQS e RabbitMQ entregam mensagens com garantia at-least-once: pelo menos uma vez, o que inclui duas. Todo consumidor precisa ser idempotente: deduplique pelo ID da mensagem (mesma técnica do Redis acima) ou desenhe o processamento pra que repetir seja inofensivo, como gravações com chave natural única. O mesmo vale pra webhooks, que provedores reenviam quando não recebem confirmação.
Perguntas frequentes
O que é idempotência em APIs?
É a garantia de que repetir a mesma requisição produz o mesmo resultado, sem efeitos colaterais duplicados. Permite que clientes reenviem requisições após timeout ou erro de rede com segurança, sem risco de criar dois pedidos ou duas cobranças.
O que é uma chave de idempotência (Idempotency-Key)?
É um identificador único (geralmente UUID) que o cliente envia num header da requisição. O servidor usa a chave pra reconhecer repetições: a primeira chamada é processada e a resposta fica salva; as seguintes com a mesma chave recebem a resposta salva, sem reprocessar.
Quais métodos HTTP são idempotentes?
GET, HEAD, OPTIONS, PUT e DELETE são idempotentes por especificação. POST não é, e PATCH não tem garantia — depende da semântica da operação.
POST pode ser idempotente?
Pode, com implementação explícita: o padrão Idempotency-Key torna POSTs seguros pra retry. É assim que APIs de pagamento permitem reenviar a criação de uma cobrança sem duplicá-la.
Por que idempotência é importante em pagamentos e no Pix?
Porque a falha mais comum em pagamento é a resposta perdida: a cobrança foi feita, mas o cliente não soube. Sem idempotência, o retry cobra duas vezes. No Pix, o txid único da cobrança cumpre esse papel; no Open Finance, o header x-idempotency-key é obrigatório nos POSTs de iniciação de pagamento.
Conclusão
Idempotência é pré-requisito de qualquer API que processa operações com efeito colateral em rede não confiável. O caminho prático: aproveite a idempotência natural de PUT e DELETE, proteja os POSTs críticos com Idempotency-Key armazenada de forma atômica (Redis com SET NX e TTL de 24h), valide o fingerprint do payload pra detectar reuso indevido de chave e mantenha consumidores de fila e webhooks preparados pra mensagens repetidas. Com isso, retry deixa de ser risco e vira o que deveria ser: mecanismo de resiliência.


