Preskočiť na obsah
Sursa Developers

Prírastková synchronizácia s updated_since

Ak chcete mať kópiu údajov Sursy vo vlastnom systéme, nemusíte zakaždým čítať všetko. Zoznamy objektov, ktoré majú updated_at, prijímajú updated_since a vracajú len objekty, ktoré sa zmenili v danom okamihu alebo neskôr.

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"

S updated_since je zoznam zoradený vzostupne podľa updated_at, potom podľa id, a kurzor pokračuje v tomto poradí. Zmeny teda čítate v poradí, v akom nastali, a hranica stránky ich nikdy nerozdelí tak, aby sa niektorá stratila.

updated_since prijímajú tieto zoznamy:

ZoznamČo sa počíta ako zmena
GET /v1/cards, GET /v1/cards/countupdated_at karty.
GET /v1/groupsupdated_at skupiny: jej názov alebo nastavenia.
GET /v1/webhooksupdated_at webhooku: jeho nastavenia a tajný kľúč, nie jeho doručenia.
GET /v1/jobsupdated_at úlohy: každá zmena jej stavu.
GET /v1/draftsupdated_at návrhu.
GET /v1/cards/{card_id}/threadsPosledné vytvorenie alebo úprava koreňového komentára alebo ktorejkoľvek odpovede. Vlákno príde celé.
GET /v1/folders, GET /v1/collections/{name}/foldersupdated_at priečinka. Vyhovujúce priečinky prídu ako plochý zoznam, pozri nižšie.

Kolekcie, používatelia a oznámenia nemajú updated_at, preto ich zoznamy podľa neho nefiltrujú: sú krátke, takže ich pri každom behu čítajte celé. Čas musí obsahovať posun časového pásma, napríklad Z alebo +02:00; každá iná hodnota sa odmietne, rovnako ako pri GET /v1/cards.

S updated_since už strom priečinkov nie je stromom: folders každej kolekcie obsahuje zmenené priečinky ako plochý zoznam s prázdnym children a parent_id hovorí, kde každý z nich leží. GET /v1/folders potom vynechá kolekcie bez zmenených priečinkov.

Slučka synchronizácie

  1. Pri prvom behu načítajte celý zoznam bez updated_since a zapamätajte si okamih, keď sa beh začal.
  2. Pri každom ďalšom behu odošlite zapamätaný okamih ako updated_since mínus malá rezerva, napríklad jedna minúta, a zapamätajte si nový čas začiatku.
  3. Každý objekt zapíšte do svojho úložiska podľa jeho id a nahraďte ním predchádzajúcu kópiu. Objekty, ktoré pre rezervu prídu dvakrát, sa jednoducho zapíšu znova.
  4. Každú ďalšiu stránku si vyžiadajte s kurzorom a s tým istým updated_since. Kurzor funguje len s filtrami prvej stránky: bez nich požiadavka vráti 400 s kódom api.cursor_invalid.

Vďaka času začiatku behu, nie času jeho skončenia, zachytí zmenu urobenú počas behu ten nasledujúci.

GET /v1/cards vracia pole JSON, preto jeho ďalšia stránka prichádza v hlavičke X-Next-Cursor (pozri Zoznamy, ktoré vracajú pole):

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
}

Vymazania

Zoznam vracia len existujúce objekty, takže vám nemôže povedať, že sa niečo vymazalo. Vymazania zistíte z kanála udalostí:

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"

Čítanie kanála vyžaduje kľúč s rolou admin a rozsahom webhooks:manage. Udalosti sa uchovávajú 30 dní. Ak vaša synchronizácia nebežala dlhšie, načítajte znova celý zoznam a zo svojho úložiska odstráňte každý objekt, ktorý v ňom už nie je.

Export do dátového skladu spája zoznamy, updated_since a kanál udalostí do jednej úlohy.