Sincronizare incrementală cu updated_since
Pentru a păstra o copie a datelor din Sursa în propriul sistem, nu trebuie să citiți totul de fiecare dată. Listele
obiectelor care au updated_at acceptă updated_since și returnează doar obiectele modificate în acel moment sau după
el.
curl -G https://api.sursa.com/v1/cards \
-H "Authorization: Bearer $SURSA_API_KEY" \
--data-urlencode "updated_since=2026-10-23T00:00:00Z" \
--data-urlencode "limit=200"Cu updated_since, lista este sortată crescător după updated_at, apoi după id, iar cursorul
continuă în aceeași ordine. Astfel citiți modificările în ordinea în care s-au produs, iar granița dintre pagini nu le
desparte niciodată în așa fel încât una să se piardă.
updated_since este acceptat de aceste liste:
| Listă | Ce se consideră o modificare |
|---|---|
GET /v1/cards, GET /v1/cards/count | updated_at al fișei. |
GET /v1/groups | updated_at al grupului: titlul sau setările lui. |
GET /v1/webhooks | updated_at al webhookului: setările și secretul lui, nu livrările lui. |
GET /v1/jobs | updated_at al jobului: fiecare schimbare a stării lui. |
GET /v1/drafts | updated_at al schiței. |
GET /v1/cards/{card_id}/threads | Cea mai recentă creare sau modificare a comentariului rădăcină ori a unui răspuns. Firul vine complet. |
GET /v1/folders, GET /v1/collections/{name}/folders | updated_at al dosarului. Dosarele potrivite vin ca listă simplă, vedeți mai jos. |
Colecțiile, utilizatorii și anunțurile nu au updated_at, așa că listele lor nu filtrează după el: sunt scurte, deci
citiți-le integral la fiecare rulare. Momentul trebuie să aibă decalajul fusului orar, de exemplu Z sau +02:00;
orice altă valoare este refuzată, ca la GET /v1/cards.
Cu updated_since, un arbore de dosare nu mai este arbore: folders din fiecare colecție conține dosarele modificate
ca listă simplă, cu children goale, iar parent_id arată unde se află fiecare. GET /v1/folders
omite în acest caz colecțiile fără dosare modificate.
O buclă de sincronizare
- La prima rulare, citiți întreaga listă fără
updated_sinceși rețineți momentul în care rularea a început. - La fiecare rulare următoare, transmiteți momentul reținut ca
updated_since, minus o mică marjă, de exemplu un minut, și rețineți noul moment de început. - Scrieți fiecare obiect în spațiul de stocare după
id-ul lui, înlocuind copia anterioară. Obiectele care apar de două ori din cauza marjei sunt pur și simplu scrise din nou. - Cereți fiecare pagină următoare cu cursorul și același
updated_since. Un cursor funcționează doar cu filtrele primei pagini: fără ele, cererea returnează400cu codulapi.cursor_invalid.
Folosind momentul de început al rulării, nu pe cel de sfârșit, vă asigurați că o modificare făcută în timpul rulării este preluată de rularea următoare.
GET /v1/cards returnează un tablou JSON, așa că pagina următoare vine în antetul X-Next-Cursor
(vedeți Liste care returnează un tablou):
const BASE = "https://api.sursa.com";
const headers = { Authorization: `Bearer ${process.env.SURSA_API_KEY}` };
async function syncCards(since, saveCard) {
const startedAt = new Date();
const params = new URLSearchParams({ limit: "200" });
if (since) params.set("updated_since", new Date(since.getTime() - 60_000).toISOString());
let query = params.toString();
while (query) {
const response = await fetch(`${BASE}/v1/cards?${query}`, { headers });
if (!response.ok) throw new Error(`HTTP ${response.status}: ${await response.text()}`);
for (const card of await response.json()) await saveCard(card); // write into your store by card.id
const cursor = response.headers.get("X-Next-Cursor");
if (cursor) params.set("cursor", cursor); // keep updated_since: the cursor needs the same filters
query = cursor ? params.toString() : "";
}
return startedAt; // pass it as `since` next time
}Ștergeri
O listă returnează doar obiectele care există, așa că nu vă poate spune că ceva a fost șters. Preluați ștergerile din fluxul de evenimente:
curl -G https://api.sursa.com/v1/webhook-events \
-H "Authorization: Bearer $SURSA_API_KEY" \
--data-urlencode "type=card.deleted" \
--data-urlencode "created_since=2026-10-23T00:00:00Z"Citirea fluxului necesită o cheie cu rolul admin și domeniul webhooks:manage. Evenimentele se păstrează 30 de
zile. Dacă sincronizarea nu a rulat mai mult de atât, citiți din nou lista completă
și eliminați din spațiul de stocare fiecare obiect care nu mai este în ea.
Exportul într-un depozit de date reunește listele, updated_since și
fluxul de evenimente într-un singur job.