On this page

Pagination

Beta

Cursors, why they are opaque, and how to walk a list to the end.

2 min read

Every list endpoint takes limit and cursor, and answers newest first.

curl "https://api.ghostsms.io/v1/activations?limit=50" \
  -H "Authorization: Bearer $GHOSTSMS_KEY"
{
  "object": "list",
  "data": [ { "object": "activation", "id": "8c1e4f2a-3b6d-4e9f-a0c7-2d5b9e1f7a34", "…": "…" } ],
  "next_cursor": "eyJjIjoiMjAyNi0wOS0xOFQxMDoxNTowMFoiLCJpIjoiYWN0XzVmMDgzMmQ4Ijp9",
  "has_more": true
}

Pass next_cursor back as cursor to get the next page. When has_more is false, next_cursor is absent and you have reached the end.

let cursor = undefined
const everything = []

do {
  const url = new URL('https://api.ghostsms.io/v1/activations')
  url.searchParams.set('limit', '100')
  if (cursor) url.searchParams.set('cursor', cursor)

  const page = await get(url)
  everything.push(...page.data)
  cursor = page.next_cursor
} while (cursor)

The rules worth knowing

Cursors are opaque. They encode where the last page stopped, and the encoding is ours to change. Pass back exactly what you were given; do not build one, parse one, or store one for tomorrow. A cursor you did not get from us is answered with 400 and invalid_cursor.

Paging is stable. Pages are cut on when a thing was created and its id, not on an offset, so a purchase made while you are paging cannot shuffle the rows and make you miss one. A new activation appears on page one next time you start, which is what newest-first means.

limit is clamped, not obeyed blindly. Ask for more than the maximum and you get the maximum rather than an error.

Filters travel with the cursor. If you paged with client_reference=order-8842, keep sending it alongside the cursor — a cursor does not carry your filter.

Walking only what is new

For a job that runs periodically, client_reference is usually a better handle than paging the whole history: tag your purchases with it and fetch the ones you care about. For codes as they arrive, do not page at all — register an endpoint.