Skip to content

Pagination

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 (typically 20–50); capped at 100 on most list endpoints (some insights endpoints accept up to 2000 — 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 Go SDK hides the loop behind Page[T], so you rarely write it by hand. .Iter(ctx) yields items lazily, fetching pages as you consume them; .All(ctx) collects every remaining item into a slice:

Auto-pagination — fetches pages as you iterate
page, err := client.Sites.List(ctx, nil)
if err != nil {
return err
}
for site, err := range page.Iter(ctx) {
if err != nil {
return err
}
fmt.Println(site.ID, site.Domain)
}
Or collect everything at once
sites, err := page.All(ctx) // beware unbounded result sets

Collections return newest first, and within a single cursor walk ordering is stable: each endpoint sorts by a deterministic key, 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.