Skip to main content
To read the next page of a list, send the response’s next_cursor as the next request’s cursor. Keep the same filters and stop when has_more is false. Treat a cursor as an opaque string: save it, URL-encode it, and send it back unchanged. Do not construct a cursor or depend on its contents.

Read the response

Event replay keeps a next_cursor even when caught up, so you can save it and ask for later events. That does not mean another page exists now. Search content, Webhooks, and Webhook events return one bounded list. They have no cursor parameter and always return has_more: false.

Choose a page size

Check the endpoint reference for its exact bounds. Live list endpoints clamp nonnegative whole-number limits into their supported range: limit=0 becomes 1, and a value above the maximum becomes the maximum. X-Effective-Query reports the applied limit. A non-integer limit returns 400 invalid_query; the sandbox also rejects numbers outside the schema’s bounds.

Send a cursor

Let your HTTP client encode the query parameters. With curl, use --data-urlencode:
Use a cursor only with the endpoint that issued it, or that endpoint’s documented alias. Preserve the filters for the entire run; changing them can invalidate the cursor or change the set you are reading.

Recover from an expired cursor

If a request returns 400 with error.reason set to cursor_expired:
  1. Discard the cursor and the rows collected for that run.
  2. Request the first page with the same filters.
  3. Continue using the new cursors.
No Retry-After is sent for this error. Waiting and resending the same cursor will not repair it. Other 400 responses can indicate a malformed cursor or parameter. Read error.reason, error.param, and error.message before restarting.

Which cursors can expire

Some lists change while you read them. The following cursors are tied to a published ranking, a snapshot, or specific request parameters: Pre-game observations use a signed cursor bound to snapshot_as_of and cohort. An edited cursor, or one reused for another cohort, returns 400. Trade lists, positions, timelines, search, explore, webhook deliveries, and suspicious trades in mode=live use row-position cursors rather than the expiring rankings above. A cursor remaining valid does not freeze the underlying data. Market-holder cursors identify an offset in a shared list and are bound to the market and filters. New cursors allow a different page size; older page-number cursors require their original size. They remain usable after the holder list refreshes.

Example: read all pages

This Python example restarts after an expired cursor and gives up after 3 attempts:

Limits

Most lists do not return a total count. A valid cursor does not promise an unchanged ranking, and there is no page-number shortcut to later pages. This handles pagination only. Add your application’s rate-limit handling before using it for a long-running job.