The window
window is required: 1h, 4h or 24h. Every record covers [window_start, window_end). The window ends at the newest 5-minute boundary that is at least 4 minutes old, so a response at 20:05 UTC describes the window ending at 20:00. meta.as_of names that boundary and equals every record’s window_end.
History is not served. The route refuses every parameter other than window with 400 and error_code invalid_parameter, naming it: a request with end is told that history is not served rather than silently given the current window.
Shortly after a new boundary, a response can still describe the previous one for a short time while the next is prepared. Compare meta.as_of across responses rather than assuming the newest boundary.
Routes
The Hyperliquid core route returns every listed perp. The HIP-3 route returns every HIP-3 perp with open interest above zero in the last hour. Delisted markets are not included. Records are sorted by symbol and the response is not paged. HIP-4, Spot and Lighter paths answer
404 with error_code unsupported_for_venue.
Plans and credits
Positioning comes with the Build, Pro, Scale and Enterprise plans. A Free key receives403 with error_code forbidden, the datatype (positioning), the required_plans and an upgrade_url. A refused request is not charged. Each request costs 1 credit, for every market in the response.
Example response
Response fields
Read the cross-section correctly
Null is not zero.oi_start, oi_end, mark_start and mark_end are null when their 5-minute bucket has no reading. Flows and liquidations are sums, so 0.0 there means none.
Typical moves make markets comparable. Each typical_* figure is the median absolute move over every window of the same length, sliding by 5 minutes through the last 2,000 five-minute buckets, about 6.9 days: the mark’s relative change for typical_price, the relative change in open interest for typical_oi, and the taker imbalance (buy - sell) / (buy + sell) for typical_flow. Divide a market’s move in this window by its typical move to compare a quiet market with a busy one. Under 288 counted windows the three are null.
A 503 is retryable. While the cross-section is still being prepared, the route answers 503 with error_code upstream_unavailable and Retry-After. Retry after the delay.
Positioning state
state names what open interest, taker flow and price did together, judged against the market’s own history rather than one threshold for every market:
Every window of the same length in the last 2,000 five-minute buckets gets a vector: its relative change in open interest divided by the market’s median one, and its net taker USD divided by
typical_delta. The vector’s length is the square root of the sum of their squares. bar_enter is the length at the 92nd percentile of the market’s own windows and bar_exit the length at the 80th, so only a market’s largest moves for its own size can enter a state.
The windows are walked oldest first. A window enters the state of its signs when its length reaches bar_enter and price moved the way taker flow leans. A held state continues while the next window has the same signs of open interest change and net taker flow, at a length of at least bar_exit, so a state does not switch on and off around the entry bar. A window that is not counted ends any held state. state is the state of the window that ends at window_end.
A window is counted when open interest and the mark were read, and not zero, at both of its ends, and it had at least one trade. The four fields are null in three cases:
- Under 288 counted windows, all four are null, as the typical moves are.
- When the market’s median open interest change or median net taker USD is zero,
typical_deltais served and the other three are null. - When the window ending at
window_endis not counted,stateis null.
Access
Each venue’s plans and the SDK, CLI and MCP names for the same data come fromGET /v1/capabilities. Send 0xArchive-Version: 2026-10-01 for the current response contract; see API conventions.
Stream it live
There is no positioning WebSocket channel. A new cross-section is ready every 5 minutes; poll on that cadence and checkmeta.as_of.