Pagination
List endpoints return a page and a cursor:
{ "data": [ … ], "next_cursor": "MjAyNi0xMC0wMVQwODoxNTowMC4wMDBafGN2XzNQekE5MQ", "has_more": true }Pass next_cursor back as cursor to get the next page. Stop when has_more is false. Control the page size with limit (1–100, default 50).
Cursors are keyset-based: new items arriving while you page don’t shift or duplicate results. Treat them as opaque strings — their format may change.
async function* all(path) { let cursor; do { const url = new URL(`https://api.waasl.io/v1${path}`); if (cursor) url.searchParams.set("cursor", cursor); const page = await (await fetch(url, { headers: { Authorization: `Bearer ${process.env.WAASL_API_KEY}` } })).json(); yield* page.data; cursor = page.next_cursor; } while (cursor);}
for await (const contact of all("/contacts?tag=vip")) console.log(contact.name);def all_items(path): cursor = None while True: r = requests.get(f"https://api.waasl.io/v1{path}", params={"cursor": cursor} if cursor else None, headers={"Authorization": f"Bearer {os.environ['WAASL_API_KEY']}"}) page = r.json() yield from page["data"] cursor = page["next_cursor"] if not cursor: breakMessage lists are the one exception in ordering: each page is oldest-first so it renders like a chat, and the cursor walks back in time.