Boas práticas de consumo
Esta página reúne as melhores práticas para consumir a API do FazNota de forma estável, performática e que respeite os limites operacionais da plataforma.
1. Idempotência
Sempre envie numero-origem em emissões. Veja Idempotência.
{ "numero-origem": "PED-2026-00042", ... }Sem ele, retries em caso de timeout podem gerar duplicatas.
2. Polling responsável
Para consultar recibo após emissão:
- Intervalo mínimo: 2 segundos entre consultas do mesmo recibo.
- Use backoff exponencial: 2s → 3s → 4.5s → 7s → 10s → 15s → 23s → 30s (cap).
- Pare em status terminal (
004,010,900,999). - Timeout total razoável: 5 minutos. Após isso, acione o suporte.
async function polling(recibo, token) { const TERM = ['004', '010', '900', '999']; let wait = 2000; const start = Date.now();
while (Date.now() - start < 5 * 60_000) { const json = await mApi('GET', `/nfe/nota/${recibo}`, undefined, token); if (TERM.includes(json.status)) return json; await sleep(wait); wait = Math.min(wait * 1.5, 30_000); } throw new Error('Timeout');}3. Cache local
Dados que não mudam com frequência podem ser cacheados:
| Recurso | TTL recomendado |
|---|---|
| Listagem de clientes | 1 hora |
| Listagem de produtos | 1 hora |
Cliente individual (GET /clientes/{doc}) | 1 hora |
Produto individual (GET /produtos/{ref}) | 1 hora |
| NFes emitidas (consulta por recibo) | Sem cache durante emissão; cache longo após 004/010 |
Use Redis, Memcached ou cache em memória da aplicação.
4. Retry com backoff
Apenas em erros transitórios (HTTP 5xx, timeout, erro de rede). Não retente em
erros de validação (status: "999" com mensagem clara):
async function comRetry(fn, maxTentativas = 3) { for (let i = 1; i <= maxTentativas; i++) { try { return await fn(); } catch (err) { // Se for ApiError de validação, propaga (não retentar) if (err instanceof ApiError && err.payload?.status === '999') throw err; if (i === maxTentativas) throw err; await sleep(1000 * Math.pow(2, i - 1)); // 1s, 2s, 4s } }}5. Timeouts
Defina timeouts adequados no seu cliente HTTP:
| Operação | Timeout recomendado |
|---|---|
GET /health | 5 segundos |
Listagens (GET /nfe, etc.) | 30 segundos |
| Consulta por recibo | 15 segundos |
| Emissão (POST) | 30 segundos |
| Cadastros (POST/PUT clientes/produtos) | 30 segundos |
Timeout mínimo recomendado: 10 segundos. Menor que isso pode causar falsos timeouts.
6. Concorrência limitada
Evite enviar dezenas de requisições em paralelo no mesmo token:
// ❌ Ruimconst promises = clientes.map((c) => mApi('POST', '/clientes', c));await Promise.all(promises);
// ✅ Bom — limite de 5 simultâneasimport pLimit from 'p-limit';const limit = pLimit(5);await Promise.all(clientes.map((c) => limit(() => mApi('POST', '/clientes', c))));7. Headers de rate limit
Monitore os headers em cada resposta:
function checarRateLimit(res) { const remaining = parseInt(res.headers.get('x-ratelimit-remaining') || '0', 10); const reset = parseInt(res.headers.get('x-ratelimit-reset') || '0', 10);
if (remaining < 100) { console.warn(`Rate limit baixo: ${remaining} restantes. Reset em ${new Date(reset * 1000)}`); // Considere pausar emissões em massa }}8. Sincronização incremental
Evite percorrer todo o histórico a cada sincronização. Use marcadores:
- NFSe: filtro
dataInicial. - Outros: salve o último
idsincronizado e pare quando alcançá-lo.
Veja Sincronizar clientes e produtos para padrões completos.
9. Não polling sobre listas
Evite:
// ❌ Polling agressivo de listagenssetInterval(() => mApi('GET', '/nfe?page=1&page_size=100'), 5000);Prefira:
- Poll apenas o que precisa: o
reciboespecífico, não a lista inteira. - Use cache local com TTL de minutos para listagens.
10. Tratamento correto de erros
- HTTP 401/403/429: trate antes de qualquer lógica de domínio.
- HTTP 200 +
status: "999": erro de domínio. Vejadata.erro. - HTTP 200 +
status: "050": não é erro. É proteção; use o recibo retornado. - HTTP 200 +
status: "900": rejeição SEFAZ; vejadata.sefaz.mensagem.
Veja Tratamento de erros para detalhe.
11. Use X-Request-Id no suporte
Toda resposta traz meta.request_id e o header X-Request-Id com o mesmo valor.
Cite esse valor sempre que abrir ticket. Sem ele, a investigação fica difícil.
12. Versionamento da API
Hoje a API está em v3 (nfemyse-v3 no path). Mudanças significativas de contrato
serão anunciadas com antecedência via aviso prévio (ver Políticas operacionais).
Checklist de integração madura
- Token armazenado em variável de ambiente ou cofre de segredos
- Cliente HTTP centralizado com headers padrão e timeouts
-
numero-origemúnico em todas as emissões - Polling com intervalo mínimo de 2s e backoff exponencial
- Tratamento de
status: "999","900","050" - Cache local de clientes e produtos (TTL 1h)
- Concorrência limitada (≤5 simultâneas no mesmo token)
- Retry só em erros transitórios, com backoff
- Monitoramento de
X-RateLimit-Remaining - Log estruturado com
meta.request_idem cada operação - Health check externo apontando para
GET /health