Pagination
How to paginate through lists using Nodukan's limit/offset model — response format, practical examples, and performance tips.
Pagination
All list endpoints in the Nodukan API use a limit/offset pagination model. You request a page of results with limit (page size) and offset (how many to skip), and the response includes a pagination object with the total count.
Query parameters#
| Parameter | Type | Default | Max | Description |
|---|---|---|---|---|
limit | integer | 20 | 100 | Number of records to return |
offset | integer | 0 | — | Number of records to skip from the start |
Response format#
Every paginated response wraps the list in data and includes a pagination block:
{
"data": [
{ "id": "lm_01j9x...", "title": "Free Notion Template", "isActive": true },
{ "id": "lm_01j9y...", "title": "Instagram Caption Pack", "isActive": true }
],
"pagination": {
"total": 47,
"limit": 20,
"offset": 0,
"hasMore": true
},
"requestId": "req_01j9xabc..."
}
pagination.hasMore is true when there are more records after the current page (i.e., offset + limit < total).
Iterating through all records#
JavaScript — async iterator#
async function* paginate(path, params = {}) {
const base = 'https://api.nodukan.com/v1';
const headers = { Authorization: `Bearer ${process.env.NODUKAN_API_KEY}` };
let offset = 0;
const limit = params.limit ?? 100;
while (true) {
const url = new URL(`${base}${path}`);
url.searchParams.set('limit', String(limit));
url.searchParams.set('offset', String(offset));
for (const [k, v] of Object.entries(params)) {
if (k !== 'limit') url.searchParams.set(k, String(v));
}
const res = await fetch(url, { headers });
if (!res.ok) throw new Error(`API error: ${res.status}`);
const body = await res.json();
yield* body.data;
if (!body.pagination.hasMore) break;
offset += limit;
}
}
// Usage — iterate all lead magnets
for await (const lm of paginate('/lead-magnets')) {
console.log(lm.id, lm.title);
}
Python#
from typing import Generator, Any
import os, requests
def paginate(path: str, params: dict = {}) -> Generator[Any, None, None]:
base = "https://api.nodukan.com/v1"
headers = {"Authorization": f"Bearer {os.environ['NODUKAN_API_KEY']}"}
limit = params.pop("limit", 100)
offset = 0
while True:
resp = requests.get(
f"{base}{path}",
headers=headers,
params={"limit": limit, "offset": offset, **params},
)
resp.raise_for_status()
body = resp.json()
yield from body["data"]
if not body["pagination"]["hasMore"]:
break
offset += limit
# Usage — collect all leads from a specific lead magnet
leads = list(paginate(f"/lead-magnets/{lead_magnet_id}/leads", {"from": "2026-01-01"}))
print(f"Total leads: {len(leads)}")
Filtering alongside pagination#
Most list endpoints accept additional filter parameters that work alongside limit and offset:
# Get active digital lead magnets, 50 at a time
curl "https://api.nodukan.com/v1/lead-magnets?limit=50&offset=0&isActive=true&type=digital" \
-H "Authorization: Bearer NDK_live_..."
# Get leads captured in May 2026
curl "https://api.nodukan.com/v1/lead-magnets/lm_abc123/leads?limit=100&offset=0&from=2026-05-01&to=2026-05-31" \
-H "Authorization: Bearer NDK_live_..."
Tips#
- Use
limit=100when fetching large datasets — fewer round trips reduce latency and rate limit consumption. - Sort order is
createdAt DESC(newest first) unless the endpoint specifies otherwise. pagination.totalis the count of all records matching your filters, not just the current page. Use it to calculate total pages:Math.ceil(total / limit).- Stable ordering — results are ordered by a stable key (usually
idorcreatedAt). Safe to resume pagination from a known offset.
The maximum limit is 100. If you need more than 100 records in a single call, use the async iterator pattern above to fetch them across multiple requests automatically.
Last updated