Pular para o conteúdo

Idempotência

Uma requisição pode se perder no caminho: tempo esgotado na rede, nova tentativa automática do seu cliente, falha do servidor depois de gravar e antes de responder. Sem idempotência, repetir um POST /v1/sales cria duas vendas. O cabeçalho Idempotency-Key resolve isso: a Ligga API guarda a resposta da primeira chamada e devolve a mesma resposta nas repetições.

  1. Gere um identificador único para a operação, de 1 a 255 caracteres. UUID v4 ou ULID são boas escolhas.

  2. Envie esse identificador no cabeçalho Idempotency-Key da requisição.

  3. A API processa a primeira chamada e guarda a resposta por 24 horas, junto com a assinatura da requisição.

  4. Qualquer repetição com a mesma chave, dentro da janela, devolve a resposta guardada sem reprocessar nada. A resposta repetida carrega o cabeçalho Idempotent-Replay: true.

Terminal window
curl -X POST "$LIGGA_BASE/v1/sales" \
-H "Authorization: Bearer $LIGGA_API_KEY" \
-H "Idempotency-Key: $(uuidgen)" \
-H "Content-Type: application/json" \
-d '{
"customer_id": "c06d8705-f091-46e1-81bb-4a2cec656694",
"transaction_type": "sale",
"sale_date": "2026-05-18",
"items": []
}'

O cabeçalho é lido apenas em POST. Em GET, PATCH e DELETE ele é ignorado, porque essas operações já são idempotentes: repetir a mesma atualização parcial ou a mesma desativação leva ao mesmo estado final.

OperaçãoEnvie Idempotency-Key
POST /v1/salesSempre. Uma venda duplicada corrompe o financeiro da conta
POST /v1/customersSempre. Sem ela, uma nova tentativa cria o cliente duas vezes
POST /v1/expensesSempre
PATCH /v1/customers/{id}Não. O cabeçalho é ignorado
DELETE /v1/customers/{id}Não. O cabeçalho é ignorado
GET /v1/customersNão. Leitura não tem efeito colateral
import { randomUUID } from 'node:crypto';
const idempotencyKey = randomUUID();

Não derive a chave do corpo da requisição, por exemplo com um hash do JSON. Duas vendas legitimamente idênticas no mesmo dia produziriam a mesma chave, e a segunda voltaria como repetição da primeira em vez de ser criada.

SituaçãoResposta
Mesma chave, mesma requisição, dentro de 24 horasA resposta original, com Idempotent-Replay: true
Mesma chave, corpo diferente409 com type idempotency_conflict
Mesma chave, outro método ou outro caminho409 com type idempotency_conflict
Mesma chave, mais de 24 horas depoisTratada como requisição nova
Chave com mais de 255 caracteres422 com type validation

O 409 sinaliza um defeito no cliente: uma chave que deveria identificar uma operação está sendo reaproveitada em outra. Gere uma chave nova em vez de repetir a chamada.

A chave é guardada por chave de API. A assinatura comparada nas repetições cobre o método, o caminho e o corpo da requisição.

Duas chaves de API diferentes podem usar o mesmo valor de Idempotency-Key sem interferência: são operações independentes. Já a mesma chave de API reaproveitando o valor em outro endpoint recebe 409, porque a assinatura não bate com a guardada.

Perder o cabeçalho na nova tentativa. Se o seu cliente HTTP repete a requisição sozinho e monta os cabeçalhos de novo a cada tentativa, a garantia some. Confira a configuração da camada de repetição antes de confiar nela.

Gerar a chave dentro do laço. A chave precisa ser criada antes da primeira tentativa e permanecer a mesma em todas elas.

// Errado: cada tentativa vira uma operação nova
for (let i = 0; i < 3; i++) {
await fetch(url, { headers: { 'Idempotency-Key': randomUUID() } });
}
// Certo: uma chave para a operação inteira
const key = randomUUID();
for (let i = 0; i < 3; i++) {
await fetch(url, { headers: { 'Idempotency-Key': key } });
}

Guardar a chave só na memória do processo. Em um processo que pode reiniciar entre a tentativa e a repetição, grave a chave junto com o registro de origem, para reencontrá-la depois.