ZevCampaign Docs
Sign up

API Reference

Pagination

Cursor paging, and why there are no page numbers.

List endpoints are cursor-paginated.

curl "https://api.zevcampaign.com/v1/contacts?limit=50" \
  -H "Authorization: Bearer sk_live_your_key_here"
{
  "data": [ "…50 contacts…" ],
  "meta": {
    "limit": 50,
    "has_more": true,
    "next_cursor": "Y3RfOHZxMnhrNG0"
  }
}

Pass the cursor back for the next page:

curl "https://api.zevcampaign.com/v1/contacts?limit=50&cursor=Y3RfOHZxMnhrNG0" \
  -H "Authorization: Bearer sk_live_your_key_here"

When has_more is false, next_cursor is null and you are done.

Walking everything

let cursor = null;
const all = [];

do {
  const url = new URL('https://api.zevcampaign.com/v1/contacts');
  url.searchParams.set('limit', '100');
  if (cursor) url.searchParams.set('cursor', cursor);

  const res = await fetch(url, {
    headers: { Authorization: `Bearer ${process.env.ZEVCAMPAIGN_KEY}` },
  });
  const { data, meta } = await res.json();

  all.push(...data);
  cursor = meta.next_cursor;
} while (cursor);

Loop on next_cursor, not on data.length. A page can come back short and still have more behind it.

limit

Between 1 and 100. Defaults to 20.

Anything outside that is refused with invalid_limit rather than clamped. Silently turning limit=1000 into limit=100 means your pagination looks broken and you spend an afternoon finding out why.

Why no page numbers

Offset paging drifts on a moving list. If somebody subscribes while you are on page 3, page 4 starts one row late and you never see that row. On an audience that changes constantly, that is a contact quietly missing from an export.

Cursors are anchored to a row, so they stay correct while the list changes underneath them.

Treat cursors as opaque

A cursor is a string we issued. Pass it back unchanged.

Do not decode it, build one, or store one for later: a cursor from last week may point at something that has moved. One we did not issue is refused with invalid_cursor.

Updated at, Saturday, October 10, 2026