page and per_page query parameters, and return a meta block.
Parameters
Response
total is the count across all pages, not the length of data. There’s no total_pages field — compute it as ceil(total / per_page), or just accumulate until you’ve collected total items.
Fetching everything
not body["data"] guard matters. Without it, a shrinking result set — rows deleted between requests — can loop forever, since len(items) never reaches a total that keeps moving.
Raise per_page
The ceiling is 500, and each request counts against your rate limit regardless of size. Paging 5,000 keywords at the default 25 costs 200 requests; at 500 it costs 10. That matters more than it sounds: the per-minute allowance is 120 for an API key, so a bulk export at the default page size will hit the limit. Always setper_page explicitly when fetching in bulk.
The 500 ceiling bounds an upstream provider’s page size as well as a database one — an uncapped value would be a request Surnex gets billed for.
Consistency
Pages are fetched separately, so a list changing underneath you — a scheduled job adding rows mid-pagination — can shift items between pages. An item can be seen twice or missed. For large exports where that matters, prefer the CSV export endpoints, which produce a single consistent snapshot.Not everything is paginated
Some endpoints return a complete set — an audit’s issues, a keyword’s history for a date range, summary data. Those returndata without meta.
Detect it by checking for meta rather than assuming. When it’s absent, you have everything.