Skip to main content
List endpoints support cursor-based pagination. It is opt-in: send a limit or a cursor and you get a paginated envelope; send neither and the endpoint returns the same unpaginated body it always has.
Unpaginated list responses are supported but not recommended — they grow without bound as your workspace does. New integrations should paginate.

Requesting a page

integer
default:"25"
Rows per page, between 1 and 100. Out-of-range values are rejected with invalid_pagination rather than silently clamped — a request for 500 rows that quietly returns 100 would leave you believing you had the whole list.
string
Opaque position marker. Pass the next_cursor from the previous response verbatim. starting_after is accepted as an alias.

The response

boolean
Whether more rows exist after this page. Stop when it is false.
string | null
Position to resume from. null on the final page.
Some endpoints wrap the list in their own envelope ({ "status": "success", … }). Where they do, the pagination fields are merged in alongside — data still holds the rows.

Walking a full list

Loop until has_more is false. Do not construct cursors yourself; they encode a sort position, not an offset, and their format is not part of the public contract.

Why cursors, not page numbers

Lists are ordered newest-first. With ?page=2&per_page=25, any record created between your first and second request shifts everything down by one — so page 2 repeats a row you already saw, and eventually a row is skipped entirely. That is not a rare race; for a resource ordered by creation time it is the normal case. A cursor encodes where you stopped, not how far in you were, so concurrent writes cannot make you skip or repeat a record. It also stays fast at depth: there is no growing offset for the database to count past.

Errors

A malformed or foreign cursor, or a limit outside 1–100, returns a 400 with error.code of invalid_pagination and error.param naming the offending parameter. See Errors.