Find the insights and best practices about our product.
Pagination & Incremental Sync

The Cranium Public REST API uses cursor-based pagination on all list endpoints. The cursor encodes "all records updated after this point," which is exactly the semantic needed for incremental sync. By storing the cursor between runs and replaying it on the next poll, your client receives only what has changed since the last successful sync, with no gaps and no duplicates.

This article covers how pagination works, how to perform an initial full sync, how to perform incremental syncs on subsequent runs, and how to recover from a lost cursor.

Response Format

All list endpoints return responses in the following envelope.

json

{
"data": [...],
"pagination": {
"limit": 100,
"nextCursor": "eyJ1cGRhdGVkQXQi...",
"hasMore": true
},
"meta": {
"requestId": "3fa85f64-...",
"timestamp": "2026-04-15T10:00:00Z"
},
"error": null
}

The data array contains the records for the current page. The pagination object describes the page returned and how to request the next page. The meta object includes a request identifier and server timestamp. The error field is null on successful responses.

Query Parameters

All list endpoints accept the same three query parameters.

Sync Workflow

Omit the cursor parameter (or pass an empty string) on the first call to begin from the beginning. Store the returned nextCursor and pass it on every subsequent call. When hasMore is false, you have reached the end. Store the final cursor for the next run. On the next poll, only records that were created or changed since that cursor will be returned.

Example Pagination Loop (psuedocode)

cursor = stored_cursor_or_empty
while true:
response = GET /endpoint?limit=200&cursor={cursor}
process(response.data)
cursor = response.pagination.nextCursor
if not response.pagination.hasMore:
break
store(cursor)


This same loop handles both initial full sync and incremental sync. On the first run, the stored cursor is empty and the API returns all records. On subsequent runs, the stored cursor causes the API to return only what has changed.

Recovering from a Lost Cursor

If a cursor is lost or you need to reset a known point in time, omit the cursor parameter and pass updatedAfter={last-known-sync-time} to begin a fresh feed from that date. The response includes a new cursor you can use to continue incrementally from there.

updatedAfter can also be combined with limit (no cursor) for a simple date-bounded one-off query.

Notes

  • Cursors are opaque. Do not parse, modify, or generate them yourself.
  • The cursor encodes the position in the result set for an endpoint. Cursors from one endpoint cannot be used on a different endpoint.
  • The meta.requestId value can be useful for support requests. Include it when reporting issues to your Cranium support.
Did this answer your question?