Conceitos
Sincronização incremental
Como manter o seu sistema igual ao Mucanda pedindo só o que mudou: alteradoDesde e os webhooks.
Para ter no seu sistema uma cópia dos clientes, fornecedores e artigos, não repita a listagem inteira de cada vez: faça uma carga inicial e depois peça só o que mudou desde a última sincronização. Para os documentos, use o período (dataInicio e dataFim).
| Onde | Como |
|---|---|
GET /api/clientes, /api/fornecedores, /api/produtos | Acrescente alteradoDesde (data e hora ISO 8601, em UTC: 2026-10-16T09:15:00Z). Devolve o que foi criado ou alterado desde esse instante, inclusive, por ordem de alteração. |
| Cada item | Traz alteradoEmUtc: a data da última alteração. Guarde a mais recente que viu. |
| Clientes e fornecedores eliminados | Só aparecem com alteradoDesde, com eliminado: true, para os retirar do seu lado. Sem alteradoDesde nunca aparecem. |
| Artigos desactivados | Aparecem sempre com alteradoDesde (com activo: false), mesmo que peça apenasActivos=true. |
| Paginação | Igual à das outras listagens: tamanho e cursor (ver Paginação). O cursor desta listagem leva a data; não o reutilize com outro alteradoDesde. |
#O ciclo certo
- Carga inicial: percorra a listagem normal, sem
alteradoDesde, e guarde o instante em que começou (não o do fim). - Cada sincronização: peça com
alteradoDesdeigual ao instante guardado menos 5 minutos (uma pequena folga: uma gravação que estava a decorrer quando a anterior terminou pode ter a data um pouco antes). Percorra todas as páginas. - Aplique cada item pelo seu
id(criar se não existir, actualizar se existir, retirar seeliminado): é seguro repetir o mesmo item, e a folga de 5 minutos traz alguns repetidos de propósito. - No fim, guarde o instante em que começou esta sincronização para a próxima.
async function sincronizarClientes(ultimaSincronizacao) {
const inicio = new Date()
const desde = new Date(ultimaSincronizacao.getTime() - 5 * 60 * 1000).toISOString()
let cursor = null
do {
const url = new URL('https://<endereço-da-API>/api/clientes')
url.searchParams.set('alteradoDesde', desde)
url.searchParams.set('tamanho', '200')
if (cursor) url.searchParams.set('cursor', cursor)
const resposta = await fetch(url, { headers: { 'X-Api-Key': process.env.MUCANDA_API_KEY } })
if (!resposta.ok) throw new Error(`Erro ${resposta.status}`)
const pagina = await resposta.json()
for (const c of pagina.itens) {
if (c.eliminado) await removerCliente(c.id)
else await gravarCliente(c) // criar ou actualizar pelo id
}
cursor = pagina.itens.length === 0 ? null : pagina.proximoCursor
} while (cursor)
return inicio // guarde-o como a próxima «última sincronização»
}