Pagination
Every list works the same way.
curl "https://api.usedoozy.com/api/v1/todos?limit=25" \
-H "Authorization: Bearer $DOOZY_API_KEY"{
"object": "list",
"data": [ "..." ],
"hasMore": true,
"nextCursor": "eyJ2IjoxLCJ0IjoiMjAyNi0wOC0yMFQxNDowMzoxMS4wMDBaIiwiaWQiOiI5YTFmIn0"
}Pass nextCursor back as cursor to get the next page:
curl "https://api.usedoozy.com/api/v1/todos?limit=25&cursor=eyJ2Ijox..." \
-H "Authorization: Bearer $DOOZY_API_KEY"hasMore is false and nextCursor is null on the last page.
limit runs from 1 to 100 and defaults to 25.
Walking a whole collection
async function* allTodos(apiKey) {
let cursor = null;
do {
const url = new URL('https://api.usedoozy.com/api/v1/todos');
url.searchParams.set('limit', '100');
if (cursor) url.searchParams.set('cursor', cursor);
const response = await fetch(url, {
headers: { Authorization: `Bearer ${apiKey}` },
});
const page = await response.json();
yield* page.data;
cursor = page.nextCursor;
} while (cursor);
}Cursors are opaque
A cursor encodes where the last page ended. Its contents are ours to change, so read it as a string and pass it back unaltered. A cursor from a different endpoint, or one you built yourself, returns 400 with invalid_cursor.
Why not offset
Offset pagination drifts. Ask for the first 25 todos, have three created while you read them, ask for the next 25, and three fall through the gap unseen. Cursors point at a record rather than a position, so a page stays correct while the collection changes underneath it.
The tradeoff is that you cannot jump to page seven. In exchange, walking the whole thing is reliable, which is what a program actually needs.
Sorting
Lists that support ordering take sort and order. Changing them mid-walk invalidates your cursor, so decide the order before you start.
Todos sort by createdAt, updatedAt, dueDate or priority. Chats and captures come newest first.
Polling for what is new
Cursors walk a collection; they do not watch one. nextCursor is null exactly when you have caught up, so there is nothing to hold on to between polls.
To watch for new records, keep the createdAt of the newest record you have seen and filter on it. Captures take createdAfter directly:
curl "https://api.usedoozy.com/api/v1/captures?createdAfter=2026-08-20T14:03:11.000Z" \
-H "Authorization: Bearer $DOOZY_API_KEY"For todos, page the default newest-first order and stop at the first record you already have.
Chat messages are the exception, and the better model: they carry a sequence that only goes up, so you keep a number rather than a timestamp. See Working with agents.
Nothing is pushed to you. There are no webhooks and no streaming, so watching means polling.