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.
Why cursors, not offsets
Section titled “Why cursors, not offsets”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.
The parameters
Section titled “The parameters”| 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_more—truewhen more pages exist. Loop until it’sfalse.next_cursor— pass ascursoron the next request. It’snullwhenhas_moreisfalse.
A worked loop
Section titled “A worked loop”Fetch every site by following next_cursor until has_more is false.
curl https://api.managed.dev/v1/sites?limit=2 \ -H "Authorization: Bearer mfk_live_…" \ -H "Forge-Version: 2026-06-23"curl "https://api.managed.dev/v1/sites?limit=2&cursor=eyJ0…" \ -H "Authorization: Bearer mfk_live_…" \ -H "Forge-Version: 2026-06-23"page, err := client.Sites.List(ctx, &forge.ListOptions{Limit: 100})if err != nil { return err}sites := page.Itemsfor page.HasMore { if page, err = page.Next(ctx); err != nil { return err } if page == nil { break } sites = append(sites, page.Items...)}Auto-pagination in the Go SDK
Section titled “Auto-pagination in the Go SDK”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:
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)}sites, err := page.All(ctx) // beware unbounded result setsStable ordering
Section titled “Stable ordering”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.