Pagination
When it applies
Pagination only applies to table-shaped tools: endpoints that return rows, one per record. Aggregation tools (Net Drift, Net Flow, Gainers / Losers, Heat Map, …) return a complete result for the requested window in a single response; there is nothing to page through.
/v1/options/tool/order-flow/consolidated: blocks, splits, sweeps, and their comprising trades./v1/options/tool/order-flow/unconsolidated: trade-by-trade option tape./v1/equities/tool/equity-prints: trade-by-trade equity tape (lit and dark venues).
Page size
The size request field controls how many rows come back per page. It is bounded so a single request cannot ask the server for an unbounded result set.
sizeis optional. Omitted requests get50rows.- Valid range is
1–100inclusive. Anything outside that returns a400 · validationresponse naming the offending field. - The chosen size applies to every page in a walk; the cursor does not carry it. Setting
size: 25on the first request andsize: 100on the next is allowed but unusual. - A short final page does not signal the end on its own. Only a
nullnextSearchAfterin the response means there is nothing else to fetch.
The cursor
Each response carries nextSearchAfter, an opaque cursor. Pass it back as searchAfter on the next request to continue where the previous page ended. null means there is no next page.
nextSearchAfteris a list of strings. The shape is intentionally opaque; its meaning is an implementation detail and is not stable across endpoints or versions.- Pass the value back verbatim as
searchAfteron the next request. Do not parse, edit, or transcribe it across requests with different filter or sort fields. - Cursors are tied to the request that produced them. Changing the filter, the sort, the session date, or the time range between pages can produce duplicate or skipped rows.
- On the first request,
searchAfterisnull(or omitted entirely).
Walking a result set
Three requests walk a result set start to finish: the first page (no cursor), the second page (paste back the cursor), and the last page (cursor comes back as null).
searchAfter. The server returns the first size rows along with a nextSearchAfter cursor.searchAfter set to the prior response's nextSearchAfter. Repeat until nextSearchAfter comes back as null.null cursor is the only signal that the walk is complete. A response shorter than size on its own does not mean the end; that can happen mid-walk too.First page · request
// First page: no searchAfter. { "sessionDate": "2026-05-13", "filter": { "tickers": ["AAPL"] }, "size": 50, "sort": { "field": "tradeTime", "direction": "DESCENDING" } }
First page · response (truncated)
{ "nextSearchAfter": [ "1747144203000", "9f7f7d52-..." ], "prints": [ { "ticker": "AAPL", "price": 185.41, "size": 100, "tradeTime": 1747144203000, "...": "..." } // ... 49 more ] }
Next page · request
// Next page: paste the prior response's nextSearchAfter verbatim. { "sessionDate": "2026-05-13", "filter": { "tickers": ["AAPL"] }, "size": 50, "sort": { "field": "tradeTime", "direction": "DESCENDING" }, "searchAfter": [ "1747144203000", "9f7f7d52-..." ] }
Final page · response
// nextSearchAfter is null on the last page: stop paging. { "nextSearchAfter": null, "prints": [ { "ticker": "AAPL", "price": 184.92, "size": 200, "tradeTime": 1747147800000, "...": "..." } // ... fewer than 'size' rows if you ran out before filling the page. ] }
Sort and stability
The cursor encodes the sort. Pagination is stable across page boundaries only when the filter, sort, and time window stay the same between requests. Changing any of them invalidates the cursor.
Each paginated tool has a default sort. For the tape endpoints, that is tradeTime DESCENDING. You can override it via sort on the first request, then keep paging with the same sort to walk the result set in that order. Mid-walk sort changes are not supported; start a new walk with a fresh first request instead.
A note on duplicates: if new rows arrive in the underlying data store between page N and page N+1, you can see the same row twice across pages; the cursor is positional, not a snapshot. For walks that need to be perfectly snapshot-consistent, narrow the time range to a window that has already closed (a past session date, or a timeRange whose endTime is in the past).