Synchronizacja przyrostowa z updated_since
Aby utrzymywać kopię danych Sursy we własnym systemie, nie musisz za każdym razem odczytywać wszystkiego. Listy
obiektów, które mają updated_at, przyjmują updated_since i zwracają tylko obiekty zmienione w tym momencie lub
później.
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"Z updated_since lista jest sortowana rosnąco według updated_at, a następnie według id, a
kursor kontynuuje w tej kolejności. Dzięki temu odczytujesz zmiany w kolejności,
w jakiej nastąpiły, a granica strony nigdy nie dzieli ich tak, że któraś zostanie utracona.
updated_since przyjmują te listy:
| Lista | Co liczy się jako zmiana |
|---|---|
GET /v1/cards, GET /v1/cards/count | updated_at karty. |
GET /v1/groups | updated_at grupy: jej nazwa lub ustawienia. |
GET /v1/webhooks | updated_at webhooka: jego ustawienia i sekret, nie jego dostarczenia. |
GET /v1/jobs | updated_at zadania: każda zmiana jego statusu. |
GET /v1/drafts | updated_at szkicu. |
GET /v1/cards/{card_id}/threads | Ostatnie utworzenie lub edycja komentarza głównego albo dowolnej odpowiedzi. Wątek przychodzi w całości. |
GET /v1/folders, GET /v1/collections/{name}/folders | updated_at folderu. Pasujące foldery przychodzą jako płaska lista, zob. niżej. |
Kolekcje, użytkownicy i ogłoszenia nie mają updated_at, więc ich list nie można według niego filtrować: są krótkie,
dlatego odczytuj je w całości przy każdym uruchomieniu. Czas musi zawierać przesunięcie strefy czasowej, np. Z lub
+02:00; każda inna wartość jest odrzucana, tak jak w GET /v1/cards.
Z updated_since drzewo folderów przestaje być drzewem: folders każdej kolekcji zawiera zmienione foldery jako
płaską listę, z pustym children, a parent_id wskazuje, gdzie każdy z nich się znajduje.
GET /v1/folders pomija wtedy kolekcje bez zmienionych folderów.
Pętla synchronizacji
- Przy pierwszym uruchomieniu odczytaj całą listę bez
updated_sincei zapamiętaj moment, w którym uruchomienie się rozpoczęło. - Przy każdym kolejnym uruchomieniu przekaż zapamiętany moment jako
updated_since, pomniejszony o niewielki zapas, np. jedną minutę, i zapamiętaj nowy czas rozpoczęcia. - Zapisz każdy obiekt w swoim magazynie danych według jego
id, zastępując poprzednią kopię. Obiekty, które z powodu zapasu pojawią się dwukrotnie, zostaną po prostu zapisane ponownie. - Każdą następną stronę pobieraj z kursorem i tym samym
updated_since. Kursor działa tylko z filtrami pierwszej strony: bez nich żądanie zwraca400z kodemapi.cursor_invalid.
Użycie czasu rozpoczęcia uruchomienia, a nie czasu jego zakończenia, gwarantuje, że zmiana wprowadzona w trakcie uruchomienia zostanie uwzględniona przy następnym.
GET /v1/cards zwraca tablicę JSON, więc jej następna strona przychodzi w nagłówku X-Next-Cursor
(zob. Listy zwracające tablicę):
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
}Usunięcia
Lista zwraca tylko istniejące obiekty, więc nie może poinformować, że coś zostało usunięte. Usunięcia pobieraj z kanału zdarzeń:
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"Do odczytu kanału potrzebny jest klucz z rolą admin i zakresem webhooks:manage. Zdarzenia są przechowywane przez
30 dni. Jeśli Twoja synchronizacja nie była uruchamiana dłużej, odczytaj ponownie pełną listę i usuń ze swojego
magazynu danych każdy obiekt, którego już w niej nie ma.
Eksport do hurtowni danych łączy listy, updated_since i kanał zdarzeń
w jedno zadanie.