page, an integer starting at 1. That’s the whole mechanism — no cursor token to store between requests, no opaque string to round-trip.
What you get back differs by endpoint
Worth reading before you write one generic paginator and point it at everything, because the response shape isn’t uniform.Contacts — tells you the total
Contacts — tells you the total
GET /api/v1/accounts/{account_id}/contacts returns:meta.count is the total number of contacts matching the query, so you can compute how many pages exist. Default page size is 15.Conversations — tells you counts, not a total
Conversations — tells you counts, not a total
GET /api/v1/accounts/{account_id}/conversations returns:current_page, no total for the query you actually ran. The numbers in meta are status-bucket counts — mine, unassigned, assigned, all — not a page count for whatever filters you passed. The reliable end-of-list signal is an empty payload array, not a count comparison.Agents, teams, canned responses, custom filters — not paginated
Agents, teams, canned responses, custom filters — not paginated
These return the full collection as a bare array, every time. No
page parameter does anything, and there’s no meta to read, because nothing is being paged — you get everything in one response. That’s a reasonable design for what these lists actually are today (an account’s agent roster, its teams, its canned responses). It stops being reasonable if you’re building against an account with an unusually large canned-response library; there’s no server-side limit protecting you from a large response body on these endpoints.The exception: message history
GET /api/v1/accounts/{account_id}/conversations/{conversation_id}/messages doesn’t take a page parameter — passing one silently does nothing. Message history pages backward and forward from a message ID instead:
This isn’t in the published parameter list for that endpoint, but it’s the real, load-bearing behavior underneath both the Application API’s conversation-scoped messages endpoint and the Client API’s public messages endpoint. If you’re walking a long conversation, page backward with
before set to the oldest message ID you’ve seen, and stop when you get an empty array.
Iterating safely
Whatever shape you’re dealing with, the safe loop termination is the same: stop when the page comes back empty, not when you hit a count you precomputed at the start. Filters and totals can both change between your first request and your fifth.Next
Rate limits
What happens if that loop runs faster than it should.
Errors
The shape of the body when a page request fails.