Docs/Core Concepts/Pagination

Pagination

All collection endpoints in Ptolemy use cursor-based pagination. Cursors are stable, efficient, and safe to use across concurrent writes — unlike offset pagination, they won't skip or duplicate rows.

How cursor pagination works

Each list response includes a meta object with a next_cursor and has_more flag. When has_more is true, pass the next_cursor value as the after parameter in your next request to fetch the following page.

First page request
GET /v1/workspaces/acme-capital/instruments?limit=50
First page response
{ "data": [/* 50 instruments */], "meta": { "next_cursor": "eyJpZCI6IjNmYTg1ZjY0LTU3MTctNDU2Mi1iM2ZjLTJjOTYzZjY2YWZhNiJ9", "has_more": true } }
Next page request
GET /v1/workspaces/acme-capital/instruments?limit=50&after=eyJpZCI6IjNmYTg1ZjY0...

When has_more is false, you’ve reached the last page. next_cursor will be null.

Pagination parameters

ParameterDefaultMaxDescription
limit50200Number of records to return per page
afterCursor from the previous response's meta.next_cursor
Cursors are opaque base64-encoded strings. Do not attempt to decode, construct, or modify them — their internal structure may change. Always use the cursor exactly as returned.

Pagination with the filter API

The POST filter endpoint supports the same pagination model, but parameters are passed in the request body rather than as query parameters:

Filter request with pagination
{ "filter": { /* your conditions */ }, "sort": [{ "field": "created_at", "direction": "desc" }], "limit": 100, "after": "eyJpZCI6IjNmYTg1ZjY0..." }

Iterating all records

To fetch all records, loop until has_more is false:

results = [] cursor = None while True: body = {"limit": 200} if cursor: body["after"] = cursor resp = client.post("/instruments/filter", json=body).json() results.extend(resp["data"]) if not resp["meta"]["has_more"]: break cursor = resp["meta"]["next_cursor"]

Best practices

Use large page sizes
Set limit: 200 (the maximum) when fetching all records to minimise the number of requests and API calls consumed.
Process sequentially
Fetch pages one at a time. Making concurrent requests for multiple pages is wasteful and risks triggering burst throttling.
Don't cache cursors
Cursors can expire if not used within a reasonable time. Always fetch fresh from the previous response.
Use count for planning
Call POST /instruments/count first to estimate total record count before starting a full iteration.
PrivacyTermsStatus© 2025 Ptolemy Pty Ltd