Idempotência
A API suporta idempotência para repetir solicitações com segurança, sem executar a mesma operação duas vezes. Útil quando uma chamada é interrompida em trânsito e você não recebe resposta — por exemplo, uma requisição para criar uma assinatura que cai por erro de rede pode ser repetida com a mesma chave, garantindo que apenas uma assinatura seja criada.
Como usar
Envie o cabeçalho X-Idempotency-Key: <chave> em qualquer requisição POST, PUT ou PATCH. A chave é livre, gerada pelo seu lado. Recomendamos UUID v4 ou outra string aleatória com entropia suficiente para evitar colisões.
curl -i \
-H "Authorization: Bearer $KOBANA_TOKEN" \
-H 'Content-Type: application/json' \
-H 'X-Idempotency-Key: 8c0f5d6e-3f8b-4cb5-9a47-d8f5b15e9b21' \
-H 'User-Agent: Kevin Mitnick <kmitnick@kobana.com.br>' \
-d '{
"subscription": {
"billing_account_id": "ba_01HXY123",
"plan_id": "plan_01HPRO",
"billing_cycle": "monthly"
}
}' \
-X POST 'https://api.billing.sandbox.kobana.com.br/v1/subscriptions'
Como funciona
Quando o servidor recebe uma requisição com X-Idempotency-Key:
- Reserva a chave atomicamente, escopada à sua organização. Duas organizações diferentes podem usar a mesma chave sem conflito.
- Calcula a impressão digital da requisição — SHA-256 de
método + caminho + corpo bruto. Esse hash é guardado junto com a chave. - Executa o handler. Se ele retornar uma resposta, o servidor grava
status_code, corpo e cabeçalhos relevantes vinculados à chave. - Marca a chave como completa. Qualquer nova requisição com a mesma chave dentro de 24 horas recebe a resposta original verbatim — mesmo
status_code, mesmo corpo, mesmos cabeçalhos — acrescida do cabeçalhoX-Idempotent-Replay: truepara indicar que se trata de uma reexecução.
A camada salva o resultado independentemente de ter sido sucesso ou falha. Retries com a mesma chave retornam o mesmo resultado, incluindo erros 5xx.
Limites
- Tamanho máximo da chave: 255 caracteres.
- Retenção: chaves expiram automaticamente 24 horas após a criação. Após expirar, uma nova solicitação com a mesma chave gera um novo resultado.
- Escopo: por organização. Uma chave usada em uma organização não interfere em outra.
- Caracteres aceitos: qualquer string UTF-8 imprimível.
Quando o resultado não é salvo
A camada só grava o resultado quando o handler começou a executar. Não há registro nos seguintes casos — é seguro reenviar a requisição:
- A chave está vazia ou passou de 255 caracteres → resposta
400 bad_request. - O parser do envelope da API rejeita a requisição antes do handler (por exemplo, JSON inválido ou autenticação ausente).
- O handler lança uma exceção durante a execução — a reserva é liberada para que o próximo retry possa rodar limpo.
- Outra requisição com a mesma chave está em execução simultânea → resposta
409 conflictcomdetails.reason = "idempotency_request_in_progress".
Conflitos
Se a mesma chave for reutilizada com uma requisição diferente (qualquer mudança em método, caminho ou corpo), a API responde 409 conflict com details.reason = "idempotency_key_reused". Isso protege contra reuso acidental — por exemplo, persistir a chave junto com a operação no seu lado e tentar criar dois recursos diferentes com o mesmo identificador.
Resposta de erro
{
"error": {
"code": "conflict",
"message": "X-Idempotency-Key was already used with different request parameters. Reuse the original parameters or generate a new key.",
"details": { "reason": "idempotency_key_reused" }
}
}
Outras respostas possíveis
| Cenário | Status | error.code | details.reason |
|---|---|---|---|
| Outra requisição com a mesma chave em execução | 409 | conflict | idempotency_request_in_progress |
| Mesma chave reutilizada com payload diferente | 409 | conflict | idempotency_key_reused |
| Chave vazia ou maior que 255 caracteres | 400 | bad_request | invalid_idempotency_key |
Métodos aceitos
| Método | Aceita X-Idempotency-Key? |
|---|---|
POST | ✅ Sim |
PUT | ✅ Sim |
PATCH | ✅ Sim |
GET | ❌ Não (já é idempotente por definição) |
DELETE | ❌ Não (já é idempotente por definição) |
Enviar a chave em GET ou DELETE não tem efeito — a API processa a requisição normalmente, sem gravar registro.
Identificando uma reexecução
Toda resposta servida a partir do registro carrega o cabeçalho:
X-Idempotent-Replay: true
Você pode usar esse cabeçalho para distinguir, no seu lado, entre a primeira execução e um retry replicado pelo servidor.
Boas práticas
- Uma chave por operação lógica. Não reutilize a mesma chave para criar dois recursos diferentes — você receberá
409 conflict. - Persista a chave junto com o estado da operação no seu lado, para que o retry depois de crash ou reinício use a mesma chave.
- Combine com backoff exponencial ao receber
5xxou timeout — a chave garante que o retry não duplica o recurso. Como o resultado é gravado também para falhas, você pode parar de tentar assim que vier o status code esperado. - Limpe a chave depois de 24 horas. Não há ganho em mantê-la no seu lado após esse prazo: o servidor já descartou o registro.
- Não envie a chave em métodos que não a aceitam. Em
GET/DELETEela é silenciosamente ignorada — preferimos que o cliente nem a inclua para deixar claro o que é idempotente por contrato e o que depende da chave.