Skip to main content
Every list endpoint returns the same envelope:

Walking pages

Stop when has_more is false. At that point next_cursor is null. Passing both returns 400 conflicting_cursors.

Cursors are opaque

A cursor is base64url and encodes an ordering position. Do not parse, construct or modify one — a cursor we did not issue returns 400 invalid_cursor rather than an empty page, so a mangled cursor fails loudly instead of looking like the end of the list.

Why no offset

?page=47 degrades as the offset grows — the database counts past every skipped row — and it is wrong in a way that is hard to see: records arrive while you are reading. Calls complete, usage rows land. With an offset, an insertion shifts every later page and you silently re-read or skip records. A cursor names a position in the ordering, so it stays correct regardless of what arrives. Once an offset parameter is documented it cannot be withdrawn without breaking clients, which is why there has never been one here.