Synchronisation incrémentale avec updated_since
Pour conserver une copie des données de Sursa dans votre propre système, inutile de tout relire à chaque fois. Les
listes des objets qui ont updated_at acceptent updated_since et ne renvoient que les objets modifiés à partir de
ce moment.
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"Avec updated_since, la liste est triée par updated_at croissant, puis par id, et le
curseur suit cet ordre. Vous lisez donc les modifications dans l’ordre où elles se sont
produites, et une limite de page ne les coupe jamais d’une façon qui en ferait perdre une.
updated_since est accepté par les listes suivantes :
| Liste | Ce qui compte comme modification |
|---|---|
GET /v1/cards, GET /v1/cards/count | updated_at de la fiche. |
GET /v1/groups | updated_at du groupe : son titre ou ses réglages. |
GET /v1/webhooks | updated_at du webhook : ses réglages et son secret, pas ses livraisons. |
GET /v1/jobs | updated_at du job : chaque changement de son statut. |
GET /v1/drafts | updated_at du brouillon. |
GET /v1/cards/{card_id}/threads | La dernière création ou modification du commentaire racine ou de l’une des réponses. Le fil arrive en entier. |
GET /v1/folders, GET /v1/collections/{name}/folders | updated_at du dossier. Les dossiers correspondants arrivent sous forme de liste à plat, voir ci-dessous. |
Les collections, les utilisateurs et les annonces n’ont pas de updated_at : leurs listes ne filtrent donc pas selon
ce champ. Elles sont courtes : relisez-les en entier à chaque exécution. L’heure doit comporter un décalage horaire,
comme Z ou +02:00 ; toute autre valeur est refusée, comme avec GET /v1/cards.
Avec updated_since, une arborescence de dossiers n’est plus une arborescence : folders de chaque collection contient
les dossiers modifiés sous forme de liste à plat, avec des children vides, et parent_id indique où se trouve chacun
d’eux. GET /v1/folders omet alors les collections sans dossier modifié.
Une boucle de synchronisation
- Lors de la première exécution, lisez la liste entière sans
updated_sinceet retenez le moment où l’exécution a commencé. - À chaque exécution suivante, passez ce moment comme
updated_since, moins une petite marge, par exemple une minute, et retenez la nouvelle heure de début. - Écrivez chaque objet dans votre stockage selon son
id, en remplaçant la copie précédente. Les objets qui apparaissent deux fois à cause de la marge sont simplement réécrits. - Demandez chaque page suivante avec le curseur et le même
updated_since. Un curseur ne fonctionne qu’avec les filtres de la première page : sans eux, la requête renvoie400avec le codeapi.cursor_invalid.
En utilisant l’heure de début de l’exécution, et non l’heure de fin, vous êtes sûr qu’une modification faite pendant l’exécution sera prise en compte par la suivante.
GET /v1/cards renvoie un tableau JSON : sa page suivante est donc indiquée dans l’en-tête X-Next-Cursor (voir
Listes qui renvoient un tableau) :
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
}Suppressions
Une liste ne renvoie que les objets qui existent : elle ne peut pas vous signaler qu’un objet a été supprimé. Prenez les suppressions dans le flux d’événements :
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"La lecture du flux exige une clé dotée du rôle admin et de la portée webhooks:manage. Les événements sont conservés
30 jours. Si votre synchronisation n’a pas tourné depuis plus longtemps, relisez la liste complète et retirez de votre
stockage chaque objet qui n’y figure plus.
Exporter vers un entrepôt de données réunit les listes, updated_since et le
flux d’événements dans un seul job.