Imagine que um cliente clica em “pagar”. A requisição sai do celular dele, atravessa uma rede de celular instável, e… nada. A tela fica girando. Ele não sabe se a cobrança passou ou não. O que ele faz? Clica de novo. Claro que clica.
Se o seu backend não estiver preparado para isso, você acabou de cobrar duas vezes a mesma pessoa. E esse é, em uma frase, o problema que a idempotência resolve.
O que idempotência quer dizer, sem o palavrão
Uma operação é idempotente quando executá-la uma vez ou várias vezes dá exatamente o mesmo resultado. Apertar o botão do elevador dez vezes não faz ele chegar mais rápido — ele já foi chamado na primeira. Isso é idempotência no mundo real.
No HTTP, alguns métodos já são idempotentes por definição. Um GET não muda nada. Um PUT que define o estado completo de um recurso pode ser repetido à vontade — o resultado final é o mesmo. O problema mora no POST, que normalmente cria algo novo a cada chamada. Repetir um POST de pagamento é repetir a cobrança.
Por que “é só não repetir a requisição” não funciona
A tentação é dizer: “o cliente que não clique duas vezes”. Mas a repetição raramente é culpa do usuário. Ela é estrutural. A rede caiu depois que o servidor processou, mas antes da resposta chegar. O cliente tem um retry automático. Um balanceador reenviou a requisição. Uma fila entregou a mesma mensagem duas vezes porque garante “pelo menos uma entrega”.
Em sistemas distribuídos, a duplicata não é exceção — é uma certeza estatística. Mais cedo ou mais tarde, a mesma operação vai chegar duas vezes. A pergunta não é “se”, é “o que meu sistema faz quando isso acontecer”.
A chave de idempotência, na prática
A solução mais usada — a mesma que gateways de pagamento como o Stripe adotam — é a chave de idempotência. O cliente gera um identificador único para aquela operação e manda junto num cabeçalho:
POST /pagamentos
Idempotency-Key: 3a1f9c8e-7b2d-4e5a-9f10-c2d4e6f8a0b1
{ "valor": 4990, "pedido_id": "P-2026-88" }
Do lado do servidor, a lógica é direta:
- Chegou uma requisição com uma chave. O servidor pergunta ao banco: “já vi essa chave antes?”.
- Se não: processa a operação, salva o resultado junto com a chave e responde.
- Se sim: não processa de novo. Apenas devolve a resposta que já foi guardada da primeira vez.
O cliente que clicou três vezes recebe três respostas idênticas e é cobrado uma vez só. Do ponto de vista dele, funcionou de primeira — que é exatamente a ilusão que a gente quer criar.
Os detalhes que separam o conceito da implementação sólida
O desenho acima é simples no papel e tem duas armadilhas na vida real.
A primeira é a corrida entre requisições duplicadas simultâneas. Se as duas cópias chegam quase ao mesmo tempo, ambas podem verificar “não existe” antes de qualquer uma gravar. A saída é deixar o banco resolver: uma restrição de unicidade na coluna da chave faz a segunda inserção falhar, e você trata esse erro como “operação já em andamento”.
CREATE UNIQUE INDEX idx_idem
ON operacoes (idempotency_key);
-- A segunda tentativa de INSERT com a mesma chave
-- estoura violação de unicidade. Você a converte
-- em "aguarde, já estamos processando".
A segunda é o tempo de vida da chave. Guardar chaves para sempre incha o banco. O comum é dar um prazo de validade — 24 horas costuma ser suficiente para cobrir retentativas, sem virar um depósito eterno.
Idempotência não é sobre impedir a duplicata de chegar. É sobre fazer com que, quando ela chegar, não cause estrago.
Idempotência também vive nos verbos HTTP
Vale entender por que o próprio HTTP já pensa nisso. Um PUT e um DELETE são idempotentes por definição: repetir “defina o nome como João” ou “apague o pedido 88” leva ao mesmo estado final, não importa quantas vezes você mande. Isso não é detalhe acadêmico — é o que permite a clientes, proxies e bibliotecas reenviarem essas requisições com segurança quando a rede engasga.
O mal-entendido comum é achar que idempotente quer dizer “retorna sempre a mesma resposta”. Não é bem isso. O segundo DELETE pode responder 404 em vez de 200, e tudo bem — o que importa é que o efeito no sistema é o mesmo: o pedido continua apagado. Foque no estado final, não no código de status.
É por isso que retentativas automáticas combinam naturalmente com esses verbos, e por que o POST precisa da chave de idempotência para entrar nessa festa com a mesma segurança.
Onde isso importa (e onde não)
Nem toda rota precisa disso. Um endpoint que atualiza o nome do usuário é naturalmente seguro de repetir — o estado final é o mesmo. O cuidado vale para operações que criam efeitos colaterais: cobranças, envio de e-mail, criação de pedidos, transferências, disparo de notificações.
Se você está construindo qualquer coisa que mexe com dinheiro ou dispara ações no mundo real, tratar idempotência deixa de ser refinamento e passa a ser requisito. É o tipo de detalhe invisível quando está certo e absolutamente visível quando falta — geralmente na forma de um cliente irritado perguntando por que foi cobrado duas vezes.



