Skip to main content
List endpoints return one page at a time and hand you a cursor to fetch the next. There is no offset/page-number paging — cursors are stable under inserts, so you never skip or double-read a row while paging a live feed. Two cursor conventions exist in the API, depending on the endpoint:
  • Envelope cursor — most list endpoints (e.g. GET /v2/yield/opportunities) return paging state inside meta: an opaque cursor plus a has_more boolean.
  • Replay cursor — the event replay endpoint (GET /v2/events/replay) walks forward by event ID and signals the end with an empty next_cursor.
Both are documented below. Always treat the cursor as opaque: don’t parse it, build it, or persist it across schema versions — pass back exactly what the previous response gave you.

Envelope cursor (meta.cursor + meta.has_more)

GET /v2/yield/opportunities is the reference example. The response wraps its rows in the standard envelope and carries paging state in meta:

Page size

Set the page size with page[limit]. For /v2/yield/opportunities the default is 50 and the maximum is 200; a value above the maximum is clamped down rather than rejected. Page-size defaults and caps vary by endpoint — the Endpoints group in the sidebar documents each one. Request the next page by passing page[cursor] set to the previous response’s meta.cursor.
Other list families that use the envelope cursor (for example point-in-time snapshots) expose the same cursor / has_more pair in meta. The field names are identical; only the per-endpoint limit default and cap differ.

Loop until has_more is false

Keep fetching while meta.has_more is true, feeding meta.cursor back as page[cursor] each time:
Each page counts as one request against your rate limit. Use the largest limit the endpoint allows to minimize round-trips, and watch X-RateLimit-Remaining to throttle before you hit 429.

Replay cursor (next_cursor)

GET /v2/events/replay recovers events you missed during a WebSocket disconnect. It is cursor-based on event ID — not timestamp ranges. Walk forward by passing the last event’s ID as since_event_id, and stop when next_cursor comes back empty. The replay window is tier-gated. A cursor older than your tier’s window returns 410 REPLAY_WINDOW_EXPIRED, and the Free tier — which has no replay window — returns 404 REPLAY_NOT_AVAILABLE. Per-tier replay windows are in Rate limits & tiers. The response keeps its fields at the top level (it is not wrapped under data/meta):

Loop until next_cursor is empty

Pass next_cursor back as since_event_id until it comes back empty:
Replay is for recovery, not for live streaming. For ongoing updates, subscribe over WebSockets or webhooks and use replay only to backfill the gap after a reconnect.

Filtering

Filters narrow a list before it’s paged. The set below is what GET /v2/yield/opportunities accepts — other endpoints expose their own filters, documented in the Endpoints group. Filter parameters use the filter[...] bracket form; comma-separate values for the multi-value filters.
Filters apply before pagination, so meta.total reflects the filtered set, not the whole catalog. Apply the same filters on every page of a paging loop — changing them mid-loop invalidates the cursor.

Sorting

GET /v2/yield/opportunities accepts a single sort parameter. Prefix the field with - for descending order. The default sort is -tvlUsd (largest TVL first).
Sort and pagination compose: the cursor encodes your sort order, so paging stays consistent as long as you keep the same sort (and filters) across the loop.

See also

API reference overview

Base URL, auth, and the response envelope.

Rate limits & tiers

Per-tier request rates, quotas, and replay windows.

Errors

The standard error envelope and status codes.

Webhooks

Push delivery for live events.