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).

OndeComo
GET /api/clientes, /api/fornecedores, /api/produtosAcrescente 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 itemTraz alteradoEmUtc: a data da última alteração. Guarde a mais recente que viu.
Clientes e fornecedores eliminadosSó aparecem com alteradoDesde, com eliminado: true, para os retirar do seu lado. Sem alteradoDesde nunca aparecem.
Artigos desactivadosAparecem sempre com alteradoDesde (com activo: false), mesmo que peça apenasActivos=true.
PaginaçãoIgual à 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 alteradoDesde igual 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 se eliminado): é 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.
JavaScript
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»
}