Pagination

Reference

Pagination

Set a page size, follow next_cursor and stop at the last page when listing sessions or world entries.

All five list endpoints take limit and cursor. Endpoints that return a single record give back one object and skip pagination.

Query parameters

Leave out cursor on your first call. A cursor that is empty also begins at the start.

Parameter Type Description
limit integer Optional positive page size. Defaults to 50. Values above 100 are capped at 100.
cursor string Optional next_cursor from the previous response to this list endpoint. Treat it as an opaque value.
First page
curl "https://app.saga20.com/api/public/v1/characters?limit=1" \
  -H "Authorization: Bearer $SAGA20_API_KEY"

Response fields

Every list response holds a data array plus a pagination object. The API gives no total count.

Field Type Description
data array of objects Records on this page. Each endpoint documents its record fields.
pagination object Whether another page is available and the cursor to request it.
pagination.next_cursor string or null Pass this value as cursor for the next page. Null on the last page.
pagination.has_more boolean True when another page is available. False on the last page.
Response
{
  "data": [
    {
      "id": "a4f1b6d2-0e5c-4b7a-8c33-1d9e2f7a6b50",
      "name": "Nyra Vael",
      "icon": "saga20:mage",
      "hidden_from_wiki": false,
      "created_at": "2026-09-02T18:00:11+00:00",
      "updated_at": "2026-09-25T08:04:02+00:00",
      "is_player_character": true
    }
  ],
  "pagination": {
    "next_cursor": "eyJvZmZzZXQiOjF9",
    "has_more": true
  }
}

Request the next page

Pass the cursor you got back to the same endpoint and keep the same page size. Take the value from the response. Never build or edit cursors.

Stop once has_more is false.

Next page
curl "https://app.saga20.com/api/public/v1/characters?limit=1&cursor=eyJvZmZzZXQiOjF9" \
  -H "Authorization: Bearer $SAGA20_API_KEY"
Last page
{
  "data": [
    {
      "id": "5e2c8a91-7d34-4f0b-a6e1-b03c9d4f1a27",
      "name": "Warden Ossric",
      "icon": null,
      "hidden_from_wiki": false,
      "created_at": "2026-09-09T20:15:44+00:00",
      "updated_at": "2026-09-18T07:42:30+00:00",
      "is_player_character": false
    }
  ],
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}

Empty pages

When there are no records, or a cursor goes past the end, you get 200 and an empty array.

Empty page
{
  "data": [],
  "pagination": {
    "next_cursor": null,
    "has_more": false
  }
}

Ordering and edits

Sessions sort by recording date, newest first, and those without a recording date come last. World entries sort by their manual sort order, then by name. Records that share those values have no guaranteed order.

Pages read the campaign as it stands now. Records may repeat or be missed when entries are added, removed or reordered while you import. Track records by id and begin a new pass if the campaign changes during your read.

Invalid parameters

A limit that fails to parse as a positive integer gives 400 with {"error":"limit must be a positive integer"}. A bad cursor gives 400 with {"error":"Invalid cursor"}. The limit check happens before the cursor check.

Authentication and rate limits run first. These 400 responses use request budget but carry no rate-limit headers.