Every list is cursor-paginated. A response carries its rows in data, a next_cursor, and has_more. Read pages until the cursor comes back null.
First page
From the published contract
curl "https://api.rivet.network/v1/documents?type=invoice&limit=2" \
-H "Authorization: Bearer rk_live_…"The page after it
From the published contract
curl "https://api.rivet.network/v1/documents?cursor=MTc1NjM…" \
-H "Authorization: Bearer rk_live_…"The cursor contract
- Pass it back verbatim. A cursor is an opaque string. Send exactly what you were given.
- Never parse or construct one. What is inside it is not part of the contract and will change. A cursor you built yourself is a request we may reject or, worse, answer oddly.
- Pages are disjoint. A record appears on one page of a walk, not two.
- Order is stable. Lists come back newest first, and the ordering does not shift under you while you page — documents created during your walk do not reshuffle the pages you have already read.
Page size
limit is 1–100 and defaults to 20. It is a maximum, not a promise: a page may come back shorter. Decide you are finished when next_cursor is null — never because a page looked small.
Narrowing instead of paging
If you are syncing repeatedly, filter rather than walk the whole history. since and until take a date (YYYY-MM-DD) or a timestamp and apply to the document date; connection, type and status narrow further. A daily job that asks for yesterday forward is cheaper and kinder than one that pages from the beginning every night.
Cursors are tied to the query that produced them. Change a filter and start a fresh walk — don’t carry a cursor from one query into another.