api · guide
Migrate from offset to cursor pagination
How to move a list integration from offset pagination to cursors without dropping or repeating rows.
Sunset: 2026-07-31 23:59:59 UTC Affected endpoints:
GET /api/v1/orders,/products,/conversationsLast updated: 2026-05-25
Why we're switching
Offset pagination scans the full preceding window on every page, so performance falls off a cliff on tenants with >100k rows. Cursor pagination is constant-time per page and stable across concurrent inserts.
What changes
-
New query params:
?cursor=<opaque>+?limit=<1..100>(default 50; conversations 20). -
New response field:
next_cursor. Null on the last page. -
offset=keeps working until 2026-07-31 — but responses now emit:Deprecation: true Sunset: Sat, 31 Jul 2026 23:59:59 GMT Link: <https://docs.vendu.app/api/pagination#cursor>; rel="successor-version" Warning: 299 - "Offset pagination is deprecated; migrate to cursor pagination before the Sunset date."
Before
GET /api/v1/orders?offset=100&limit=50
{
"object": "list",
"url": "/api/v1/orders",
"has_more": true,
"data": [ ... ]
}
After
First page:
GET /api/v1/orders?limit=50
{
"object": "list",
"url": "/api/v1/orders",
"data": [ ... ],
"next_cursor": "eyJ2IjoxLCJzb3J0IjoiY3JlYXRlZF9hdCIsImRpciI6ImRlc2MiLCJsYXN0IjoiMjAyNi0wNS0yNVQwMDowMDowMFoiLCJpZCI6ImFiYy0xMjMifQ",
"has_more": true
}
Next page — pass back the next_cursor:
GET /api/v1/orders?cursor=eyJ2IjoxLCJ…&limit=50
When has_more = false (or next_cursor = null), you're done.
Sort stability
Cursors include both the sort column (created_at by default,
updated_at for conversations) and the row id as a tie-breaker.
Even if two rows share the same timestamp, you'll never see
duplicates or skips between pages.
What if I really need random access?
You probably don't — but if you're paginating an export, the safer
path is to record the first created_at you saw, request ?fields=id
to slim the response, and walk forward with cursors. Random offset
into a >100k window is the failure mode this migration is fixing.
Reference
- Cursor payload:
{ v: 1, sort, dir, last, id }, base64url-encoded - Implementation:
src/lib/pagination/cursor.ts - Deprecation policy: Versioning and deprecation