Idempotência (numero-origem)
A API do FazNota usa o campo numero-origem (também aceito como numero_origem, legado)
para garantir idempotência nas emissões. Esse é um dos campos mais importantes
da integração — e o mais ignorado por quem está começando.
Por que importa
Imagine este cenário:
- Sua aplicação envia
POST /nfe/emissaocom um pedido. - A API do FazNota processa e emite a NFe com sucesso.
- Mas a resposta se perde na rede (timeout no cliente, falha intermediária).
- Sua aplicação interpreta como “falha” e tenta de novo com o mesmo pedido.
Sem idempotência, você teria duas NFes emitidas para o mesmo pedido. Com idempotência, a segunda chamada retorna o recibo original, sem duplicar a emissão.
Como funciona
Em qualquer emissão (NFe, NFCe, NFSe), envie no body:
{ "numero-origem": "PED-2026-00042", ...}Se você já enviou uma emissão com esse mesmo numero-origem (no escopo da sua
empresa), a API do FazNota retorna:
{ "status": "050", "descricao": "Já existe uma nota com este número de origem em nosso sistema.", "data": { "recibo": "rec_da_emissao_original" }, "meta": { ... }}Note que HTTP 200 + status: "050". Não é erro — é proteção.
Como escolher um bom numero-origem
| Estratégia | Exemplo | Comentário |
|---|---|---|
| ID do pedido no seu sistema | "PED-2026-00042" | Direto e legível. Recomendado. |
| UUID v4 | "550e8400-e29b-41d4-a716-446655440000" | Garantido único, mas opaco. |
| Composto | `“loja:42 | pedido:00042 |
Padrão de retry seguro
async function emitirComRetry(payload, token, maxTentativas = 3) { for (let tentativa = 1; tentativa <= maxTentativas; tentativa++) { try { const res = await fetch(`${BASE}/nfe/emissao`, { method: 'POST', headers: { Authorization: `Token ${token}`, 'Content-Type': 'application/json', }, body: JSON.stringify(payload), });
const json = await res.json();
// Sucesso ou duplicidade (idempotência funcionando) if (json.status === '001' || json.status === '050') { return json.data.recibo; }
// Erro de validação: não adianta retentar if (json.status === '999') { throw new Error(`Validação: ${json.data?.erro}`); } } catch (err) { if (tentativa === maxTentativas) throw err;
// Backoff exponencial: 1s, 2s, 4s await new Promise((r) => setTimeout(r, 1000 * Math.pow(2, tentativa - 1))); } }}O ponto crucial: o payload deve ter o mesmo numero-origem em todas as
tentativas. Se mudar, a idempotência se perde.
Escopo do numero-origem
- Por empresa. Cada empresa (cada Token) tem seu próprio espaço de
numero-origem. - Por tipo de documento. Vou poder usar
"PED-001"simultaneamente em NFe e em NFCe — são tabelas diferentes. (Recomenda-se evitar para clareza.) - Permanente. Uma vez registrado, o
numero-origempermanece reservado para aquela emissão.
E se eu não enviar numero-origem?
A emissão funciona normalmente, mas sem proteção contra duplicidade. Em caso de retry, você pode criar duas NFes para o mesmo pedido.
Formatos aceitos
A API aceita ambos os formatos do campo, por compatibilidade:
{ "numero-origem": "PED-001" } // ✅ Preferido (consistente com outros campos){ "numero_origem": "PED-001" } // ✅ Aceito (legado)Em novas integrações, prefira numero-origem (com hífen) — segue o padrão dos
demais campos da API.