Przejdź do treści
Sursa Developers

Stronicowanie

Listy Sursa API są stronicowane za pomocą kursora: prosisz o maksymalnie limit elementów, a odpowiedź mówi, jak pobrać następną stronę. Nigdy nie obliczasz przesunięć, a elementy nie powtarzają się ani nie znikają między stronami, gdy dane w międzyczasie się zmieniają.

ParametrWartość
limitLiczba elementów na stronę, zwykle od 1 do 200. Nowe listy domyślnie zwracają 50 elementów; dokumentacja podaje zakres i wartość domyślną każdej listy.
cursorKursor z poprzedniej strony. Pomiń go przy pierwszej stronie.

Lista zwraca następny kursor na jeden z dwóch sposobów, zależnie od struktury swojej odpowiedzi. Strona każdej operacji w dokumentacji API pokazuje, którego sposobu ta operacja używa.

Listy w kopercie data

Listy dodane dla publicznego API, np. kanał zdarzeń, zwracają obiekt z elementami w data:

curl "https://api.sursa.com/v1/webhook-events?limit=2" \
  -H "Authorization: Bearer $SURSA_API_KEY"
{
  "data": [
    {"id": "evt_8a1f…", "type": "card.published", "created_at": "2026-10-24T10:00:00Z"},
    {"id": "evt_8a20…", "type": "card.updated", "created_at": "2026-10-24T10:00:03Z"}
  ],
  "next_cursor": "eyJ2IjoxLCJrIjpbMTA0Ml19",
  "has_more": true
}

Gdy has_more ma wartość true, poproś o następną stronę, ustawiając cursor na next_cursor i używając tych samych filtrów:

curl "https://api.sursa.com/v1/webhook-events?limit=2&cursor=eyJ2IjoxLCJrIjpbMTA0Ml19" \
  -H "Authorization: Bearer $SURSA_API_KEY"

Listy, które istniały przed wprowadzeniem kursorów i zwracają obiekt, zachowują własną kopertę (np. {"items": […], "total": 120}). Otrzymują next_cursor i has_more w tym samym obiekcie; elementy pozostają tam, gdzie były.

Listy zwracające tablicę

Kilka list zwraca samą tablicę JSON, np. GET /v1/collections. Struktura ich odpowiedzi nie może się zmienić, dlatego następna strona przychodzi w nagłówkach:

curl -i "https://api.sursa.com/v1/collections?limit=50" \
  -H "Authorization: Bearer $SURSA_API_KEY"
HTTP/1.1 200 OK
Link: <https://api.example.com/v1/collections?limit=50&cursor=eyJ2IjoxLCJrIjpbNTBdfQ>; rel="next"
X-Next-Cursor: eyJ2IjoxLCJrIjpbNTBdfQ

[{"id": 1, "name": "support", …}, …]
  • Link z rel="next" to pełny adres następnej strony; X-Next-Cursor to ten sam kursor osobno.
  • Brak Link z rel="next" i brak X-Next-Cursor oznacza, że to ostatnia strona.
  • Bez limit te listy zwracają wszystkie elementy w jednej odpowiedzi, tak jak zawsze. Przekaż limit, aby je stronicować; kursor zapamiętuje rozmiar strony, więc następne żądanie może pominąć limit.
  • Wyjątkiem jest GET /v1/cards: zawsze zwraca strony, domyślnie po 200 kart, a z limit do 1000, więc podążaj za X-Next-Cursor nawet bez limit.
// Every item of a list that returns an array.
async function* listArray(path) {
  let next = `https://api.sursa.com${path}?limit=200`;
  while (next) {
    const response = await fetch(next, { headers: { Authorization: `Bearer ${process.env.SURSA_API_KEY}` } });
    if (!response.ok) throw new Error(`HTTP ${response.status}`);
    yield* await response.json();
    const cursor = response.headers.get("X-Next-Cursor");
    next = cursor ? `https://api.sursa.com${path}?cursor=${encodeURIComponent(cursor)}` : null;
  }
}

Kanał zdarzeń

Kanał zdarzeń GET /v1/webhook-events jest dziennikiem, dlatego stronicuje się nieco inaczej:

  • Zdarzenia są uporządkowane rosnąco, od najstarszego.
  • next_cursor jest zwracany na każdej stronie, nawet gdy has_more ma wartość false. Zapisz go i zapytaj ponownie później z tym samym kursorem, aby otrzymać zdarzenia, które nastąpiły w międzyczasie. Kanał jest kolejką, którą możesz czytać we własnym tempie.
  • Zdarzenie pojawia się w kanale w ciągu około sekundy od zmiany, którą opisuje, i nigdy przed zdarzeniem, które zostało już odczytane.
  • Kanał zawiera zdarzenia całej organizacji, dlatego do jego odczytu potrzebny jest klucz z rolą admin i zakresem webhooks:manage.

Eksport do hurtowni danych pokazuje kompletną pętlę odpytywania.

Zasady dotyczące kursorów

  • Kursor to nieprzezroczysty ciąg znaków o długości do 512 znaków. Nie parsuj go i nie twórz go samodzielnie: jego format może się zmienić.
  • Kursor należy do jednej listy i jednego zestawu filtrów. Kursor uszkodzony, pochodzący z innej listy lub wysłany z innymi filtrami zwraca 400 z kodem api.cursor_invalid.
  • Każda lista ma stałą kolejność sortowania, która kończy się unikalnym kluczem, więc każdy element pojawia się na dokładnie jednej stronie.
  • Listy dodane razem z kursorami nie zwracają łącznej liczby elementów; listy, które miały wcześniej total, zachowują je. Jeśli potrzebujesz sumy, licz elementy na bieżąco.

Stronicowanie z przesunięciem

Niektóre listy przyjmowały offset przed wprowadzeniem kursorów i nadal go przyjmują, aby istniejące integracje działały dalej. W nowym kodzie preferuj cursor. Parametrów offset i cursor nie można łączyć: wysłanie obu zwraca 422 z kodem validation.failed.