Pular para o conteúdo

Sincronizar clientes e produtos

Quando você tem um sistema próprio (ERP, e-commerce) integrado ao FazNota, é comum precisar manter os cadastros sincronizados. Esta página mostra padrões eficientes para isso.

Quando sincronizar

CenárioRecomendação
Cadastro de cliente novo no seu sistemaPush imediato para o FazNota (POST)
Alteração de clientePush (PUT) sob demanda
Pull periódico (espelhar FazNota → seu sistema)A cada 1h ou diário, paginado
Inicial (primeira sincronização)Paginação completa, off-peak

Push sob demanda (sistema → FazNota)

A forma mais simples: cada operação no seu sistema dispara uma chamada ao FazNota.

// Pseudo-código
async function onClienteSalvo(cliente) {
if (cliente.isNew) {
await mApi('POST', '/clientes', toMyseFormat(cliente));
} else {
await mApi('PUT', `/clientes/${cliente.cpfCnpj}`, toMyseFormat(cliente));
}
}

Vantagens: simples, baixa latência. Desvantagem: se a chamada falhar, fica fora de sincronia até retry.

Pull com paginação completa (FazNota → sistema)

Para espelhar todos os clientes/produtos do FazNota no seu sistema:

async function sincronizarTodosClientes(token) {
const todos = [];
let pagina = 1;
const tamanho = 100;
while (true) {
const url = `${BASE}/clientes?page=${pagina}&page_size=${tamanho}`;
const res = await fetch(url, {
headers: { Authorization: `Token ${token}` },
});
const json = await res.json();
if (json.status !== '005' || !json.data) break;
if (json.data.length === 0) break;
todos.push(...json.data);
if (json.data.length < tamanho) break;
pagina++;
// Respeitando rate limit
await new Promise((r) => setTimeout(r, 200));
}
return todos;
}

Pull incremental (apenas o que mudou)

Hoje o FazNota oferece o filtro dataInicial em NFSe. Para outros recursos (clientes, produtos, NFe, NFCe), use o id como marcador:

async function sincronizarNovosClientes(token, ultimoIdSincronizado) {
// Pega a primeira página (mais recentes vêm primeiro)
const res = await fetch(`${BASE}/clientes?page=1&page_size=100`, {
headers: { Authorization: `Token ${token}` },
});
const json = await res.json();
if (json.status !== '005') return [];
// Para nos clientes que já vimos
const novos = [];
for (const c of json.data) {
if (c.id <= ultimoIdSincronizado) break;
novos.push(c);
}
return novos;
}

Sincronização de NFSes (com dataInicial)

async function sincronizarNFSes(token, dataInicial) {
const todos = [];
let pagina = 1;
const tamanho = 50;
while (true) {
const url = `${BASE}/nfse?dataInicial=${dataInicial}&page=${pagina}&page_size=${tamanho}`;
const res = await fetch(url, {
headers: { Authorization: `Token ${token}` },
});
const json = await res.json();
if (!json.data || json.data.length === 0) break;
todos.push(...json.data);
if (json.data.length < tamanho) break;
pagina++;
await new Promise((r) => setTimeout(r, 200));
}
return todos;
}
// Uso:
const ontem = '2026-05-12';
const nfses = await sincronizarNFSes(token, ontem);

Boas práticas

  1. Use cache local. Não consulte o FazNota a cada operação interna se você já tem os dados em cache. Use TTL razoável (1h para clientes, 15 min para notas em emissão).

  2. Backoff exponencial em retries. Se uma sincronização falhar, espere 1s, 2s, 4s antes de tentar novamente.

  3. Limite a concorrência. Não faça 100 chamadas simultâneas — use no máximo 5–10 em paralelo.

  4. Monitore rate limit. Olhe X-RateLimit-Remaining em cada resposta. Se ficar baixo, reduza o ritmo.

  5. Idempotência em escrita. Use numero-origem único em emissões, e em POST de clientes/produtos use upsert (POST seguido de PUT se falhar por duplicidade).

Anti-padrões

❌ Evite✅ Prefira
setInterval consultando a cada 1 segundoPolling com intervalo de 30s+ ou eventos manuais
for (i=1; i<99999; i++) fetch(...) em paraleloLoop sequencial com await e pausa entre páginas
Consultar lista completa toda vezCache local + sincronização incremental
Esquecer rate limit headersMonitorar X-RateLimit-Remaining