Pagination
Read paginated results with cursors and optional parallel segments.
Read every page
For table lists, row lists, and row queries, continue until pagination.next_cursor is null. A short or empty page can still have another page.
{
"data": [],
"pagination": { "next_cursor": "<opaque cursor>" }
}
Send a non-null cursor back unchanged as cursor. URL-encode it for GET requests or put it in the JSON body for row queries. Do not construct or decode it.
limit sets the requested page size, not a guaranteed number of results. You can change limit and returned fields between pages. The quickstart includes complete loops.
Continue a read
A cursor belongs to the key, endpoint, table, filter, and segment settings that produced it. It still works after rotating that key.
Reuse the filter, including the order of conditions and in values. Reordering an equivalent filter can invalidate the cursor. Values use the field's normalization, so equivalent domain letter case does not change a filter.
A row-list cursor cannot continue a row query, or vice versa. Keep segment and total_segments unchanged throughout each read.
Cursors expire. If a request returns 400 invalid_cursor, restore the original settings or restart without a cursor. Skip rows you already processed when restarting.
Data can change between pages
Each page reads current data. Rows added, changed, or removed during a read may affect the result. For a consistent result, keep the data and readable fields unchanged while reading. Restarting and removing duplicate IDs does not recover every concurrent change.
Parallel reads
Use segment and total_segments to split rows between readers. Each reader has its own cursor.
For example, these readers cover separate parts of the table:
GET /v1/lookup-tables/{table_id}/rows?segment=0&total_segments=2
GET /v1/lookup-tables/{table_id}/rows?segment=1&total_segments=2
A POST query uses the same settings in its body:
{
"filter": { "field": "account_domain", "in": ["acme.example.com", "blue-lake.example.com"] },
"fields": ["account_domain", "owner_email"],
"segment": 0,
"total_segments": 2
}
Keep the filter and total segment count the same across readers. When the table and readable fields stay unchanged, the segments do not overlap and together cover all matching rows. No separate session is needed.
Increase parallel readers gradually and check the rate-limit headers. More requests do not guarantee a proportional speed increase. Retry temporary errors with the same cursor.