Skip to main content
List endpoints use cursor-based pagination. Results are returned in stable order, and you page through them using a cursor rather than an offset.

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 accept limit 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:
There is no 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:
If has_more is true, use next_cursor to get the next page:

Fetching all pages

Use larger limit values (up to 500) to reduce the total number of requests, especially if you are syncing all data.
Refetching every page just to find out what changed? GET /transactions has an incremental sync mode that returns only the transactions modified since your last run, including deletions.
Writing a generic helper that paginates any list endpoint? Use the url field from the response instead of hardcoding the path: append ?starting_after={next_cursor} to response.url and the same function works across /accounts, /cards, /transactions, /journal_entries, /parties/merchants, and /rules. URL-encode the cursor when you do; /accounts and /cards cursors in particular are not guaranteed to be query-safe as-is. One caveat: url never includes a query string, so if the first page carried a filter (for example /cards?account_id=...), your helper must re-append that filter to every page itself. On /cards, dropping it mid-sequence is a 400, not a silent unfiltered list.