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"