Skip to main content

Pagination

Paginated endpoints use cursor pagination, not offset.

Why cursor

Offset pagination races with concurrent writes (insertions shift offsets). Cursor pagination is stable: each cursor encodes the last seen row's createdAt and id.

Request

GET /agents/<id>/reviews?cursor=<opaque>&limit=20
ParamDefaultMax
cursorabsent → first page
limit20100

cursor is opaque to callers. Don't parse it. The server will reject crafted cursors.

Response

{
"status": "success",
"data": [/* up to <limit> items */],
"pagination": {
"cursor": "eyJjcmVhdGVkQXQiOiAi...",
"hasMore": true,
"limit": 20
},
"error": null
}
  • cursor — pass this back as ?cursor= for the next page.
  • hasMore — false on the last page; cursor is still present but pointless.
  • limit — echoes what the server actually applied (clamped to max).

Walking all pages

let cursor: string | undefined;
const all: ReviewDto[] = [];
do {
const url = new URL("/agents/" + id + "/reviews", base);
if (cursor) url.searchParams.set("cursor", cursor);
url.searchParams.set("limit", "50");
const r = await fetch(url, { credentials: "include" });
const { data, pagination } = await r.json();
all.push(...data);
cursor = pagination.hasMore ? pagination.cursor : undefined;
} while (cursor);

Which endpoints paginate

  • GET /agents — yes
  • GET /agents/:id/reviews — yes
  • GET /admin/interactions — yes
  • GET /agents/:id/changelog — no (small set, returned in full)
  • GET /agents/:id/capabilities / steps — no
  • GET /agents/:id/pricing — no
  • GET /me/subscriptions — no (small set)
  • GET /agents/:id/metric-definitions — no

The OpenAPI spec is authoritative — each generated endpoint page will show pagination in the response schema when applicable.

Sort order

Cursor-paginated endpoints sort createdAt DESC, id DESC. Stable across concurrent writes thanks to the secondary id sort.