Pagination, filtering and search
limit and cursor, filters per resource, search, and the sync pattern with updated_since.
Lists come in pages#
Every list returns the newest records first:
{
"object": "list",
"data": [ { "object": "client", "id": "…" } ],
"has_more": true,
"next_cursor": "MjAyNi0xMC0xN1QwOTozMDowMC4wMDBafDZmMWMy…"
}limit— 1 to 200, default 50.cursor— passnext_cursorfrom the previous page to get the next one. Whenhas_moreisfalse, you have everything.
Cursors stay correct while new records are added: you never get a record twice or miss one in between.
curl "$QUILO_URL/api/v1/sales?limit=200&cursor=MjAyNi0x…" -H "Authorization: Bearer $QUILO_API_KEY"Fetch every page (JavaScript)#
async function all(path) {
const out = [];
let cursor = null;
do {
const url = new URL(`${process.env.QUILO_URL}/api/v1/${path}`);
url.searchParams.set('limit', '200');
if (cursor) url.searchParams.set('cursor', cursor);
const res = await fetch(url, { headers: { Authorization: `Bearer ${process.env.QUILO_API_KEY}` } });
if (!res.ok) throw new Error(`${res.status} ${await res.text()}`);
const page = await res.json();
out.push(...page.data);
cursor = page.has_more ? page.next_cursor : null;
} while (cursor);
return out;
}Filters#
Each resource has its own filters, listed in the API reference. Combine as many as you like; all must match.
# open urgent tasks of one client
curl "$QUILO_URL/api/v1/tasks?client_id=5d2c1b0a-…&status=todo&priority=urgent" -H "Authorization: Bearer $QUILO_API_KEY"
# sales in October 2026
curl "$QUILO_URL/api/v1/sales?purchased_from=2026-10-01&purchased_to=2026-10-31" -H "Authorization: Bearer $QUILO_API_KEY"Unknown parameters are refused with 400 invalid_request, so a misspelt filter never returns everything by accident.
Search clients#
q searches first name, last name, company, email and phone (at least 2 characters, not case-sensitive):
curl "$QUILO_URL/api/v1/clients?q=marti" -H "Authorization: Bearer $QUILO_API_KEY"To find one client by email, use the exact filter email= instead; it is faster and not case-sensitive.
Keeping another system in sync#
Clients have updated_at. Save the time you started each sync and ask only for what changed since the last one:
- Remember
started = now(). GET /clients?updated_since=<last_started>&limit=200, followingnext_cursoruntilhas_moreis false.- Upsert each client in your system by
id. - Store
startedaslast_startedfor next time.
For other resources use created_since to pick up new records.