Skip to content

Pagination

Preview Every list endpoint paginates the same way: cursor-based, never offset-based. You ask for a page, get an opaque next_cursor, and pass it back to fetch the next page. There are no page numbers and no offset — which is what keeps lists stable and fast even over very large, append-heavy datasets.

Much of what you list — logs, traces, requests, jobs, audit entries — is backed by ClickHouse and grows constantly. Offset pagination (?page=5) degrades badly there: it has to count past everything it skips, and rows shifting underneath you cause duplicates and gaps. Cursors encode a stable position in the result set, so page N is cheap to fetch and the boundary between pages is exact regardless of what’s been written since. Cursor pagination is used everywhere in the API, for consistency.

Parameter Type Description
limit integer Page size. Defaults to a sensible value per endpoint; capped at a per-endpoint maximum (100 on most list endpoints — see each resource page).
cursor string The opaque next_cursor from a previous response. Omit it on the first request.

Every collection response carries a pagination block:

"pagination": {
"next_cursor": "eyJ0…",
"has_more": true
}
  • has_moretrue when more pages exist. Loop until it’s false.
  • next_cursor — pass as cursor on the next request. It’s null when has_more is false.

Fetch every site by following next_cursor until has_more is false.

First page
curl https://api.managed.dev/v1/sites?limit=2 \
-H "Authorization: Bearer mfk_live_…" \
-H "Forge-Version: 2026-06-23"
Next page — pass next_cursor back as cursor
curl "https://api.managed.dev/v1/sites?limit=2&cursor=eyJ0…" \
-H "Authorization: Bearer mfk_live_…" \
-H "Forge-Version: 2026-06-23"

The official SDKs hide the loop behind an iterator, so you rarely write it by hand. Iterate and the SDK fetches pages lazily as you consume them:

Auto-pagination — fetches pages as you iterate
for await (const site of mf.sites.listAll({ limit: 100 })) {
console.log(site.id, site.runtime);
}

Within a single cursor walk, ordering is stable: each endpoint sorts by a deterministic key (typically created_at plus the id as a tiebreaker), and the cursor pins your position against that order. Items created after you started paginating may not appear until you start a fresh walk — which is the correct, gap-free behavior for an append-heavy log. If you need only the newest rows, start a new request rather than continuing an old cursor.