Idempotency-Key
O cenário que tira o sono em fiscal: timeout no meio do request. Você manda POST /v1/nfce, network cai, retry — agora pode ter emitido duas notas pro mesmo pedido.
A solução Stripe-style: você manda um identificador único do seu lado no header Idempotency-Key. Se o gateway
já viu essa chave em < 24h, devolve a mesma resposta que devolveu antes — sem reprocessar nada.
Como usar
curl -X POST https://api.zfiscoo.zek.app.br/v1/nfce \
-H "Authorization: Bearer fk_live_..." \
-H "Idempotency-Key: pedido-2026-001" \
-d '{ ... }'Primeira chamada: processa normal. Retorna 201 Created (ou 202 Accepted).
Segunda chamada (mesma key, mesmo body): devolve a mesma resposta + header Idempotency-Replay: true.
Em que endpoints
Em todo POST/PUT/PATCH mutativo (17 endpoints). Os principais:
POST /v1/nfce,POST /v1/nfe,POST /v1/nfsePOST /v1/nfce/:id/cancel,POST /v1/nfe/:id/cancel,POST /v1/nfse/:id/cancelPOST /v1/issuers,POST /v1/issuers/:id/csc,POST /v1/issuers/:id/inutilizationPOST /v1/webhooks,POST /v1/applications(rotação de API key)
O que conta como “mesma chave”
Comparação tripla:
- Idempotency-Key (header)
- Body hash (SHA-256 do JSON do request)
- Path (rota HTTP)
Se você reenviar a mesma key com body diferente, recebe 422 idempotency_conflict:
{
"error": "idempotency_conflict",
"message": "Idempotency-Key 'pedido-001' já foi usado neste endpoint com body diferente. Use uma nova chave ou mantenha o body idêntico."
}Isso impede bug clássico de “reusar chave por engano com payload novo” — onde o cliente pensa que tá emitindo nota nova mas o gateway devolve a antiga.
TTL
Chaves expiram após 24h. Depois disso, a mesma chave reativa um novo processamento.
Boas práticas de chave
✅ Bom
// UUID por operação de negócio (não por request HTTP)
const idemKey = `nfce:${pedidoId}`;
// Ou hash determinístico de campos imutáveis
const idemKey = crypto.createHash('sha256')
.update(`${userId}:${pedidoId}:${amount}`)
.digest('hex')
.slice(0, 32);
// UUID v4 random por intenção de criar nota
const idemKey = crypto.randomUUID();Detectando replay no client
O header de resposta indica:
HTTP/1.1 201 Created
Idempotency-Replay: true
Content-Type: application/json
{ "id": "nfce_...", "status": "processing" }Útil pra logar / contar quantos retries seu sistema teve.
Não precisa usar Idempotency-Key em GET / DELETE — esses são naturalmente idempotentes pela spec HTTP. O gateway ignora o header se você mandar em GET.
Limite de tamanho
A chave precisa ter entre 8 e 256 caracteres. Recomendamos UUID v4 (36 chars) ou hash SHA-256 truncado (32 chars).