Přejít na obsah
Sursa Developers

Přírůstková synchronizace s updated_since

Chcete-li ve svém systému udržovat kopii dat ze Sursy, nemusíte pokaždé číst všechno. Seznamy objektů, které mají updated_at, přijímají updated_since a vracejí jen objekty změněné v daném okamžiku nebo později.

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 seznam seřazený vzestupně podle updated_at a poté podle id a kurzor pokračuje v tomto pořadí. Změny tak čtete v pořadí, v jakém nastaly, a hranice stránky je nikdy nerozdělí tak, aby se některá ztratila.

updated_since přijímají tyto seznamy:

SeznamCo se počítá jako změna
GET /v1/cards, GET /v1/cards/countupdated_at karty.
GET /v1/groupsupdated_at skupiny: její název nebo nastavení.
GET /v1/webhooksupdated_at webhooku: jeho nastavení a tajný klíč, ne jeho doručení.
GET /v1/jobsupdated_at úlohy: každá změna jejího stavu.
GET /v1/draftsupdated_at konceptu.
GET /v1/cards/{card_id}/threadsPoslední vytvoření nebo úprava kořenového komentáře nebo kterékoli odpovědi. Vlákno přichází celé.
GET /v1/folders, GET /v1/collections/{name}/foldersupdated_at složky. Odpovídající složky přicházejí jako plochý seznam, viz níže.

Kolekce, uživatelé a oznámení updated_at nemají, proto jejich seznamy podle něj nefiltrují: jsou krátké, takže je při každém běhu přečtěte celé. Čas musí mít posun časového pásma, například Z nebo +02:00; jakoukoli jinou hodnotu API odmítne, stejně jako u GET /v1/cards.

S updated_since už strom složek není stromem: folders každé kolekce obsahuje změněné složky jako plochý seznam s prázdným children a parent_id udává, kde každá z nich leží. GET /v1/folders pak vynechá kolekce bez změněných složek.

Synchronizační smyčka

  1. Při prvním běhu přečtěte celý seznam bez updated_since a zapamatujte si okamžik, kdy běh začal.
  2. Při každém dalším běhu předejte zapamatovaný okamžik jako updated_since, zmenšený o malou rezervu, například o jednu minutu, a zapamatujte si nový čas začátku.
  3. Každý objekt zapište do svého úložiště podle jeho id a nahraďte jím předchozí kopii. Objekty, které se kvůli rezervě objeví dvakrát, se prostě zapíší znovu.
  4. Každou další stránku vyžádejte s kurzorem a se stejným updated_since. Kurzor funguje jen s filtry první stránky: bez nich požadavek vrátí 400 s kódem api.cursor_invalid.

Protože se použije čas začátku běhu, a ne čas jeho skončení, zachytí změnu provedenou během běhu ten další běh.

GET /v1/cards vrací pole JSON, takže jeho další stránka přichází v hlavičce X-Next-Cursor (viz Seznamy, které vracejí 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
}

Smazání

Seznam vrací jen existující objekty, takže vám nemůže sdělit, že bylo něco smazáno. Smazání převezměte z kanálu událostí:

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"

Čtení kanálu vyžaduje klíč s rolí admin a rozsahem webhooks:manage. Události se uchovávají 30 dní. Pokud vaše synchronizace neběžela déle, přečtěte znovu celý seznam a odstraňte ze svého úložiště každý objekt, který v něm už není.

Export do datového skladu spojuje seznamy, updated_since a kanál událostí do jedné úlohy.