boolean
Whether another page exists. This — not an empty
data array — is the loop condition.string | null
Pass as
cursor on the next request. Null on the last page.integer | null
Approximate number of matches. Null when the result set is too large to count exactly. Useful
for a progress estimate, never as a loop bound.
The loop
GET endpoints take it as a query parameter.
Otherwise the mechanics are identical.
Cursor rules
Cursors are opaque
Cursors are opaque
The encoding is an implementation detail and will change. Never decode one, construct one, or
infer an offset from it.
A cursor pins the query
A cursor pins the query
Filters, sort, period and currency are captured when the first page is issued. Changing any of
them invalidates the cursor — start a new search instead.
Cursors expire after 10 minutes
Cursors expire after 10 minutes
An expired cursor returns
400 with cursor_expired. If you are pausing between pages for
longer than that, restart the search rather than holding the cursor.Results are a snapshot
Results are a snapshot
A cursor holds a consistent view for its lifetime, so an entity will not appear twice or vanish
mid-scan because the data refreshed underneath you.
Page size
limit accepts 1 to 100 and defaults to 25.
Use 100 for anything you are iterating. Credits are charged per row, not
per request, so larger pages cost the same in credits and a quarter as much in
rate limit budget.
Result depth
Searches page to a depth of 1,000 rows. Past that,has_more is false even if total_count
is larger.
GET /shops/{id}/products, GET /lists/{id}/items,
GET /jobs/{id}/results — have no such cap. The limit applies to ranked search, where depth
beyond the top of the ranking is not meaningfully ordered.
To go deeper: narrow the filters, shard by category or period, or use an
export job. See Search.