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