Pagination and the collection envelope

Embed
Preview of the card
<a href="https://forumulate.com/reference/pagination"><img src="https://forumulate.com/reference/_api/public/orgs/046a9bc0-d530-43ae-9bae-af7945008cda/spaces/8042f004-e3d9-445f-b7a4-b6c1f86836e6/pages/d6154df7-90f8-41f8-9e8e-47b83be512b4/social-card.svg?v=3e7ae33eec8b" alt="Pagination and the collection envelope" width="600" height="315"></a>

Every collection answers the same way, so one parser serves all of them.

Ask for the envelope

Send the version you were built against:

GET /api/orgs/{orgId}/spaces/{spaceId}/items?limit=100
Forumulate-Version: 2026-09-01
{
  "items": [ { "id": "item_912", "updatedAt": "2026-08-18T04:12:09Z" } ],
  "page": { "limit": 100, "has_more": true, "next_cursor": "eyJ2IjoxLCJ1Ijoi…", "total": 4812 },
  "sync": { "checkpoint": "2026-08-18T04:12:09Z" }
}

Pass next_cursor back as cursor to continue. Sending a cursor is itself enough to get the envelope, since there is no other way to hand one back.

Why cursors, not offsets

An offset skips and duplicates rows when anything is written mid-walk — for a documentation sync that means silently losing pages. A cursor names the exact row it stopped after. The sort is (updatedAt, id): total, so two pieces saved in the same millisecond cannot straddle a page boundary with one of them never appearing.

Cursors are opaque. Store them, do not parse them; one we did not issue is refused with a 422 that says so.

Limits

limit defaults to 50 and is capped at 200 — or 50 when you include content, because every row then carries a whole piece. The cap that applied is always in page.limit, so you never have to infer it.

Callers who say nothing

A request with no Forumulate-Version, no cursor and no sync parameters gets exactly the array this endpoint has always returned, in the same order. Nothing breaks on a day we choose.

The Forumulate teamUpdated