Skip to main content
Every list endpoint paginates with cursors, not page numbers. Cursors are stable across inserts and deletes and don’t drift when the underlying ordering changes — a page-numbered API will eventually serve you a duplicate or skip a row; a cursor API won’t.

Parameters

Treat the cursor as opaque. It’s a base64-encoded payload today; that’s an implementation detail and may change.

Response shape

Every list response carries a pagination block:
  • next_cursor is the token to pass on the next request, or null if there are no more pages.
  • has_more is a boolean shortcut. Equivalent to next_cursor !== null.
When you reach the end:

Looping through everything

A few things to notice:
  • The first request omits cursor entirely. Don’t pass cursor=null or cursor= — that’s a bad_request.
  • limit=250 is the highest the API allows. You almost always want it for back-fills and full syncs; use a smaller limit for interactive UIs where time-to-first-result matters.
  • The cursor is the only state you need to persist between pages. If a sync job crashes mid-way, store the cursor and resume.

Single-resource endpoints

Endpoints that return one resource — /v1/cards/{id}, /v1/sets/{code} — don’t paginate. The pagination block on these responses is always:
…so you can read it unconditionally without special-casing list vs detail.

Errors

Cursors are bound to the path and the filter parameters that produced them. Re-using a cursor from /v1/cards?element=fire against /v1/cards?element=water is invalid_cursor. The fix: drop the cursor and start over.