oxarchive

August 31, 2026 · View on GitHub

Crates.io Docs.rs License: MIT

Rust client for async services that need typed 0xArchive market data.

0xArchive is granular market data infrastructure for Hyperliquid and Lighter.xyz. Hyperliquid includes core perps (/v1/hyperliquid), HIP-3 builder perps (/v1/hyperliquid/hip3), HIP-4 outcome markets (/v1/hyperliquid/hip4), and Hyperliquid Spot (/v1/hyperliquid/spot). Lighter.xyz is the second top-level venue API at /v1/lighter.

Use this SDK when the integration belongs in an async Rust service, data system, backtest runner, or strongly typed market-data pipeline.

Installation

cargo add oxarchive

Or add directly to your Cargo.toml:

[dependencies]
oxarchive = "1.9"
tokio = { version = "1", features = ["rt-multi-thread", "macros"] }

For WebSocket support (real-time streaming, replay, bulk download):

oxarchive = { version = "1.9", features = ["websocket"] }

Quick Start

use oxarchive::OxArchive;

#[tokio::main]
async fn main() -> oxarchive::Result<()> {
    let client = OxArchive::new("0xa_your_api_key")?;

    // First successful call: Hyperliquid BTC order book
    let ob = client.hyperliquid.orderbook.get("BTC", None).await?;
    println!("Hyperliquid BTC mid price: {:?}", ob.mid_price);

    // Lighter.xyz uses its own venue client
    let lighter_ob = client.lighter.orderbook.get("BTC", None).await?;
    println!("Lighter BTC mid price: {:?}", lighter_ob.mid_price);

    // Hyperliquid HIP-3 builder perps stay under client.hyperliquid.hip3
    let hip3 = client.hyperliquid.hip3.instruments.list().await?;
    let hip3_ob = client.hyperliquid.hip3.orderbook.get("km:US500", None).await?;
    let hip3_funding = client.hyperliquid.hip3.funding.current("xyz:XYZ100").await?;

    // Hyperliquid Spot stays under client.hyperliquid.spot (dashed canonical pairs)
    let pairs = client.hyperliquid.spot.pairs.list().await?;
    let hype_ob = client.hyperliquid.spot.orderbook.get("HYPE-USDC", None).await?;
    println!("HYPE-USDC mid price: {:?}", hype_ob.mid_price);

    // Historical order book snapshots
    use oxarchive::resources::orderbook::OrderBookHistoryParams;
    let history = client.hyperliquid.orderbook.history("ETH", OrderBookHistoryParams {
        start: 1704067200000_i64.into(),
        end: 1704153600000_i64.into(),
        cursor: None,
        limit: Some(100),
        depth: None,
        granularity: None,
    }).await?;

    Ok(())
}

Choose Your Next Path

NeedLink
First authenticated routeQuick Start
SDK install and route docsSDK docs
Claude Code, ChatGPT Codex, and coding-agent workflowsAI Clients
File-based historical pullsData Catalog
Route contract and machine contextOpenAPI, llms.txt

Use From Coding Agents

When prototyping Rust services from Claude Code, ChatGPT Codex, or another coding agent, also install the 0xArchive skill so the agent has typed API context and example patterns for every endpoint. The skill installs into .claude/skills/0xarchive (Claude Code) or .agents/skills/0xarchive (ChatGPT Codex). For shell-driven exploration alongside the SDK, the CLI and the hosted MCP share the same API key.

Data Coverage

VenueCoverageNotes
HyperliquidApril 2023+Core perpetuals; coverage varies by schema and route.
Hyperliquid HIP-3February 2026+ for served historyBuilder perps; funding and OI update at roughly 10 seconds.
Hyperliquid HIP-4May 2, 2026+Candles and outcome-side OI are served from 2026-05-02; OI updates at ~10s. No funding or liquidations.
Hyperliquid SpotTrades March 2025+; candles from exactly 2025-03-22T10:50:22Z; orderbook, L4, TWAP, and freshness from May 2026326 authenticated inventory rows using dashed symbols (HYPE-USDC, PURR-USDC, ...). No funding, OI, or liquidations.
Lighter.xyzCandles from 2025-08-01; observed global per-fill trade floor August 27, 2025; exact starts vary by market. L3 from March 5, 2026+Maker/taker trade context; L3 caps at 250 orders per side; funding/OI update at ~10s.

Configuration

use oxarchive::OxArchive;
use std::time::Duration;

let client = OxArchive::builder("0xa_your_api_key")
    .base_url("https://api.0xarchive.io")  // Optional
    .timeout(Duration::from_secs(60))       // Optional (default: 30s)
    .build()?;

REST API Reference

The sections below show which resources are available on each exchange client:

Resourceclient.hyperliquidclient.hyperliquid.hip3client.hyperliquid.spotclient.lighter
orderbookYesYesYesYes
tradesYesYesYesYes
instrumentsYesYes-- (use pairs)Yes
pairs----Yes--
fundingYesYes--Yes
open_interestYesYes--Yes
candlesYesYesYesYes
liquidationsYesYes----
ordersYesYesYes--
l4_orderbookYesYesYes--
l2_orderbookYesYes----
l3_orderbook------Yes
twap----Yes--
freshness()YesYesYesYes
summary()YesYes--Yes
price_history()YesYes--Yes

Order Book

use oxarchive::resources::orderbook::{GetOrderBookParams, OrderBookHistoryParams};

// Get current order book
let ob = client.hyperliquid.orderbook.get("BTC", None).await?;
println!("Mid price: {:?}", ob.mid_price);
println!("Best bid: {:?}", ob.bids.first());
println!("Best ask: {:?}", ob.asks.first());

// Get with specific timestamp and depth
let ob = client.hyperliquid.orderbook.get("BTC", Some(GetOrderBookParams {
    timestamp: Some(1704067200000_i64.into()),
    depth: Some(20),
})).await?;

// Get historical snapshots
let history = client.hyperliquid.orderbook.history("BTC", OrderBookHistoryParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: Some(1000),
    depth: None,
    granularity: None,
}).await?;

Orderbook Depth

Depth is route-specific. Hyperliquid-family native L2 is capped at 20 levels per side. Lighter native L2 includes all served levels, and Lighter L3 is capped at 250 orders per side.

Note: Dedicated L2 routes derived from L4 return all served levels where supported. Lighter L3 exposes individual resting orders rather than price levels and begins March 5, 2026.

Lighter Orderbook Granularity

Lighter.xyz orderbook history supports a granularity parameter for different data resolutions:

use oxarchive::types::LighterGranularity;

let history = client.lighter.orderbook.history("BTC", OrderBookHistoryParams {
    start: 1769904000000_i64.into(), // 2026-02-01 00:00 UTC
    end: 1769990400000_i64.into(),   // 2026-02-02 00:00 UTC
    cursor: None,
    limit: None,
    depth: None,
    granularity: Some(LighterGranularity::TenSeconds),
}).await?;
GranularityIntervalCredit Multiplier
Checkpoint~60s1x
ThirtySeconds30s2x
TenSeconds10s3x
OneSecond1s10x
Ticktick-level20x

Orderbook Reconstruction

Tick-level orderbook history returns a full checkpoint plus incremental deltas, allowing you to reconstruct the exact state of the order book at every tick. This is the most granular data available and is ideal for backtesting, market microstructure research, and latency analysis.

use oxarchive::OxArchive;
use oxarchive::orderbook_reconstructor::OrderBookReconstructor;
use oxarchive::types::ReconstructOptions;

let client = OxArchive::new("your-api-key")?;

// Option 1: One-shot — fetch and reconstruct in one call
let snapshots = client.lighter.orderbook.history_reconstructed(
    "BTC",
    1769904000000_i64,  // start (2026-02-01 00:00 UTC)
    1769907600000_i64,  // end (2026-02-01 01:00 UTC)
    Some(20),           // depth (top 20 levels per side)
    true,               // emit_all: snapshot after every tick
).await?;

for snapshot in &snapshots {
    println!("{}: mid={:?}, spread={:?}bps, seq={:?}",
        snapshot.timestamp, snapshot.mid_price, snapshot.spread_bps, snapshot.sequence);
}

// Option 2: Auto-paginated — fetches all pages automatically
let all_snapshots = client.lighter.orderbook.collect_tick_history(
    "BTC",
    1769904000000_i64, // 2026-02-01 00:00 UTC
    1769990400000_i64, // 2026-02-02 00:00 UTC
    Some(20),
).await?;
println!("{} tick-level snapshots", all_snapshots.len());

// Option 3: Manual control — fetch raw tick data and reconstruct yourself
let tick_data = client.lighter.orderbook.history_tick(
    "BTC", 1769904000000_i64, 1769907600000_i64, None,
).await?;

// Check data integrity
let gaps = OrderBookReconstructor::detect_gaps(&tick_data.deltas);
if !gaps.is_empty() {
    eprintln!("Sequence gaps detected: {:?}", gaps);
}

// Reconstruct with full control
let mut reconstructor = OrderBookReconstructor::new();
reconstructor.initialize(&tick_data.checkpoint);

for delta in &tick_data.deltas {
    reconstructor.apply_delta(delta);
    let snapshot = reconstructor.get_snapshot(Some(10));
    // Process each snapshot...
}

// Or get just the final state (most efficient)
let final_state = reconstructor.reconstruct_final(
    &tick_data.checkpoint, &tick_data.deltas, Some(20),
);
println!("Final mid price: {:?}", final_state.mid_price);

Manual Pagination

For large time ranges where memory is a concern, paginate manually instead of using collect_tick_history:

let mut cursor = 1769904000000_i64; // 2026-02-01 00:00 UTC
let end = 1769990400000_i64; // 2026-02-02 00:00 UTC;

while cursor < end {
    let tick_data = client.lighter.orderbook.history_tick(
        "BTC", cursor, end, Some(20),
    ).await?;

    if tick_data.deltas.is_empty() {
        break;
    }

    // Process this page...
    let mut reconstructor = OrderBookReconstructor::new();
    let final_state = reconstructor.reconstruct_final(
        &tick_data.checkpoint, &tick_data.deltas, Some(20),
    );
    println!("{}: {} bids, {} asks", final_state.timestamp, final_state.bids.len(), final_state.asks.len());

    // Advance cursor past the last delta
    let last_ts = tick_data.deltas.iter().map(|d| d.timestamp).max().unwrap();
    cursor = last_ts + 1;

    // Fewer than ~1000 deltas means end of range
    if tick_data.deltas.len() < 1000 {
        break;
    }
}

Trades

Cursor-based pagination for efficient retrieval of large datasets.

use oxarchive::resources::trades::GetTradesParams;

// Get trades with pagination
let result = client.hyperliquid.trades.list("BTC", GetTradesParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    limit: Some(1000),
    cursor: None,
    side: None,
}).await?;

// Paginate through all results
let mut all_trades = result.data;
let mut cursor = result.next_cursor;
while let Some(c) = cursor {
    let page = client.hyperliquid.trades.list("BTC", GetTradesParams {
        start: 1704067200000_i64.into(),
        end: 1704153600000_i64.into(),
        limit: Some(1000),
        cursor: Some(c),
        side: None,
    }).await?;
    all_trades.extend(page.data);
    cursor = page.next_cursor;
}

// Get recent trades (Lighter and HIP-3 only)
let recent = client.lighter.trades.recent("BTC", Some(100)).await?;
let hip3_recent = client.hyperliquid.hip3.trades.recent("km:US500", Some(50)).await?;

Note: The recent() method is available for Lighter.xyz and HIP-3 only. Hyperliquid does not have a recent trades endpoint — use list() with a time range instead.

Instruments

// List all Hyperliquid instruments
let instruments = client.hyperliquid.instruments.list().await?;
for inst in &instruments {
    println!("{}: {}x leverage", inst.name, inst.max_leverage.unwrap_or(0));
}

// Get specific instrument
let btc = client.hyperliquid.instruments.get("BTC").await?;

// Lighter.xyz instruments (different schema with fees, market IDs)
let lighter_instruments = client.lighter.instruments.list().await?;
for inst in &lighter_instruments {
    println!("{}: taker_fee={:?}, maker_fee={:?}", inst.symbol, inst.taker_fee, inst.maker_fee);
}

// HIP-3 instruments (derived from live data, includes mark price + OI)
let hip3_instruments = client.hyperliquid.hip3.instruments.list().await?;
for inst in &hip3_instruments {
    println!("{} ({}:{}): mark={:?}", inst.coin, inst.namespace, inst.ticker, inst.mark_price);
}

Funding Rates

use oxarchive::resources::funding::FundingHistoryParams;
use oxarchive::types::OiFundingInterval;

// Get current funding rate
let current = client.hyperliquid.funding.current("BTC").await?;
println!("Funding rate: {}", current.funding_rate);

// Get history with aggregation interval
let history = client.hyperliquid.funding.history("ETH", FundingHistoryParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: None,
    interval: Some(OiFundingInterval::OneHour),
}).await?;

Aggregation Intervals

IntervalDescription
5m5 minutes
15m15 minutes
30m30 minutes
1h1 hour
4h4 hours
1d1 day

Raw cadence is route-specific: Hyperliquid core funding is ~1 minute; HIP-3 and Lighter funding are ~10 seconds. HIP-4 has no funding. HIP-3, HIP-4 outcome-side OI, and Lighter OI are also ~10 seconds.

Open Interest

use oxarchive::resources::open_interest::OpenInterestHistoryParams;
use oxarchive::types::OiFundingInterval;

// Get current open interest
let current = client.hyperliquid.open_interest.current("BTC").await?;
println!("Open interest: {}", current.open_interest);

// Get history with aggregation
let history = client.hyperliquid.open_interest.history("BTC", OpenInterestHistoryParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: None,
    interval: Some(OiFundingInterval::OneHour),
}).await?;

Liquidations (Hyperliquid and HIP-3)

Historical liquidation events from May 2025 onwards. Available on client.hyperliquid.liquidations and client.hyperliquid.hip3.liquidations.

use oxarchive::resources::liquidations::*;

// Get liquidation history
let liquidations = client.hyperliquid.liquidations.history("BTC", LiquidationHistoryParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: None,
}).await?;

// Get liquidations for a specific user
let user_liq = client.hyperliquid.liquidations.by_user("0x1234...", LiquidationsByUserParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    coin: Some("BTC".to_string()),
    cursor: None,
    limit: None,
}).await?;

// Get pre-aggregated liquidation volume (100-1000x less data)
let volume = client.hyperliquid.liquidations.volume("BTC", LiquidationVolumeParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    interval: Some("1h".to_string()),
    cursor: None,
    limit: None,
}).await?;
for bucket in &volume.data {
    println!("total=${}, long=${}, short=${}", bucket.total_usd, bucket.long_usd, bucket.short_usd);
}

// HIP-3 liquidations (same API, different exchange prefix)
let hip3_liqs = client.hyperliquid.hip3.liquidations.history("km:US500", LiquidationHistoryParams {
    start: 1772323200000_i64.into(), // 2026-03-01 00:00 UTC
    end: 1772409600000_i64.into(),   // 2026-03-02 00:00 UTC
    cursor: None,
    limit: None,
}).await?;

let hip3_vol = client.hyperliquid.hip3.liquidations.volume("km:US500", LiquidationVolumeParams {
    start: 1772323200000_i64.into(), // 2026-03-01 00:00 UTC
    end: 1772409600000_i64.into(),   // 2026-03-02 00:00 UTC
    interval: Some("1h".to_string()),
    cursor: None,
    limit: None,
}).await?;

Candles (OHLCV)

use oxarchive::resources::candles::CandleHistoryParams;
use oxarchive::types::CandleInterval;

let candles = client.hyperliquid.candles.history("BTC", CandleHistoryParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    interval: Some(CandleInterval::OneHour),
    cursor: None,
    limit: None,
}).await?;

for candle in &candles.data {
    println!("O={} H={} L={} C={} V={}", candle.open, candle.high, candle.low, candle.close, candle.volume);
}

Available Intervals

1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w

Lighter candle history is served from 2025-08-01. HIP-4 candle history is served from 2026-05-02 and accepts at most 1,000 rows per page.

let lighter_candles = client.lighter.candles.history("BTC", CandleHistoryParams {
    start: 1754006400000_i64.into(), // 2025-08-01 00:00 UTC
    end: 1754092800000_i64.into(),   // 2025-08-02 00:00 UTC
    cursor: None,
    limit: Some(1000),
    interval: Some(CandleInterval::OneHour),
}).await?;

Orders (Hyperliquid and HIP-3)

Order history, order flow aggregation, and TP/SL order queries. Available on client.hyperliquid.orders and client.hyperliquid.hip3.orders.

use oxarchive::resources::orders::*;

// Get order history for a symbol
let orders = client.hyperliquid.orders.history("BTC", OrderHistoryParams {
    start: Some(1704067200000_i64.into()),
    end: Some(1704153600000_i64.into()),
    user: None,
    status: None,
    order_type: None,
    cursor: None,
    limit: Some(1000),
}).await?;

// Filter by user address
let user_orders = client.hyperliquid.orders.history("BTC", OrderHistoryParams {
    start: Some(1704067200000_i64.into()),
    end: Some(1704153600000_i64.into()),
    user: Some("0x1234...".to_string()),
    status: Some("filled".to_string()),
    order_type: None,
    cursor: None,
    limit: None,
}).await?;

// Get aggregated order flow
let flow = client.hyperliquid.orders.flow("BTC", OrderFlowParams {
    start: Some(1704067200000_i64.into()),
    end: Some(1704153600000_i64.into()),
    interval: Some("1h".to_string()),
    limit: None,
}).await?;

// Get TP/SL (take-profit / stop-loss) orders
let tpsl = client.hyperliquid.orders.tpsl("BTC", TpslParams {
    start: Some(1704067200000_i64.into()),
    end: Some(1704153600000_i64.into()),
    user: None,
    triggered: Some(true),
    cursor: None,
    limit: None,
}).await?;

// HIP-3 orders
let hip3_orders = client.hyperliquid.hip3.orders.history("km:US500", OrderHistoryParams::default()).await?;

L4 Orderbook (Hyperliquid and HIP-3)

Node-level L4 orderbook data with user attribution. Available on client.hyperliquid.l4_orderbook and client.hyperliquid.hip3.l4_orderbook.

use oxarchive::resources::l4_orderbook::*;

// Get current L4 orderbook snapshot
let l4 = client.hyperliquid.l4_orderbook.get("BTC", None).await?;

// Get with specific timestamp and depth
let l4 = client.hyperliquid.l4_orderbook.get("BTC", Some(L4OrderBookParams {
    timestamp: Some(1704067200000_i64.into()),
    depth: Some(20),
})).await?;

// Get paginated L4 orderbook diffs
let diffs = client.hyperliquid.l4_orderbook.diffs("BTC", L4DiffsParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: Some(1000),
}).await?;

// Get paginated L4 orderbook history
let history = client.hyperliquid.l4_orderbook.history("BTC", L4HistoryParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: Some(1000),
    depth: Some(20),
}).await?;

// HIP-3 L4 orderbook
let hip3_l4 = client.hyperliquid.hip3.l4_orderbook.get("km:US500", None).await?;
let hip3_diffs = client.hyperliquid.hip3.l4_orderbook.diffs("km:US500", L4DiffsParams {
    start: 1772323200000_i64.into(), // 2026-03-01 00:00 UTC
    end: 1772409600000_i64.into(),   // 2026-03-02 00:00 UTC
    cursor: None,
    limit: None,
}).await?;

L2 Orderbook (Hyperliquid and HIP-3)

Full-depth L2 orderbook derived from L4 data. Available on client.hyperliquid.l2_orderbook and client.hyperliquid.hip3.l2_orderbook.

use oxarchive::resources::l2_orderbook::*;

// Get current L2 full-depth orderbook
let l2 = client.hyperliquid.l2_orderbook.get("BTC", None).await?;

// Get L2 orderbook at a specific timestamp
let l2 = client.hyperliquid.l2_orderbook.get("BTC", Some(L2OrderBookParams {
    timestamp: Some(1704067200000_i64.into()),
    depth: Some(50),
})).await?;

// Get L2 orderbook history
let l2_history = client.hyperliquid.l2_orderbook.history("BTC", L2HistoryParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: Some(1000),
    depth: Some(50),
}).await?;

// Get L2 tick-level diffs
let l2_diffs = client.hyperliquid.l2_orderbook.diffs("BTC", L2DiffsParams {
    start: 1704067200000_i64.into(),
    end: 1704153600000_i64.into(),
    cursor: None,
    limit: Some(1000),
}).await?;

// HIP-3 L2 orderbook
let hip3_l2 = client.hyperliquid.hip3.l2_orderbook.get("km:US500", None).await?;

L3 Orderbook (Lighter only)

Order-level L3 orderbook data showing individual orders. Available on client.lighter.l3_orderbook.

use oxarchive::resources::l3_orderbook::L3HistoryParams;

// Get current L3 orderbook
let l3 = client.lighter.l3_orderbook.get("BTC", None).await?;

// Get with depth limit
let l3 = client.lighter.l3_orderbook.get("BTC", Some(20)).await?;

// Get paginated L3 orderbook history
let history = client.lighter.l3_orderbook.history("BTC", L3HistoryParams {
    start: 1772668800000_i64.into(), // 2026-03-05 00:00 UTC
    end: 1772755200000_i64.into(),   // 2026-03-06 00:00 UTC
    cursor: None,
    limit: Some(1000),
}).await?;

HIP-4 Outcome Markets (Hyperliquid)

Binary outcome perps deployed under the Hyperliquid namespace. Coin symbols use the bare #<10*outcome_id + side> form (#0, #1, #55850, ...). The SDK accepts the bare form and percent-encodes # only for URL wire transport. Use the bare form in your code; do not pre-encode # to %23.

HIP-4 candles and outcome-side OI are served from 2026-05-02, with raw OI updates at ~10s. HIP-4 has no funding rates and no liquidations. mark_price on HIP-4 is an implied probability in [0, 1], not a USD price.

use oxarchive::exchanges::{Hip4HistoryRange, Hip4ListOutcomesParams,
    Hip4OrderBookParams, Hip4TradesParams};
use oxarchive::resources::candles::CandleHistoryParams;
use oxarchive::types::CandleInterval;

// Outcomes (per-outcome view, both sides combined)
let outcomes = client.hyperliquid.hip4.list_outcomes(None).await?;
for o in &outcomes.data {
    println!("{} . {:?}", o.outcome_id, o.display_title);
}

// Filter by settlement state OR by slug
let live = client.hyperliquid.hip4.list_outcomes(Some(Hip4ListOutcomesParams {
    is_settled: Some(false),
    slug: None,
    cursor: None,
    limit: Some(50),
})).await?;

let one = client.hyperliquid.hip4
    .get_outcome_by_slug("btc-above-78213-may-04-0600").await?;
println!("aggregated_oi: {:?}", one.aggregated_oi);

// Outcome detail (with aggregated_oi)
let detail = client.hyperliquid.hip4.get_outcome(5585).await?;

// Per-side instruments (`#0`, `#1`, ...)
let insts = client.hyperliquid.hip4.get_instruments().await?;
let inst = client.hyperliquid.hip4.get_instrument("#0").await?;

// L2 orderbook
let ob = client.hyperliquid.hip4.get_orderbook("#0", None).await?;
let ob_at = client.hyperliquid.hip4.get_orderbook("#0", Some(Hip4OrderBookParams {
    timestamp: Some(1777680000000_i64.into()),
    depth: Some(20),
})).await?;
let ob_history = client.hyperliquid.hip4.get_orderbook_history("#0", Hip4HistoryRange {
    start: 1777680000000_i64.into(),
    end:   1777766400000_i64.into(),
    cursor: None,
    limit: Some(100),
}).await?;

// Trades (history + recent)
let trades = client.hyperliquid.hip4.get_trades("#0", Hip4TradesParams {
    start: 1777680000000_i64.into(),
    end:   1777766400000_i64.into(),
    cursor: None,
    limit: Some(1000),
    side: None,
}).await?;
let recent = client.hyperliquid.hip4.get_trades_recent("#0", Some(50)).await?;

// Implied-probability OHLCV candles
let candles = client.hyperliquid.hip4.candles.history("#0", CandleHistoryParams {
    start: 1777680000000_i64.into(),
    end: 1777766400000_i64.into(),
    cursor: None,
    limit: Some(1000),
    interval: Some(CandleInterval::OneHour),
}).await?;

// Open interest (per-side history + latest)
let oi_hist = client.hyperliquid.hip4.get_open_interest("#0", Hip4HistoryRange {
    start: 1777680000000_i64.into(),
    end:   1777766400000_i64.into(),
    cursor: None,
    limit: None,
}).await?;
let oi_now = client.hyperliquid.hip4.get_open_interest_current("#0").await?;
// mark_price on HIP-4 is an implied probability in [0, 1].

// Summary, freshness, prices
let summary    = client.hyperliquid.hip4.get_summary("#0").await?;
let freshness  = client.hyperliquid.hip4.get_freshness("#0").await?;
let prices     = client.hyperliquid.hip4.get_prices("#0",
    1777680000000_i64, 1777766400000_i64, Some("1h"), Some(100), None).await?;

// L4 (current snapshot, diffs, checkpoint history)
let l4_now     = client.hyperliquid.hip4.get_l4_orderbook("#0", None).await?;
let l4_diffs   = client.hyperliquid.hip4.get_l4_diffs("#0", Hip4HistoryRange {
    start: 1777680000000_i64.into(),
    end:   1777766400000_i64.into(),
    cursor: None,
    limit: Some(1000),
}).await?;

Hyperliquid Spot

Spot trading pairs deployed under the Hyperliquid namespace. Symbols use the dashed canonical form (HYPE-USDC, PURR-USDC, ...). The server resolves the dashed form to the wire format (PURR/USDC, @107) internally.

Spot has no funding, no open interest, and no liquidations. Trade history backfills to 2025-03-22. Spot candle history starts exactly at 2025-03-22T10:50:22Z, supports 1m, 5m, 15m, 30m, 1h, 4h, 1d, and 1w, and accepts at most 1,000 rows per page. Orderbook, L4, TWAP, and freshness data are live-only from 2026-05-05.

use oxarchive::resources::orderbook::{GetOrderBookParams, OrderBookHistoryParams};
use oxarchive::resources::l4_orderbook::{L4DiffsParams, L4HistoryParams, L4OrderBookParams};
use oxarchive::resources::orders::OrderHistoryParams;
use oxarchive::resources::candles::CandleHistoryParams;
use oxarchive::resources::spot::SpotTwapParams;
use oxarchive::resources::trades::GetTradesParams;
use oxarchive::types::CandleInterval;

// Pair discovery (dashed canonical: HYPE-USDC, PURR-USDC, ...).
let pairs = client.hyperliquid.spot.pairs.list().await?;
let hype = client.hyperliquid.spot.pairs.get("HYPE-USDC").await?;

// Current L2 orderbook.
let ob = client.hyperliquid.spot.orderbook.get("HYPE-USDC", None).await?;
println!("HYPE-USDC mid: {:?}", ob.mid_price);

// Historical L2 orderbook.
let ob_history = client.hyperliquid.spot.orderbook.history("HYPE-USDC", OrderBookHistoryParams {
    start: 1746489600000_i64.into(), // 2026-05-06 UTC
    end:   1746576000000_i64.into(),
    cursor: None,
    limit: Some(1000),
    depth: None,
    granularity: None,
}).await?;

// Candles (history starts exactly at 2025-03-22T10:50:22Z; max 1,000 rows).
let candles = client.hyperliquid.spot.candles.history("HYPE-USDC", CandleHistoryParams {
    start: 1742640622000_i64.into(), // 2025-03-22T10:50:22Z
    end:   1742644222000_i64.into(),
    cursor: None,
    limit: Some(1000),
    interval: Some(CandleInterval::OneMinute),
}).await?;

// Trades (history backfilled to 2025-03-22).
let trades = client.hyperliquid.spot.trades.list("PURR-USDC", GetTradesParams {
    start: 1742601600000_i64.into(), // 2025-03-22 UTC
    end:   1746576000000_i64.into(),
    cursor: None,
    limit: Some(1000),
    side: None,
}).await?;

// L4 reconstruction.
let l4_now = client.hyperliquid.spot.l4_orderbook.get("HYPE-USDC", None).await?;
let l4_diffs = client.hyperliquid.spot.l4_orderbook.diffs("HYPE-USDC", L4DiffsParams {
    start: 1746489600000_i64.into(),
    end:   1746576000000_i64.into(),
    cursor: None,
    limit: Some(1000),
}).await?;
let l4_history = client.hyperliquid.spot.l4_orderbook.history("HYPE-USDC", L4HistoryParams {
    start: 1746489600000_i64.into(),
    end:   1746576000000_i64.into(),
    cursor: None,
    limit: Some(10),
    depth: Some(20),
}).await?;

// Order lifecycle events.
let orders = client.hyperliquid.spot.orders.history("HYPE-USDC", OrderHistoryParams::default()).await?;

// TWAP statuses by symbol or by user.
let twap_sym = client.hyperliquid.spot.twap
    .by_symbol("HYPE-USDC", SpotTwapParams::default()).await?;
let twap_user = client.hyperliquid.spot.twap
    .by_user("0x1234...", SpotTwapParams::default()).await?;

// Per-table freshness.
let freshness = client.hyperliquid.spot.freshness("HYPE-USDC").await?;

Freshness

Check when each data type was last updated for a specific coin.

let freshness = client.hyperliquid.freshness("BTC").await?;
let lighter_freshness = client.lighter.freshness("BTC").await?;
let hip3_freshness = client.hyperliquid.hip3.freshness("km:US500").await?;
let spot_freshness = client.hyperliquid.spot.freshness("HYPE-USDC").await?;

Summary

Combined market snapshot — mark/oracle price, funding rate, open interest, 24h volume, and liquidation volumes.

let summary = client.hyperliquid.summary("BTC").await?;
let lighter_summary = client.lighter.summary("BTC").await?;
let hip3_summary = client.hyperliquid.hip3.summary("km:US500").await?;

Price History

Mark, oracle, and mid price history. Supports aggregation intervals.

let prices = client.hyperliquid.price_history(
    "BTC",
    1704067200000_i64,  // start
    1704153600000_i64,  // end
    Some("1h"),         // interval
    Some(100),          // limit
    None,               // cursor
).await?;

Data Quality Monitoring

Monitor data coverage, incidents, latency, and SLA compliance.

// System health status
let status = client.data_quality.status().await?;
println!("System: {}", status.status);

// Data coverage
let coverage = client.data_quality.coverage().await?;

// Symbol-specific coverage with gap detection
let btc = client.data_quality.symbol_coverage("hyperliquid", "BTC").await?;

// Incidents
let incidents = client.data_quality.list_incidents(None).await?;
let incident = client.data_quality.get_incident("inc-123").await?;

// Latency and SLA
let latency = client.data_quality.latency().await?;
let sla = client.data_quality.sla(None).await?;

Web3 Authentication

Wallet-based authentication using SIWE (Sign-In with Ethereum) and x402 USDC payments.

// Step 1: Get a SIWE challenge
let challenge = client.web3.challenge("0xYourWalletAddress").await?;

// Step 2: Sign the challenge and register
let result = client.web3.signup(
    &challenge.message,
    "0xYourSignature",
).await?;
println!("API Key: {}", result.api_key);

// Manage API keys (requires fresh SIWE signature)
let keys = client.web3.list_keys(&challenge.message, "0xSignature").await?;
client.web3.revoke_key(&challenge.message, "0xSignature", "key-id").await?;

// Subscribe with x402 USDC payment
let sub = client.web3.subscribe("build", "base64_payment_payload").await?;

WebSocket Client

Requires the websocket feature. Supports two modes on a single connection:

  • Real-time: subscribe to live market data
  • Replay: replay historical data with timing preserved

For file-based historical exports, use the Data Catalog.

Real-time Streaming

use oxarchive::ws::{OxArchiveWs, ServerMsg, WsOptions};

let mut ws = OxArchiveWs::new(WsOptions::new("your-api-key"));
ws.connect().await?;

ws.subscribe("orderbook", Some("BTC")).await?;
ws.subscribe("trades", Some("ETH")).await?;

let mut rx = ws.rx.take().expect("receiver");
while let Some(msg) = rx.recv().await {
    match msg {
        ServerMsg::Data { channel, coin, data, .. } => {
            println!("{channel} {} update: {}", coin.unwrap_or_default(), data);
        }
        ServerMsg::Error { message } => eprintln!("Error: {message}"),
        _ => {}
    }
}

Historical Replay

// Replay BTC orderbook at 100x speed
ws.replay("orderbook", "BTC", 1704067200000, Some(1704070800000), Some(100.0)).await?;

// Control playback
ws.replay_pause().await?;
ws.replay_resume().await?;
ws.replay_seek(1704069000000).await?;
ws.replay_stop().await?;

Available Channels

ChannelDescriptionRealtimeReplay
orderbookL2 order book (~1.2s resolution)YesYes
tradesTrade/fill updatesYesYes
candlesOHLCV candle dataYesYes
liquidationsLiquidation events. Each item is a fill row with is_liquidation: true.YesYes
open_interestOpen interest snapshotsYesYes
fundingFunding rate snapshotsYesYes
tickerPrice and 24h volumeYesNo
all_tickersAll market tickersYesNo
lighter_orderbookLighter.xyz L2 order bookYesYes
lighter_tradesLighter.xyz tradesYesYes
lighter_candlesLighter.xyz candlesYesYes
lighter_open_interestLighter.xyz open interestYesYes
lighter_fundingLighter.xyz funding ratesYesYes
lighter_l3_orderbookLighter.xyz L3 order-level orderbookYesYes
hip3_orderbookHIP-3 L2 order bookYesYes
hip3_tradesHIP-3 tradesYesYes
hip3_candlesHIP-3 candlesYesYes
hip3_open_interestHIP-3 open interestYesYes
hip3_fundingHIP-3 funding ratesYesYes
hip3_liquidationsHIP-3 liquidation events. Same wire shape as liquidations.YesYes
hip4_orderbookHIP-4 outcome-market L2 order bookNoStored replay only
hip4_tradesHIP-4 trade/fill updatesYesYes
hip4_open_interestHIP-4 open interest snapshotsNoStored replay only
l4_diffsHyperliquid L4 orderbook diffs with user attributionYesNo
l4_ordersHyperliquid order lifecycle eventsYesNo
hip3_l4_diffsHIP-3 L4 orderbook diffs with user attributionYesNo
hip3_l4_ordersHIP-3 order lifecycle eventsYesNo
hip4_l4_diffsHIP-4 L4 orderbook diffs with user attributionYesNo
hip4_l4_ordersHIP-4 order lifecycle eventsYesNo
spot_orderbookHyperliquid Spot L2 order bookYesNo
spot_tradesHyperliquid Spot tradesYesNo
spot_l4_diffsHyperliquid Spot L4 orderbook diffs with user attributionYesNo
spot_l4_ordersHyperliquid Spot order lifecycle eventsYesNo
spot_twapHyperliquid Spot TWAP execution updatesYesNo

HIP-4 has no funding or liquidation channels. HIP-4 candles and current outcome-side OI are available over REST from 2026-05-02; the live HIP-4 order-book and OI bridges are paused, while stored replay remains available. This HIP-4 channel set has no dedicated candle channel.

Hyperliquid Spot has no funding, open-interest, or liquidation resources. Spot candle history is REST-served from 2025-03-22T10:50:22Z and has no dedicated WebSocket channel. Spot symbols use the dashed canonical form (HYPE-USDC, PURR-USDC).

Settlement Frame

When a HIP-4 outcome settles, the server emits an outcome_settled frame exactly once per (outcome_id, side) and proactively unsubscribes the client from every hip4_* subscription on that coin. Other subscriptions remain active.

use oxarchive::ws::ServerMsg;

while let Some(msg) = rx.recv().await {
    if let ServerMsg::OutcomeSettled { coin, settlement_value, .. } = msg {
        println!("{coin} settled to {:?}", settlement_value);
    }
}

Tier Limits

All self-serve tiers reach the published route families; Free covers the most recent rolling 30 days of history (30-day span per request or replay), and Build and above keep the retained archive. Schema availability remains family-specific; plans gate capacity and Free's 30-day history window, not route families, schemas, or served depth.

TierMax SubscriptionsMax ConnectionsMax Replay SpeedMax Batch Size
Free10210x2,000
Build500350x2,000
Pro3,0005100x5,000
Scale20,00016300x10,000
EnterpriseCustomCustomfrom 500x10,000

Timestamp Formats

All time parameters accept the Timestamp enum:

use oxarchive::types::Timestamp;

// Unix milliseconds (i64)
let ts: Timestamp = 1704067200000_i64.into();

// ISO 8601 string
let ts: Timestamp = "2024-01-01T00:00:00Z".into();

// chrono::DateTime<Utc>
let ts: Timestamp = chrono::Utc::now().into();

Error Handling

use oxarchive::Error;

match client.hyperliquid.orderbook.get("BTC", None).await {
    Ok(ob) => println!("Mid price: {:?}", ob.mid_price),
    Err(Error::Api { message, code, .. }) => {
        eprintln!("API error ({code}): {message}");
    }
    Err(Error::Timeout) => eprintln!("Request timed out"),
    Err(Error::Http(e)) => eprintln!("HTTP error: {e}"),
    Err(e) => eprintln!("Other error: {e}"),
}

Examples

Run the included examples:

export OXARCHIVE_API_KEY="your-api-key"

# Basic usage
cargo run --example basic

# Cursor-based pagination
cargo run --example pagination

# Hyperliquid Spot
cargo run --example spot

# WebSocket (requires websocket feature)
cargo run --example websocket --features websocket

Data Catalog

For large-scale data exports (route-specific order books, fill-level trade history, and other retained datasets), use the Data Catalog. It lets you choose markets, datasets, and date ranges, see a live quote, and export zstd-compressed Parquet.

Requirements

  • Rust 1.75+
  • tokio runtime

License

MIT