Pagination
Large collections are returned one page at a time, using cursor pagination — not offset/limit. Each page carries its rows plus a cursor pointing at the next page, so pagination stays stable even as new rows are created while you iterate.
The list envelope
Section titled “The list envelope”A cursor-paginated list responds with:
{ "data": [ /* ...rows for this page... */ ], "has_more": true, "next_cursor": "c3Vic2NyaWJlZA"}| Field | Meaning |
|---|---|
data | The rows for this page. |
has_more | true if more pages remain after this one. |
next_cursor | Pass this back as ?cursor= to fetch the next page. null on the last page. |
Control page size with ?limit= — an integer from 1 to 100, defaulting to 25. A value outside
that range (or a non-integer) is rejected with 400 invalid_limit rather than being silently clamped.
Cursors are opaque
Section titled “Cursors are opaque”A cursor is an opaque token. Never parse, construct, or decode one — its internal format is not part
of the contract and can change without notice. Pass back exactly the next_cursor you were given. A
stale or malformed cursor is ignored (treated as “start from the top”), not an error.
Iterating a full result set
Section titled “Iterating a full result set”Loop until has_more is false, threading each next_cursor into the following request:
async function listAll(path, apiKey) { const rows = []; let cursor = null; do { const url = new URL(`https://app.personablocks.io/api/v1${path}`); url.searchParams.set('limit', '100'); if (cursor) url.searchParams.set('cursor', cursor); const res = await fetch(url, { headers: { Authorization: `Bearer ${apiKey}` } }); const page = await res.json(); rows.push(...page.data); cursor = page.next_cursor; } while (cursor); return rows;}Which lists paginate
Section titled “Which lists paginate”Cursor-paginated (return data + has_more + next_cursor):
GET /v1/verification-sessionsGET /v1/customersGET /v1/events
Plain lists (return just { "data": [...] }, no cursor — these are naturally bounded per merchant):
GET /v1/customers/{address}/notesGET /v1/webhook-endpointsGET /v1/webhook-endpoints/{id}/deliveries
Related
Section titled “Related”- Errors —
invalid_limit. - Customers & VICs —
updated_sincefor incremental syncs. - Webhooks — the real-time alternative to polling lists.