Skip to main content

Pagination and Sorting

Endpoints that return a collection return it one page at a time. Paging uses an opaque cursor rather than page numbers, so that a page boundary stays correct when items are added while you are reading.

The Page Object​

Every paginated endpoint returns the same wrapper:

{
"items": [
{ "key": "3f2b8c1e-7a4d-4e5b-9c61-2d8f0a7b6e14", "name": "Invoice Review — INV-2041" },
{ "key": "a4d7e2c9-1b6f-4a38-9e05-7c2b8d1f3e60", "name": "Invoice Review — INV-2040" }
],
"nextCursor": "eyJ2IjoxLCJzIjoic3RhcnREYXRlOmRlc2MiLCJmIjoiOWE0YzFlMmI3ZDBmNTNhOCIsIm8iOjIsImsiOiJhNGQ3In0",
"hasMore": true,
"total": 214
}
FieldTypeDescription
itemsarrayThis page's results. Empty when nothing matches.
hasMorebooleantrue when there is at least one more page.
nextCursorstringThe value to send as after to get the next page. Absent on the last page.
totalintegerHow many items match in all, where the endpoint can count them cheaply. Absent otherwise.

Query Parameters​

ParameterTypeDescription
pageSizeintegerHow many items to return. The usual range is 1–100 and the default is 50; each endpoint page states its own. A value outside the range is not refused — the default is used instead, so pageSize=500 returns 50 items, not 100.
afterstringThe nextCursor from the previous page. Leave it out to start at the beginning.
sortstringThe order, as field, field:asc or field:desc. Each endpoint lists the fields it can sort by and its default. A field without a direction uses that field's usual direction.

Reading Every Page​

Repeat the request with after set to the last nextCursor until hasMore is false:

GET https://api.checkflow.io/v3/checklists?status=InProgress&sort=startDate:desc&pageSize=100
X-API-KEY: your-api-key-here
GET https://api.checkflow.io/v3/checklists?status=InProgress&sort=startDate:desc&pageSize=100&after=eyJ2IjoxLCJzIjoic3RhcnREYXRlOmRlc2MiLCJmIjoi...
X-API-KEY: your-api-key-here

In JavaScript:

async function listAll(path, params = {}) {
const items = [];
let after;

do {
const query = new URLSearchParams({ ...params, ...(after ? { after } : {}) });
const response = await fetch(`https://api.checkflow.io${path}?${query}`, {
headers: { 'X-API-KEY': process.env.CHECKFLOW_API_KEY },
});

if (!response.ok) {
throw new Error((await response.json()).error.message);
}

const page = await response.json();
items.push(...page.items);
after = page.hasMore ? page.nextCursor : undefined;
} while (after);

return items;
}

const inProgress = await listAll('/v3/checklists', { status: 'InProgress', pageSize: '100' });

Rules for Cursors​

Send the same query with every page. A cursor records the sort, the filters and the page size it was issued under. Send it with a different sort, different filters or a different pageSize and it is refused with 400 VALIDATION_ERROR and field set to after, rather than being quietly applied to a list you never saw the first page of. Start again without after when you change the query.

Treat cursors as opaque. A cursor is URL-safe text you pass back unchanged. Its contents can change between releases; a cursor that cannot be read is refused with 400 on after, and the fix is to start again.

Cursors are for one paging loop, not for storage. Use them to walk a list now. Do not save one and expect it to work next week.

Concurrent changes. If an item is added while you are paging, you will not see the item at the page boundary twice. An item added near the start of the list after you have passed it will not appear until you start again.

Endpoints That Do Not Page​

Some collections are small and bounded — a task's assignees, a checklist's tags, a Data Set's fields — and are returned in full without the page wrapper. Each endpoint page says whether it is paginated.

  • Checklists — the list most integrations page through first, with its filters and sort fields.
  • Tasks Grid — a paginated list with many filters.
  • Conventions — the JSON rules the items follow.
  • Rate Limits — every page is one request against your budget; a larger pageSize uses fewer.