API reference
Pagination
List endpoints return at most 50 records by default and 100 maximum. Larger result sets are walked with opaque cursors.
Query parameters
limit— integer, 1–100 (default 50). Out-of-range values clamp to the default.cursor— opaque string returned asnext_cursorfrom the previous page. Omit on the first call.
Response shape
json
{
"data": [
{ "id": "cli_01HX...", "name": "Tan & Co", "createdAt": "2026-05-12T03:14:22.412Z" },
{ "id": "cli_01HW...", "name": "Lim Renovations", "createdAt": "2026-05-11T22:08:01.882Z" }
],
"hasMore": true,
"nextCursor": "eyJpZCI6ImNsaV8wMUhXLi4uIiwiY3JlYXRlZEF0IjoiMjAyNi0wNS0xMVQyMjowODowMS44ODJaIn0"
}- data — array of records, newest first by
createdAt. - hasMore — boolean. When
false, you've reached the end andnextCursorisnull. - nextCursor — base64url-encoded JSON pointing to the next record. Treat it as opaque — its structure may change without notice.
Walking a full list
terminal
#!/bin/sh
KEY="zb_live_4xK2pQ7nR9sT1vW3yZ5aBd"
URL="https://www.zengbook.com/api/v1/clients?limit=100"
while [ -n "$URL" ]; do
RES=$(curl -sS "$URL" -H "Authorization: Bearer $KEY")
echo "$RES" | jq -c '.data[]'
CURSOR=$(echo "$RES" | jq -r '.nextCursor // empty')
if [ -z "$CURSOR" ]; then break; fi
URL="https://www.zengbook.com/api/v1/clients?limit=100&cursor=$CURSOR"
doneIn TypeScript
walk.ts
async function* walk<T>(path: string, key: string): AsyncGenerator<T> {
let url: string | null = `https://www.zengbook.com/api/v1/${path}?limit=100`
while (url) {
const res = await fetch(url, {
headers: { Authorization: `Bearer ${key}` },
})
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`)
const body = (await res.json()) as {
data: T[]
hasMore: boolean
nextCursor: string | null
}
for (const row of body.data) yield row
url = body.nextCursor
? `https://www.zengbook.com/api/v1/${path}?limit=100&cursor=${body.nextCursor}`
: null
}
}Stability
New records during paging
The cursor is anchored on (createdAt, id) of the last row seen. Records inserted while you are paging will not appear in your walk — they sort newer than where you started. Re-run the walk (or page from a stored high-water mark) if you need a fresh snapshot.