Direct naar de inhoud
Sursa Developers

Incrementele synchronisatie met updated_since

Om een kopie van de gegevens van Sursa in je eigen systeem bij te houden, hoef je niet elke keer alles te lezen. De lijsten van objecten met updated_at accepteren updated_since en geven alleen de objecten terug die op of na dat moment zijn gewijzigd.

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"

Met updated_since wordt de lijst oplopend gesorteerd op updated_at en daarna op id, en de cursor gaat in die volgorde verder. Zo lees je de wijzigingen in de volgorde waarin ze plaatsvonden, en een paginagrens splitst ze nooit zo dat er een verloren gaat.

updated_since wordt geaccepteerd door deze lijsten:

LijstWat als wijziging telt
GET /v1/cards, GET /v1/cards/countupdated_at van de kaart.
GET /v1/groupsupdated_at van de groep: de titel of de instellingen ervan.
GET /v1/webhooksupdated_at van de webhook: de instellingen en het geheim ervan, niet de leveringen.
GET /v1/jobsupdated_at van de job: elke wijziging van de status ervan.
GET /v1/draftsupdated_at van het concept.
GET /v1/cards/{card_id}/threadsHet laatste moment waarop de eerste opmerking of een antwoord is gemaakt of bewerkt. De thread komt in zijn geheel mee.
GET /v1/folders, GET /v1/collections/{name}/foldersupdated_at van de map. De overeenkomende mappen komen als platte lijst, zie hieronder.

Collecties, gebruikers en aankondigingen hebben geen updated_at, dus hun lijsten filteren er niet op: ze zijn kort, lees ze daarom bij elke run in hun geheel. Het tijdstip moet een tijdzoneverschuiving hebben, zoals Z of +02:00; elke andere waarde wordt geweigerd, net als bij GET /v1/cards.

Met updated_since is een mappenboom geen boom meer: folders van elke collectie bevat de gewijzigde mappen als platte lijst, met lege children, en parent_id geeft aan waar elke map staat. GET /v1/folders laat dan de collecties zonder gewijzigde mappen weg.

Een synchronisatielus

  1. Lees bij de eerste run de hele lijst zonder updated_since en onthoud het moment waarop de run begon.
  2. Geef bij elke volgende run dat onthouden moment mee als updated_since, min een kleine marge van bijvoorbeeld één minuut, en onthoud het nieuwe begintijdstip.
  3. Schrijf elk object op basis van zijn id in je opslag en vervang daarbij de vorige kopie. Objecten die door de marge twee keer verschijnen, worden gewoon opnieuw geschreven.
  4. Vraag elke volgende pagina op met de cursor en dezelfde updated_since. Een cursor werkt alleen met de filters van de eerste pagina: zonder die filters geeft het request 400 met de code api.cursor_invalid.

Doordat je het begintijdstip van de run gebruikt en niet het moment waarop hij klaar was, pakt de volgende run ook een wijziging op die tijdens de lopende run is gemaakt.

GET /v1/cards geeft een JSON-array terug, dus de volgende pagina komt in de header X-Next-Cursor (zie Lijsten die een array teruggeven):

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
}

Verwijderingen

Een lijst geeft alleen objecten terug die bestaan, dus hij kan je niet vertellen dat er iets is verwijderd. Haal verwijderingen uit de eventfeed:

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"

Om de feed te lezen heb je een sleutel nodig met de rol admin en de scope webhooks:manage. Events worden 30 dagen bewaard. Heeft je synchronisatie langer dan dat niet gedraaid, lees dan de volledige lijst opnieuw en verwijder uit je opslag elk object dat er niet meer in staat.

Export naar een datawarehouse brengt lijsten, updated_since en de eventfeed samen in één proces.