PristineSend
Get started
Guides

Pagination

Every list endpoint (emails, contacts, domains, suppressions, events) is keyset-paginated and returns newest first. Keyset cursors are stable under inserts — you never skip or repeat a row mid-iteration the way offset pagination can.

The cursor model

Pass limit (1–100, default 50). Each response includes has_more and an opaque next_cursor. To get the next page, pass that value back as cursor. When has_more is false, next_cursor is null.

{
  "data": [ /* … */ ],
  "has_more": true,
  "next_cursor": "eyJjIjoiMjAyNi0w…"
}

SDK iterator

The SDK returns a page that is async-iterable and fetches subsequent pages on demand — the idiomatic way to walk a whole list:

// list() returns a page that auto-paginates when iterated —
// no cursor bookkeeping:
for "color:#ff7b72">await ("color:#ff7b72">const contact of "color:#ff7b72">await ps.contacts.list({ limit: 100 })) {
  console.log(contact.email)
}

Or drive it a page at a time:

"color:#ff7b72">const page = "color:#ff7b72">await ps.contacts.list({ limit: 50 })
console.log(page.data)        // this page's items
console.log(page.has_more)    // is there another page?
console.log(page.next_cursor) // opaque cursor (or null)

"color:#ff7b72">const next = "color:#ff7b72">await page.nextPage() // Page | null

"color:#ff7b72">const everything = "color:#ff7b72">await ("color:#ff7b72">await ps.contacts.list()).all() // collect all (use with care)

Manual (raw HTTP)

# First page
"color:#79c0ff">curl "https://pristinesend.com/api/v1/contacts?limit=50" \
  "color:#ff7b72">-H "Authorization: Bearer ps_live_YOUR_API_KEY"

# Next page — pass next_cursor back as cursor
"color:#79c0ff">curl "https://pristinesend.com/api/v1/contacts?limit=50&cursor=eyJjIjoiMjAyNi0w…" \
  "color:#ff7b72">-H "Authorization: Bearer ps_live_YOUR_API_KEY"