Response structure
Every paginated response includes these fields:
In incremental sync mode,
GET /transactions adds one more field to this envelope: a watermark timestamp to pass back as updated_after on your next sync. It appears only when the request carried updated_after, so treat it as optional when parsing. Incremental mode also changes what the cursor looks like: the classic transactions cursor happens to resemble a transaction id, while the incremental cursor is an unmistakably opaque token. Treat both as opaque and pass them back unchanged.
Parameters
integer
default:"100"
Number of results per page. Minimum 1, maximum 500.
string
Pass the
next_cursor value from the previous response unchanged to fetch the next page.Paginated endpoints
GET /accounts and GET /cards cursors are opaque tokens, never acct_ or card_ ids, and they can contain characters that need URL-encoding when you assemble the query string by hand. Pass one back exactly as issued; substituting an id returns 400 invalid_request.
A /cards cursor is additionally bound to the exact account_id filter the page was fetched with, so keep the same filter on every page of one sequence. Changing the filter mid-pagination, or replaying a cursor issued by /accounts, returns the same generic 400 invalid_request. To switch filters, start a new sequence without a cursor.
GET /rules cursors currently look like rule_ ids, the same quirk the classic transactions cursor has. Treat them as opaque all the same and pass them back unchanged. An unknown, deleted, malformed, or inaccessible cursor returns 404 resource_missing with param: "starting_after" (not the 400 that /accounts and /cards use), so discard the stored cursor and restart from the first page. Rules come back newest first, and pagination is live keyset pagination rather than a snapshot: a rule created ahead of your cursor appears on a fresh traversal, not on the next page of the current one.
Unpaginated list endpoints
These return a list envelope but always deliver the full set in a single response. Their sets are small and bounded, so there is nothing to page through: They do not acceptlimit or starting_after, and their envelopes carry only object, url, and data. There is no has_more and no next_cursor field at all, so a generic pagination helper must treat an absent has_more as “this is the only page” rather than reading it as false off an object that never had it.
Endpoints with no list envelope
GET /team is not a list endpoint, even though it returns collections. It returns a single team document whose members and invitations arrays sit directly on the response:
object: "list", no url, and no data, so a generic helper that reaches for response.data will read undefined rather than an empty page. Branch on object before treating any response as a list. Both arrays are always present and are [] when empty, never null, and neither accepts limit or starting_after.
Lists embedded in an object
GET /jobs/{id} returns a single job, not a list, but the job’s errors field is a complete list envelope with its own has_more and next_cursor. Page through it with the usual limit (1 through 500, default 100) and starting_after on the job’s URL. Each page returns the whole job again along with the next slice of errors.
The embedded envelope’s url is the job’s own path (for example /api/v1/jobs/job_example123), so a generic helper works if you point it at response.errors rather than at the response itself. Job error cursors are opaque signed tokens bound to one job: pass them back unchanged (URL-encoded in the query string), and expect 400 invalid_request for a cursor that is malformed, tampered with, or issued for another job. See Reading job errors.
Example
Fetch the first page of transactions:has_more is true, use next_cursor to get the next page: