Skip to content

Pagination ​

Lists that can grow without bound are paginated by cursor: the response carries an opaque nextCursor, which you send back to get the following page. Tables rows are the one exception and use an offset, because a Table is a spreadsheet sorted by any column on demand.

Cursor-based lists ​

A paginated list takes two optional query parameters and returns one extra field:

WhereNameMeaning
querylimitThe page size. Each route has a default and a maximum (most often 50 and 200; see the reference). A limit above the maximum is refused with 400.
querycursorThe nextCursor of the previous page. Absent for the first page.
responsenextCursorThe cursor of the next page, or null when there is no more.
http
GET /api/v1/executions?workflowId=0192f1c2-aaaa-7000-8000-000000000001&limit=50
json
{
  "executions": [ { "id": "…", "status": "succeeded", "…": "…" } ],
  "nextCursor": "MjAyNi0xMC0wNFQwOToxMjo0NC4xMjNafDAxOTJmMWMy"
}

Then:

http
GET /api/v1/executions?workflowId=0192f1c2-aaaa-7000-8000-000000000001&limit=50&cursor=MjAyNi0xMC0wNFQwOToxMjo0NC4xMjNafDAxOTJmMWMy

Rules to follow:

  • The cursor is opaque: do not parse it, build it or store it beyond the current traversal. Its format may change between versions.
  • Keep the same filters from one page to the next. A cursor encodes a position in one particular ordering; changing status or workflowId mid-way gives an undefined result.
  • Stop when nextCursor is null. An empty page with a null cursor is a normal end, not an error.
  • Lists are newest first unless the route says otherwise (executions, incidents, messages, audit log); the waiting executions are sorted by deadline.
  • A cursor is stable against insertions: a run created while you page does not shift the following pages.

The routes paginated this way include GET /api/v1/executions, GET /api/v1/executions/waiting, GET /api/v1/executions/incidents, GET /api/v1/messages, GET /api/v1/threads, GET /api/v1/contacts, GET /api/v1/approvals, GET /api/v1/review, GET /api/v1/notifications, GET /api/v1/journal, GET /api/v1/sending/journal, GET /api/v1/admin/audit and the cases of GET /api/v1/eval-runs/{id}.

Lists that are not paginated ​

Short, bounded lists are returned whole: workflows (GET /api/v1/workflows), mailboxes, tables, connections, API keys, the versions of a workflow, the members of the instance. They take no cursor and return no nextCursor.

Tables rows: offset and limit ​

GET /api/v1/tables/{id}/rows sorts by any column (sort, dir), filters (q, filter, match) and pages by offset:

NameDefaultMaximumMeaning
offset0100000The number of rows to skip
limit100500The page size

The response carries the rows plus two counters: total, the number of rows the filter retains across all pages, and totalUnfiltered, the size of the table. Page n of size limit is offset = (n - 1) × limit; the last page is reached when offset + rows.length >= total.

http
GET /api/v1/tables/0192f1c2-dddd-7000-8000-000000000001/rows?sort=created_at&dir=desc&offset=200&limit=100

The offset is capped: a request beyond 100000 is refused with 400, and a page that lies beyond the end of the filtered rows is tables.page_out_of_range. Tables are bounded objects (see Tables), which is what makes an offset acceptable here and nowhere else.