Skip to main content
Read public perpetual positions by wallet, account index, or market. The API provides current snapshots, historical state within the available coverage, position changes, and account and market summaries. These are read-only records derived from public venue data. They do not provide access to a private venue account, spot balances, or order execution. Authenticate with your 0xArchive API key, not a venue credential or wallet private key.
Check meta.as_of, meta.stale, and the quality fields before using a result. Current positions are periodic snapshots, not a real-time account feed. For historical reads, also check coverage and finality. See Finality and freshness and Quality.

Venues and account keys

Positions are published for Hyperliquid core perps, HIP-3 builder perps, Lighter mainnet, and Lighter on Robinhood Chain. Spot markets and HIP-4 outcome markets have no positions routes. Hyperliquid addresses are 42-character hex strings starting with 0x and are case-insensitive. Lighter paths take integer account indexes, not wallet addresses. Use the L1 address lookup to find an address’s Lighter mainnet accounts. Mainnet and Robinhood Chain account indexes are separate identifiers, even when their numbers match.

Historical coverage

A request before coverage returns 200 with an empty result, meta.coverage_from, and a meta.notice identifying the coverage start. This applies to as-of reads and change logs on every venue, and to hourly position history on both Lighter deployments. Hyperliquid and HIP-3 hourly position history before the first snapshot returns an empty page without a notice. An empty result outside coverage does not mean the account had no positions.

Routes

Every route is GET. Prefix each path with the venue namespace from the table above. Related routes:
  • GET /v1/lighter/accounts?l1_address=0x... lists the Lighter mainnet account indexes an L1 address owns. Robinhood Chain has no L1 lookup.
  • GET /v1/data-quality/positions reports, per venue, the latest live snapshot and its age, the latest hourly snapshot, built_through, and finalized_through.
See OpenAPI for the full request and response schemas.

First request

Set OXARCHIVE_API_KEY in your environment and set WALLET_ADDRESS to the public Hyperliquid address you want to query. Keep API keys in server-side code or a local shell, not browser code or source control.
The response contains data.positions and data.account. The account summary can be null; see Account summary. An empty positions result also includes data.account_seen. This illustrative response uses synthetic values. It is not a captured account response or a prediction of what your request will return.
For Lighter mainnet, set LIGHTER_ACCOUNT_INDEX to the account index returned by the L1 lookup:

Current, as-of, and reconstructed state

Without timestamp, the account positions routes return the latest snapshot. meta.stale is true, with a meta.notice, when that snapshot is more than 12 minutes old. With timestamp (epoch milliseconds), the response is the state after every event before that instant:
  • An exact UTC hour with an available hourly snapshot returns that snapshot. meta.source is snapshot.
  • Other instants return reconstructed state, with meta.source: "reconstructed". Mark price, value, and unrealized PnL describe the served instant when a mark is available. Check row quality and nullable fields rather than assuming a complete snapshot.
  • A request later than the available change history is limited to meta.built_through. The response adds meta.requested_end and meta.clamped_to so you can detect the difference.
  • An instant before coverage returns no positions, data.account_seen: "outside_coverage", a meta.notice, and meta.coverage_from.
Reconstructed responses retain the position schema, but snapshot-only values are null: meta.as_of identifies the time the returned data describes, not the request time. Market routes read snapshots only: pass hour as an exact UTC hour in epoch milliseconds, and check the resolved snapshot in meta.snapshot_ts.

Empty results

When an account holds no positions on the first page, data.account_seen says why:

Finality and freshness

Historical responses can report two time boundaries. They serve different purposes: On Lighter and Robinhood Chain, finalized_through follows the finalized trade record and usually trails the present by about a day. Change legs after that boundary carry finalized: false; Lighter position rows based on those trades also remain preliminary. Current and exact-hour account positions, current account summaries, market positions, current market summaries, and bulk pages do not carry these boundaries. Use GET /v1/data-quality/positions to check finality and snapshot age before a job. A fresh snapshot is not necessarily finalized.

Quality

Position rows and summaries carry quality; snapshot responses also report meta.quality. Change-log rows use continuity and finalized instead. meta.quality is complete, partial, or degraded. Read it together with row-level quality. A row marked complete does not establish that the entire requested history is available or finalized.

Known limits

  • History begins at the dates in Historical coverage. Earlier state is unavailable, and never_seen applies only within that coverage.
  • Recent Lighter and Robinhood Chain snapshots can report meta.quality: "degraded" while their rows are preliminary and finalized: false. Recheck quality and meta.finalized_through after finalization before using them as final historical records.
  • Hyperliquid’s published fill data has gaps in three short windows in June and July 2025. A small number of positions around those windows are marked partial.
  • Lighter rows have no leverage multiple, cumulative funding, or liquidation price: those members are null and liquidation_price_status is unavailable. Account summaries on Lighter are position aggregates only.
  • Spot markets, including Lighter spot pairs, and HIP-4 outcome markets have no positions routes. Robinhood Chain has no L1 address lookup.

Field reference

Financial values such as sizes, prices, and PnL are decimal strings, not JSON numbers. Counts and fields such as max_leverage are integers. Preserve decimal precision and treat null as unknown, not zero. Robinhood Chain monetary values are in USDG, including Lighter fields whose names contain usdc. Times in data are RFC 3339 UTC strings, with fractional seconds when non-zero. Times in meta always include milliseconds. Request parameters (timestamp, start, end, hour) use epoch milliseconds.

Position

Lighter rows add account_index (a string, because indexes can exceed JavaScript integers), account_kind (user, settlement, insurance, or system), initial_margin_fraction, allocated_margin, margin_mode, mark_source, and finalized.

Change

Each change row describes one trade, liquidation, deleverage, or settlement leg for the account, with the position before and after it. Some Lighter legs leave the position unchanged. Change-log responses use meta.source: "changes". A leg with continuity: "quarantined" is excluded from position state; do not apply it as a normal fill when processing the log. Lighter change rows add position_size_before and position_size_after, fee_rate, fee_usdc, and usdc_amount. On Robinhood Chain, fee_token is USDG and the USDC-named amount fields are in USDG.

Account summary

On an account positions response, data.account contains a summary only on the first page of an eligible snapshot read: Otherwise, including on later pages and reconstructed reads, data.account is null. All account summaries carry total_position_value, total_unrealized_pnl, long_value, short_value, n_positions, and quality. A total with any unpriced position is null, never a partial sum. Hyperliquid and HIP-3 also carry account_value, cross_account_value, collateral, total_margin_used, cross_maintenance_margin_used, withdrawable, account_mode, and snapshot_as_of. withdrawable is null outside periods where it was captured. HIP-3 summaries are scoped to one dex. Lighter summaries identify the account with account_index and contain position aggregates only, not account balances.

Market rows and summaries

Market and bulk rows carry the account key (user_address on Hyperliquid, account_index and account_kind on Lighter), symbol, size, side, entry_price, mark_price, position_value, unrealized_pnl, leverage_type, liquidation_price, and quality. The first page of /positions/{symbol} adds meta.totals for the whole filtered set. Market summaries carry long_count, short_count, long_size, short_size, long_value, short_value, long_avg_entry_price, short_avg_entry_price, long_positions_with_entry, short_positions_with_entry, long_top10_value_share, short_top10_value_share, top10_value_share, and quality.

Parameters

Market summary routes accept a limit parameter up to 2,000, but a history page contains at most 168 hourly points. Follow the returned cursor for the remaining hours.

Pagination

Pass meta.next_cursor back as cursor, keeping the route and all other parameters unchanged. Stop when no next cursor is returned. Treat cursors as opaque values; do not decode or modify them. They expire after 24 hours. Reusing a cursor with different parameters returns invalid_cursor. Market and bulk pages use the same snapshot throughout pagination. If that snapshot is no longer available, the next page returns 409 with snapshot_advanced. Restart from the first page without a cursor; do not combine pages from the old and new snapshots. History pages can end on an hour boundary with fewer than limit rows and still have a next cursor. A short page does not mean you have reached the end.

Bulk export in Arrow

Request Arrow on a bulk route with format=arrow or Accept: application/vnd.apache.arrow.stream. An Arrow response is an Apache Arrow IPC stream with up to 50,000 rows per page. It has no JSON envelope: read x-count, x-next-cursor, and x-schema-version from the response headers. The schema version is positions.v1. Always check the response Content-Type before parsing. The route returns JSON if Arrow output is not enabled, even when you requested Arrow.

Market-wide positioning

Rows are sorted by position value, largest first. On Lighter, pass include_system=true to include settlement, insurance, and other system accounts. /positions/{symbol}/summary without start or end returns one summary for the latest snapshot; with a window it returns one summary per available hour.

Lighter L1 address lookup

Set WALLET_ADDRESS to the L1 address you want to look up:
data holds l1_address, total_accounts, and accounts, each with account_index, account_type, and first_seen. The lookup covers Lighter mainnet only.

SDKs

Positions resources are available in SDK version 1.12.0 and later for Python, TypeScript, and Rust. The examples below use OXARCHIVE_API_KEY and WALLET_ADDRESS from your environment. See SDK installation and REST usage for setup and language-specific method names.

Billing and caching

Position routes cost one credit per 1,000 rows returned, with a minimum of one credit per request. Account summary routes and the Lighter L1 lookup cost one credit per request. Your plan’s history window applies to timestamp, hour, and [start, end). When caching results, retain their timestamps, quality, and finality metadata. A cached current response still describes its original meta.as_of, and preliminary history should be refreshed after finalization.

Errors

Errors use the standard error body with code, error, param when a parameter is at fault, and an error_code for the cases below.

Common mistakes

  • Treating data.account_seen: "never_seen" as evidence that an account never traded. It is scoped to covered history.
  • Reading the null members of a reconstructed row as zero, or typing leverage as nullable and leverage.type as only cross or isolated. A reconstruction keeps the leverage and cum_funding objects, with leverage.type set to unknown on Hyperliquid and HIP-3, and its null values mean unknown, not zero.
  • Joining Lighter account indexes across mainnet and Robinhood Chain. They are separate account spaces.
  • Paging with changed parameters. A cursor belongs to the exact request that issued it.
Use Trades for the fills behind each change, Liquidations for liquidation events, Lighter on Robinhood Chain REST for that deployment’s market data, and Data quality before a long job.
Last modified on September 28, 2026