Pagination
How it works
Section titled “How it works”A long list does not come in one response. The API cuts it into pages and returns, along with the data, a mark of where it stopped. You ask for the next page by sending that mark back.
Two things go into the query:
| Parameter | What it is |
|---|---|
limit | How many records you want in the page. Default 20, maximum 100 |
cursor | The mark to continue from. Do not send it on the first call |
The response always has this shape:
{ "object": "list", "data": [], "has_more": true, "next_cursor": "Y3JlYXRlZF9hdDoy..."}| Field | What it is |
|---|---|
object | Always "list". This is how you recognize a list response |
data | The records of this page, in the order of the query |
has_more | true when there is still a page after this one |
next_cursor | The mark to ask for the next page |
What the client keeps between pages
Section titled “What the client keeps between pages”Only next_cursor. Nothing else.
Do not keep the call number, the total of records read, or the last id seen in order to continue from it. The cursor already carries everything the API needs to resume from the right place.
How to know it ended
Section titled “How to know it ended”Stop when has_more is false. While it is true, send next_cursor back in the cursor parameter and ask again.
Do not use the size of data as an end signal. A page may come smaller than limit and still have a continuation.
The cursor is opaque
Section titled “The cursor is opaque”The cursor value is a string only the API understands. Treat it as a black box:
- Do not read it. It looks readable in some cases, but its content is internal and may change without notice, because that breaks nobody who only sends the value back.
- Do not build one by hand. An invented cursor is rejected.
- Do not touch it. Send back exactly the string that came, without trimming, decoding or changing a character.
Why there is no page number
Section titled “Why there is no page number”With page numbers, page 2 means “skip the first 20”. If somebody creates a record between your call for page 1 and your call for page 2, everything moves down one position: the twentieth record of page 1 becomes the first of page 2, and you read it twice. If somebody deletes a record, the opposite happens and a record never shows up.
A cursor does not count positions, it marks a point in the ordering. A record created after your first page pushes nothing, and the sweep finishes without repeating and without skipping.
That is also why there is no offset and no page in the API.
Filters and order
Section titled “Filters and order”Every list accepts the same three date filters:
| Filter | What it does |
|---|---|
created_after | Only what was created after this instant |
created_before | Only what was created before this instant |
updated_after | Only what changed after this instant |
The default order is created_at descending, newest first.
With updated_after, the order becomes updated_at ascending. That is the sync mode: you keep the largest updated_at you have seen, and on the next round you continue from there, without rereading what did not change. Dates follow the format in Dates and money.
There is no free ordering and no filter by arbitrary field. Each resource declares its own filters in the Reference.
Next step
Section titled “Next step”- Dates and money: the date format the filters accept.
- Rate limits: sweeping a long list spends request budget.