Pagination
The cursor model — limit and nextCursor, the stable createdAt-and-id ordering, ignored malformed cursors, and a loop that fetches every page.
All three v1 endpoints are cursor-paginated. There are no page numbers and no total count.
Parameters
| Parameter | Default | Max | Meaning |
|---|---|---|---|
limit | 100 | 200 | Rows per page |
cursor | — | — | The nextCursor from the previous response |
A limit above the maximum is clamped rather than rejected; below 1 it falls back to the default.
The terminator
Each response carries nextCursor:
- a string — there is another page; pass it as
cursoron the next request, - `null` — you have reached the end. Stop.
Do not stop on a short page. A page can come back smaller than your limit and still have a successor; nextCursor: null is the only end signal.
Ordering
Rows are ordered `createdAt` descending, then `id` descending. The id tiebreak matters: without it, rows sharing a timestamp — as a bulk import produces — could be skipped or repeated across a page boundary. With it, paging is stable.
Newest first also means new rows appear at the start of the sequence, so a long paging run will not see records created while it is running. For a recurring sync, page until nextCursor is null, then start again from the top next time and stop when you reach records you already have.
Malformed cursors
A cursor that is not a UUID is ignored, not rejected: the request is served as if no cursor were supplied — the first page. It does not error.
That means a typo silently restarts your loop rather than failing loudly. If your sync seems to re-read the first page forever, check that you are passing nextCursor through verbatim.
Fetch every page
const BASE = "https://app.evoriqa.com/api/v1";
async function* allLeads() {
let cursor = null;
do {
const url = new URL(`${BASE}/leads`);
url.searchParams.set("limit", "200");
if (cursor) url.searchParams.set("cursor", cursor);
const res = await fetch(url, {
headers: { Authorization: `Bearer ${process.env.EVORIQA_API_KEY}` },
});
const body = await res.json();
if (!body.success) throw new Error(body.error.code);
yield* body.data.data;
cursor = body.data.nextCursor;
} while (cursor !== null);
}
let count = 0;
for await (const lead of allLeads()) count += 1;
console.log(`${count} leads`);import os, requests
BASE = "https://app.evoriqa.com/api/v1"
HEADERS = {"Authorization": f"Bearer {os.environ['EVORIQA_API_KEY']}"}
def all_leads():
cursor = None
while True:
params = {"limit": 200}
if cursor:
params["cursor"] = cursor
res = requests.get(f"{BASE}/leads", headers=HEADERS,
params=params, timeout=30)
body = res.json()
if not body["success"]:
raise RuntimeError(body["error"]["code"])
yield from body["data"]["data"]
cursor = body["data"]["nextCursor"]
if cursor is None:
return
print(sum(1 for _ in all_leads()))At 200 rows per page you will reach the per-minute rate limit after 120 pages — 24,000 rows. Handle RATE_LIMITED with a backoff inside the loop for larger datasets.
Where to go next
Last updated