Pagination
Every collection answers { data, nextCursor, hasMore } with opaque cursors, a published page-size ceiling, strict query parameters and a stable order per endpoint.
Every list in the API answers the same envelope:
{
"data": [ … ],
"nextCursor": "eyJ2IjoiMjAyNi0xMC0wN1QxODo0MjoxMS4wMDBaIiwiaWQiOiIuLi4iLCJoIjoiOWI3ZCJ9",
"hasMore": true
}datais the page.nextCursoris the opaque token for the next page, ornullon the last one.hasMoresays whether another page exists.
Bounded lists that always fit in one answer (a run's tasks, a run's files) use the same envelope with nextCursor: null and hasMore: false, so one loop handles everything.
Walking a collection
curl "https://app.processcart.com/api/v1/runs?limit=100" -H "Authorization: Bearer pc_live_…"
# … then, while hasMore:
curl "https://app.processcart.com/api/v1/runs?limit=100&cursor=<nextCursor>" -H "Authorization: Bearer pc_live_…"Send the same filters and sort on every page. A cursor is bound to the query that produced it: a cursor sent with a different filter or sort is refused with 422 validation_failed (field: "cursor", code: "cursor_mismatch"), never silently applied to the wrong list. A cursor the API did not hand out, or one that was altered, is refused the same way with code: "invalid_cursor".
Page size
limit defaults to 50. The ceiling is 200 on ordinary lists and 100 on GET /v1/runs and GET /v1/views/{id}/runs (every item there is a full Run with its fields and tasks). A limit above the ceiling is a 422 — it is never clamped, so a client cannot silently get less than it asked for.
Stable order
Each endpoint documents its order. The cursor is a keyset (the sort value and the row id), so a page never repeats or skips a row that did not change. Two orders traverse a changing collection stably: startedAt (the default on runs) and updatedAt asc (what updatedSince forces). Other sorts — name, dueAt, keyDate, completedAt, priority — may skip or repeat a row whose sort value changes while you are paging. For a full copy, use startedAt; for a sync, use Incremental sync.
Strict query parameters
Every query parameter is validated and unknown parameters are refused with 422 validation_failed so a typo cannot silently widen a filter:
{
"code": "validation_failed",
"errors": [
{ "field": "updated_since", "code": "unknown_parameter",
"message": "Unknown query parameter \"updated_since\". Did you mean \"updatedSince\"? Query parameters are camelCase." }
]
}Parameters are camelCase everywhere (updatedSince, workflowId, includeTrashed); the message suggests the camelCase twin of the common snake_case spellings (updated_since, workflow_id, page_size, per_page, include_trashed, …). Comma-separated parameters (status=active,on_hold) may also be repeated (status=active&status=on_hold).