Currently Available: Need a skilled Software Developer for your next project?
Categories
APIs

Explaining Cursor Pagination Tokens to API Consumers

When a client requests a large collection from an API, the server often sends the results in parts. A cursor pagination token is a value the server returns so the client can ask for the next part. The token marks where the server should continue in the sorted results, or carries other information that API uses to continue.

Treat the token as an opaque value, meaning you should not try to interpret it. Save it exactly as returned and send it with the next request, following the API’s instructions. The token’s appearance does not tell you whether it represents a record position, sort values, or information stored by the server. A collection changing does not automatically invalidate every cursor, and no universal token lifetime applies across APIs.

What a cursor token represents

A server creates a cursor for a specific query. The query names the collection and may also include filters, sort order, or other parameters. The server returns a page of results and, when more results are available, a token that lets the client continue.

For example, a client requests records sorted by creation time. The server returns some records and a next-page token. The client sends that token with the same query to request the next portion. The token does not mean “page 3”; it tells that API how to continue from the previous request. The GraphQL Cursor Connections specification describes this pattern as passing the last result’s cursor to retrieve results after it. The SCIM pagination standard likewise directs clients to continue using the returned cursor while keeping the original query parameters.

The token’s format does not tell you what it means. Google’s API guidance says page tokens should be opaque, meaning clients should not interpret or change them. Stripe documents a product-specific cursor based on an object ID, while Microsoft Data API builder shows a Base64-encoded cursor. Those examples illustrate different implementations; they do not make an ID or encoded string a safe, general-purpose cursor format. Pass the value through unchanged unless the API explicitly documents another use.

What the token does not promise

A cursor is not necessarily a record ID, a page number, or a numbered offset. It also does not grant access to the collection: the server still checks authorization on each request, as Google’s pagination guidance specifies for Google-style APIs.

The JSON:API cursor profile allows results to change between page requests, so a cursor does not automatically freeze the collection as it was when the client made the first request. It describes snapshot-consistent results, where every page shows the same fixed version of the collection, as an optional server behavior. Unless the API promises a snapshot, treat each page request as a request for results that may have changed since the previous page.

Nor does a cursor guarantee that every response contains the requested number of records. Google’s guidance, for example, allows a page to contain fewer results than requested, including an empty page before the end, when the response still supplies a next-page token. Follow the API’s explicit next-page indicator rather than inferring that an empty or short page always ends the traversal.

Why the query and ordering matter

The server needs a consistent sort order to determine which results come before and after a cursor. If a client changes a filter or sort order midway through pagination, the next request may no longer match the query that produced the token. Keep using the same endpoint and query parameters unless the API documents an exception. Some APIs permit a page-size change; Google’s guidance allows it while expecting other request arguments to stay the same. The target API’s contract takes precedence.

The sort order must also distinguish records that share a value. For example, if several records have the same creation time, the server needs a way to order them relative to each other. The JSON:API cursor profile calls for a unique ordering when pagination is supported, and the GraphQL specification calls for consistent ordering across pages. As a consumer, use the sort options the API documents and avoid changing them during a traversal.

Cursor pagination avoids some problems with numbered offsets. With offset pagination, deleting a record before the next offset shifts later records, which can cause the client to skip one. A cursor based on sort order avoids that particular shift. It does not prevent other changes during pagination or guarantee that an export includes each record exactly once.

How collection changes affect a cursor

An insertion or deletion does not always invalidate a cursor. The outcome depends on how the API defines the cursor and handles changes. The JSON:API profile describes a case where the server deletes the record associated with a cursor but the cursor still separates the remaining results at that record’s former position. Other APIs use different rules.

Some changes do invalidate tokens under specific API contracts. Microsoft Data API builder documents that schema or ordering changes invalidate previously issued tokens and directs clients to start pagination again. This is a product-specific rule, not a general consequence of any collection change. Check the API documentation for the changes it treats as invalidating.

For a complete export, check whether the API promises a snapshot or similar consistency. Without that guarantee, new, deleted, or reordered records can change which results the client sees as it requests each page.

Why a token expires or gets rejected

Some APIs set an expiration time for tokens or invalidate them when the query changes. The SCIM standard defines errors for invalid and expired cursors. Google’s guidance suggests three days as a rule of thumb for APIs that store page tokens. Azure Cosmos DB documents that its continuation tokens do not expire when used with the same SDK version. Each rule applies in its stated context; no universal cursor expiration period exists.

When a server rejects a token, the API determines the response format and how the client can recover. Read the error details and follow the API’s instructions. If the token has expired or the API says it is invalid and provides no recovery path, restart pagination from the first page. Do not assume that a particular HTTP status or error format applies across unrelated APIs.

How to use tokens safely

Save the exact next-page token the server returns and send it again with the same query. Do not decode, edit, create, or use it with a different filter or sort order unless the API explicitly allows it. Follow the response’s documented next-page signal; an omitted or empty next token indicates the end only when that API defines it as the end.

If a request fails after several pages, do not treat the results you have as a complete collection. Check whether the API reports that the token expired or became invalid, then restart pagination or use the API’s documented recovery method. For long-running exports, check whether the API documents token lifetime and snapshot behavior before relying on a traversal to represent one fixed collection.

What I'm building

Delegate tasks. Get software.

Give Vroni a GitHub issue, bug report, spec, or rough idea. It reads the repo, plans the change, writes code, runs checks, and works toward a review-ready pull request.

Take a look at vroni.com

Email updates

Usually a new article and a few links I found interesting.

No spam. Unsubscribe with one click.

Leave a Reply

Your email address will not be published. Required fields are marked *