---
title: "WebSocket API | 0xArchive Docs"
description: "Connect to 0xArchive WebSocket for live subscriptions, replay, continuity signals, market-data channels, and operational streams."
canonical_url: "https://www.0xarchive.io/docs/websocket/"
markdown_url: "https://www.0xarchive.io/docs/websocket.md"
route: "/docs/websocket"
robots: "index, follow"
generated_from: "prerendered_html"
---

# WebSocket API

One socket for live subscriptions, replay, and continuity signals.

Endpoint wss://api.0xarchive.io/ws Modes Live and replay Commands Subscribe, replay, keep-alive Health Status on /status

## Connection

Connect once, keep the heartbeat alive, then issue subscribe or replay commands.

### Open the socket

Connect to `wss://api.0xarchive.io/ws` with your API key.

JavaScript

JavaScript

```
const ws = new WebSocket(
  "wss://api.0xarchive.io/ws?apiKey=0xa_your_api_key"
);

ws.onopen = () => {
  console.log("Connected to 0xArchive WebSocket");
};

ws.onmessage = (event) => {
  const data = JSON.parse(event.data);
  console.log("Received:", data);
};
```

Python

Python

```
import asyncio
import websockets
import json

async def connect():
    uri = "wss://api.0xarchive.io/ws?apiKey=0xa_your_api_key"
    async with websockets.connect(uri) as ws:
        print("Connected to 0xArchive WebSocket")
        async for message in ws:
            data = json.loads(message)
            print("Received:", data)

asyncio.run(connect())
```

### Keep-alive

The server sends ping frames every **30 seconds**. Clients that do not answer within **60 seconds** are disconnected.

JavaScript

```
// Send a ping to keep connection alive
ws.send(JSON.stringify({ op: "ping" }));

// Server responds with:
// {"type": "pong"}
```

### Command model

The same socket handles subscribe, unsubscribe, replay, and keep-alive commands.

Real-time Subscriptions

`subscribe`

Subscribe to a real-time channel

Params: channel, symbol

Send

```
{
  "op": "subscribe",
  "channel": "orderbook",
  "symbol": "BTC"
}
```

Receive

```
{
  "type": "subscribed",
  "channel": "orderbook",
  "symbol": "BTC"
}
```

`unsubscribe`

Unsubscribe from a channel

Params: channel, symbol

Send

```
{
  "op": "unsubscribe",
  "channel": "orderbook",
  "symbol": "BTC"
}
```

Receive

```
{
  "type": "unsubscribed",
  "channel": "orderbook",
  "symbol": "BTC"
}
```

Historical Replay

`replay`

Start historical replay. Use "channel" for single or "channels" (array) for multi-channel synchronized replay. All channels must be from the same exchange. Use interval for candles (1m-1w). Use granularity for lighter_orderbook.

Params: channel|channels, symbol, start, end, speed, [interval], [granularity]

Send

```
{
  "op": "replay",
  "channel": "trades",
  "symbol": "BTC",
  "start": 1704067200000,
  "end": 1704153600000,
  "speed": 10
}
```

Receive

```
{
  "type": "replay_started",
  "replay_id": "rpl_abc123",
  "channel": "trades",
  "symbol": "BTC",
  "speed": 10
}
```

`replay.pause`

Pause current replay

Params: -

Send

```
{
  "op": "replay.pause"
}
```

Receive

```
{
  "type": "replay_paused",
  "replay_id": "rpl_abc123"
}
```

`replay.resume`

Resume paused replay

Params: -

Send

```
{
  "op": "replay.resume"
}
```

Receive

```
{
  "type": "replay_resumed",
  "replay_id": "rpl_abc123"
}
```

`replay.seek`

Seek to specific timestamp

Params: timestamp

Send

```
{
  "op": "replay.seek",
  "timestamp": 1704100000000
}
```

Receive

```
{
  "type": "replay_seeked",
  "replay_id": "rpl_abc123",
  "timestamp": 1704100000000
}
```

`replay.stop`

Stop current replay

Params: -

Send

```
{
  "op": "replay.stop"
}
```

Receive

```
{
  "type": "replay_stopped",
  "replay_id": "rpl_abc123"
}
```

Utility

`ping`

Send a ping to keep connection alive (server responds with pong)

Params: -

Send

```
{
  "op": "ping"
}
```

Receive

```
{
  "type": "pong",
  "timestamp": "2026-01-01T12:00:00Z"
}
```

## Channels

Channel inventory by venue, plus live vs replay availability and depth detail.

### Hyperliquid

Historical data from April 2023. Symbols: BTC, ETH, SOL, etc.

Channel

`orderbook`

Description

High-frequency L2 order book snapshots (spacing varies by market activity and query window)

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "orderbook",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "bids": [
      {
        "px": "42150.50",
        "sz": "2.5",
        "n": 5
      }
    ],
    "asks": [
      {
        "px": "42151.00",
        "sz": "1.8",
        "n": 3
      }
    ],
    "mid_price": "42150.75"
  }
}
```

Channel

`trades`

Description

Trade/fill updates (pre-March 2025 fills are taker-only)

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "trades",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "side": "B",
      "price": "42150.50",
      "size": "0.25",
      "trade_id": 12345678
    }
  ]
}
```

Channel

`candles`

Description

OHLCV candles. Interval param: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w

Mode

Historical only (March 2025+)

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "candles",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "interval": "1h",
  "data": {
    "open": "42100.00",
    "high": "42200.00",
    "low": "42050.00",
    "close": "42180.00",
    "volume": "125.5"
  }
}
```

Channel

`open_interest`

Description

Open interest snapshots

Mode

Real-time & Historical (May 2023+)

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "open_interest",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "open_interest": "12500.5",
    "mark_price": "42150.75"
  }
}
```

Channel

`funding`

Description

Funding rate snapshots

Mode

Real-time & Historical (May 2023+)

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "funding",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "funding_rate": "0.0001",
    "premium": "0.00005"
  }
}
```

Channel

`liquidations`

Description

Fills with is_liquidation: true (filtered subset of trades). Real-time emits the trades wire format with is_liquidation:true; historical replay emits the ClickHouse liquidations row shape (camelCase fields, liquidatedUser, tradeId).

Mode

Real-time & Historical (December 2025+)

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "liquidations",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "side": "A",
      "price": "42150.50",
      "size": "1.5",
      "trade_id": 12345678,
      "is_liquidation": true,
      "direction": "Close Long",
      "closed_pnl": -118.4
    }
  ]
}
```

Channel

`ticker`

Description

Price and 24h volume

Mode

Real-time only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "ticker",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "price": "42150.75",
    "volume_24h": "1250000000"
  }
}
```

Channel

`all_tickers`

Description

All market tickers at once (no symbol param needed)

Mode

Real-time only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "all_tickers",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "symbol": "BTC",
      "price": "42150.75",
      "volume_24h": "1250000000"
    }
  ]
}
```

Channel

`l4_diffs`

Description

L4 orderbook diffs with user wallet attribution. Batched by block (~100ms).

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "l4_diffs",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "side": "B",
      "price": "42150.50",
      "size_delta": "0.5"
    }
  ]
}
```

Channel

`l4_orders`

Description

Order lifecycle events (new, partial fill, filled, cancelled) with wallet attribution. Batched by block.

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "l4_orders",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "status": "filled",
      "side": "B",
      "price": "42150.50",
      "size": "1.2"
    }
  ]
}
```

### HIP-3

Builder-deployed perpetuals on Hyperliquid. Historical trades, candles, orderbook, OI/funding, and liquidations begin in February 2026. Symbols: km:US500, hyna:BTC, etc.

Channel

`hip3_orderbook`

Description

L2 order book snapshots

Mode

Real-time & Historical

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_orderbook",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "bids": [
      {
        "px": "42150.50",
        "sz": "2.5",
        "n": 5
      }
    ],
    "asks": [
      {
        "px": "42151.00",
        "sz": "1.8",
        "n": 3
      }
    ],
    "mid_price": "42150.75"
  }
}
```

Channel

`hip3_trades`

Description

Trade/fill updates

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_trades",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "side": "B",
      "price": "42150.50",
      "size": "0.25",
      "trade_id": 12345678
    }
  ]
}
```

Channel

`hip3_candles`

Description

OHLCV candles. Interval param: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w

Mode

Historical only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_candles",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "interval": "1h",
  "data": {
    "open": "42100.00",
    "high": "42200.00",
    "low": "42050.00",
    "close": "42180.00",
    "volume": "125.5"
  }
}
```

Channel

`hip3_open_interest`

Description

Open interest snapshots

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_open_interest",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "open_interest": "12500.5",
    "mark_price": "42150.75"
  }
}
```

Channel

`hip3_funding`

Description

Funding rate snapshots

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_funding",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "funding_rate": "0.0001",
    "premium": "0.00005"
  }
}
```

Channel

`hip3_liquidations`

Description

Fills with is_liquidation: true (filtered subset of hip3_trades). Real-time emits the hip3_trades wire format with is_liquidation:true; historical replay emits the ClickHouse hip3_fills-derived shape (camelCase fields, liquidatedUser, tradeId).

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_liquidations",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "side": "A",
      "price": "42150.50",
      "size": "1.5",
      "trade_id": 12345678,
      "is_liquidation": true,
      "direction": "Close Long",
      "closed_pnl": -118.4
    }
  ]
}
```

Channel

`hip3_l4_diffs`

Description

L4 orderbook diffs with user wallet attribution. Batched by block (~100ms).

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_l4_diffs",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "side": "B",
      "price": "42150.50",
      "size_delta": "0.5"
    }
  ]
}
```

Channel

`hip3_l4_orders`

Description

Order lifecycle events with wallet attribution. Batched by block.

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "hip3_l4_orders",
  "symbol": "km:US500",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "status": "filled",
      "side": "B",
      "price": "42150.50",
      "size": "1.2"
    }
  ]
}
```

### Hyperliquid Spot

Hyperliquid spot pairs. 294 pairs live from May 2026. Symbols use dash form (PURR-USDC, HYPE-USDC, HFUN-USDC); the bare token (e.g. HFUN) is also accepted. No funding, OI, or liquidations (perp-only constructs).

Channel

`spot_orderbook`

Description

L2 order book snapshots (~1.9/sec) for spot pairs

Mode

Real-time only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "spot_orderbook",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "bids": [
      {
        "px": "42150.50",
        "sz": "2.5",
        "n": 5
      }
    ],
    "asks": [
      {
        "px": "42151.00",
        "sz": "1.8",
        "n": 3
      }
    ],
    "mid_price": "42150.75"
  }
}
```

Channel

`spot_trades`

Description

Spot trade/fill updates

Mode

Real-time only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "spot_trades",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "side": "B",
      "price": "42150.50",
      "size": "0.25",
      "trade_id": 12345678
    }
  ]
}
```

Channel

`spot_l4_diffs`

Description

L4 orderbook diffs with wallet attribution. Batched ~250ms (per-block, sourced from the Singapore prod node).

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "spot_l4_diffs",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "side": "B",
      "price": "42150.50",
      "size_delta": "0.5"
    }
  ]
}
```

Channel

`spot_l4_orders`

Description

Order lifecycle events (open, filled, canceled, selfTradeCanceled, badAloPxRejected, insufficientSpotBalanceRejected, iocCancelRejected, minTradeNtlRejected) with wallet attribution.

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "spot_l4_orders",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "status": "filled",
      "side": "B",
      "price": "42150.50",
      "size": "1.2"
    }
  ]
}
```

Channel

`spot_twap`

Description

TWAP order lifecycle for spot (activated, finished, error, terminated). Joinable by twap_id.

Mode

Real-time only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "spot_twap",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "status": "ok"
  }
}
```

### HIP-4

Binary outcome markets on Hyperliquid L1. Per-side coins are #-prefixed (e.g. #0 for Yes, #1 for No). No funding, no liquidations, no candles by design (build candles client-side from hip4_trades). Live data from May 2026.

Channel

`hip4_orderbook`

Description

L2 order book snapshots per outcome side

Mode

Real-time & Historical

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "hip4_orderbook",
  "symbol": "#0",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "bids": [
      {
        "px": "42150.50",
        "sz": "2.5",
        "n": 5
      }
    ],
    "asks": [
      {
        "px": "42151.00",
        "sz": "1.8",
        "n": 3
      }
    ],
    "mid_price": "42150.75"
  }
}
```

Channel

`hip4_trades`

Description

Per-side fill/trade updates

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "hip4_trades",
  "symbol": "#0",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "side": "B",
      "price": "42150.50",
      "size": "0.25",
      "trade_id": 12345678
    }
  ]
}
```

Channel

`hip4_open_interest`

Description

Per-side OI snapshots (upstream channel name: activeSpotAssetCtx; server translates)

Mode

Real-time & Historical

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "hip4_open_interest",
  "symbol": "#0",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "open_interest": "12500.5",
    "mark_price": "42150.75"
  }
}
```

Channel

`hip4_l4_diffs`

Description

L4 orderbook diffs with user wallet attribution. Initial l4_snapshot then l4_batch event stream. Symbol required.

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "hip4_l4_diffs",
  "symbol": "#0",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "side": "B",
      "price": "42150.50",
      "size_delta": "0.5"
    }
  ]
}
```

Channel

`hip4_l4_orders`

Description

Order lifecycle events with wallet attribution. Symbol required.

Mode

Real-time only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "hip4_l4_orders",
  "symbol": "#0",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "order_id": "0xabc",
      "user_address": "0x1234...abcd",
      "status": "filled",
      "side": "B",
      "price": "42150.50",
      "size": "1.2"
    }
  ]
}
```

### Lighter.xyz

Data from August 2025 for fills, candles, open interest, and funding; January 2026 for L2 orderbook; March 2026 for L3 orderbook. Symbols: BTC, ETH, SOL, etc.

Channel

`lighter_orderbook`

Description

Full-depth order book. Finer L2 granularity is tier-gated, and tick reconstruction is Enterprise-only.

Mode

Historical only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "lighter_orderbook",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "bids": [
      {
        "px": "42150.50",
        "sz": "2.5",
        "n": 5
      }
    ],
    "asks": [
      {
        "px": "42151.00",
        "sz": "1.8",
        "n": 3
      }
    ],
    "mid_price": "42150.75"
  }
}
```

Channel

`lighter_trades`

Description

Trade/fill updates

Mode

Historical only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "lighter_trades",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": [
    {
      "side": "B",
      "price": "42150.50",
      "size": "0.25",
      "trade_id": 12345678
    }
  ]
}
```

Channel

`lighter_candles`

Description

OHLCV candles. Interval param: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w

Mode

Historical only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "lighter_candles",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "interval": "1h",
  "data": {
    "open": "42100.00",
    "high": "42200.00",
    "low": "42050.00",
    "close": "42180.00",
    "volume": "125.5"
  }
}
```

Channel

`lighter_open_interest`

Description

Open interest snapshots

Mode

Historical only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "lighter_open_interest",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "open_interest": "12500.5",
    "mark_price": "42150.75"
  }
}
```

Channel

`lighter_funding`

Description

Funding rate snapshots

Mode

Historical only

Tier

Build+

Message sample

```
{
  "type": "market_data",
  "channel": "lighter_funding",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "funding_rate": "0.0001",
    "premium": "0.00005"
  }
}
```

Channel

`lighter_l3_orderbook`

Description

L3 order-level orderbook snapshots with individual order IDs and sizes

Mode

Historical only

Tier

Pro+

Message sample

```
{
  "type": "market_data",
  "channel": "lighter_l3_orderbook",
  "symbol": "BTC",
  "timestamp": "2026-01-01T12:00:00Z",
  "data": {
    "bids": [
      {
        "px": "42150.50",
        "sz": "2.5",
        "n": 5
      }
    ],
    "asks": [
      {
        "px": "42151.00",
        "sz": "1.8",
        "n": 3
      }
    ],
    "mid_price": "42150.75"
  }
}
```

### Real-time subscriptions

Subscribe to proxied venue streams.

JavaScript

```
// Subscribe to real-time order book updates
ws.send(JSON.stringify({
  op: "subscribe",
  channel: "orderbook",
  symbol: "BTC"
}));

// Subscribe to real-time trades
ws.send(JSON.stringify({
  op: "subscribe",
  channel: "trades",
  symbol: "ETH"
}));

// Subscribe to L4 orderbook diffs (Pro+, real-time only)
// Messages are batched by block and include user wallet addresses
ws.send(JSON.stringify({
  op: "subscribe",
  channel: "l4_diffs",
  symbol: "BTC"
}));

// Subscribe to L4 order lifecycle events (Pro+, real-time only)
// Streams order state changes (new, partial fill, filled, cancelled)
ws.send(JSON.stringify({
  op: "subscribe",
  channel: "l4_orders",
  symbol: "ETH"
}));

// Subscribe to HIP-3 L4 channels
ws.send(JSON.stringify({
  op: "subscribe",
  channel: "hip3_l4_diffs",
  symbol: "km:US500"
}));

ws.send(JSON.stringify({
  op: "subscribe",
  channel: "hip3_l4_orders",
  symbol: "km:US500"
}));

// Subscribe to HIP-4 outcome-market channels
// HIP-4 coins are #-prefixed: #0 = Yes side, #1 = No side
ws.send(JSON.stringify({
  op: "subscribe",
  channel: "hip4_orderbook",
  symbol: "#0"
}));

ws.send(JSON.stringify({
  op: "subscribe",
  channel: "hip4_l4_diffs",
  symbol: "#0"
}));

// Unsubscribe
ws.send(JSON.stringify({
  op: "unsubscribe",
  channel: "orderbook",
  symbol: "BTC"
}));
```

### L4 orderbook streaming

L4 starts with a snapshot and follows with diff batches.

Python

```
import websockets, json, asyncio

async def stream_l4():
    uri = "wss://api.0xarchive.io/ws?apiKey=YOUR_KEY"
    async with websockets.connect(uri, max_size=20_000_000) as ws:
        # Subscribe to L4 diffs (works for l4_diffs, hip3_l4_diffs, or hip4_l4_diffs)
        await ws.send(json.dumps({
            "op": "subscribe",
            "channel": "l4_diffs",
            "symbol": "BTC"
        }))

        book = {"bids": {}, "asks": {}}
        snapshot_ts = None

        async for msg in ws:
            data = json.loads(msg)

            if data["type"] == "l4_snapshot":
                # Full book delivered first (every order including triggers)
                snapshot_ts = data["timestamp"]
                for order in data["data"]["bids"]:
                    book["bids"][order["oid"]] = order
                for order in data["data"]["asks"]:
                    book["asks"][order["oid"]] = order
                print(f"Snapshot: {len(book['bids'])} bids, {len(book['asks'])} asks")

            elif data["type"] == "l4_batch" and snapshot_ts is not None:
                # Apply diffs to maintain the book
                for diff in data["data"]:
                    if diff["ts"] <= snapshot_ts:
                        continue
                    side = "bids" if diff["side"] == "B" else "asks"
                    oid = diff["oid"]
                    if diff["dt"] == "new":
                        book[side][oid] = {
                            "oid": oid, "side": diff["side"],
                            "price": diff["px"], "size": diff["sz"],
                            "user_address": diff["user"]
                        }
                    elif diff["dt"] == "update":
                        if oid in book[side]:
                            book[side][oid]["size"] = diff["sz"]
                    elif diff["dt"] == "remove":
                        book[side].pop(oid, None)

asyncio.run(stream_l4())
```

## Replay & Backtesting

Replay historical data over the same socket, then feed it through your live event loop for backtests.

### Historical replay

Replay historical data with original timing and adjustable speed.

JavaScript

```
// Start historical replay at 10x speed (Hyperliquid)
ws.send(JSON.stringify({
  op: "replay",
  channel: "orderbook",
  symbol: "BTC",
  start: 1681516800000,  // Unix timestamp in ms
  end: 1681603200000,
  speed: 10  // 10x playback speed
}));

// Start Lighter.xyz orderbook replay with granularity
ws.send(JSON.stringify({
  op: "replay",
  channel: "lighter_orderbook",
  symbol: "BTC",
  start: 1706140800000,
  end: 1706227200000,
  speed: 10,
  granularity: "10s"  // Options: checkpoint, 30s, 10s, 1s, tick
}));

// Replay candles with specific interval
ws.send(JSON.stringify({
  op: "replay",
  channel: "candles",
  symbol: "ETH",
  start: 1681516800000,
  end: 1681603200000,
  speed: 10,
  interval: "1h"  // Options: 1m, 5m, 15m, 30m, 1h, 4h, 1d, 1w
}));

// Replay OI/funding data
ws.send(JSON.stringify({
  op: "replay",
  channel: "open_interest",
  symbol: "BTC",
  start: 1684540800000,
  end: 1684627200000,
  speed: 10
}));

// Multi-channel synchronized replay (all channels must be same exchange)
// Data is interleaved in timestamp order across channels
ws.send(JSON.stringify({
  op: "replay",
  channels: ["orderbook", "trades", "funding"],  // Use "channels" (plural) for multi-channel
  symbol: "BTC",
  start: 1681516800000,
  end: 1681603200000,
  speed: 10
}));

// Multi-channel Lighter replay
ws.send(JSON.stringify({
  op: "replay",
  channels: ["lighter_orderbook", "lighter_trades", "lighter_funding"],
  symbol: "ETH",
  start: 1706140800000,
  end: 1706227200000,
  speed: 10,
  granularity: "10s"  // Applies to lighter_orderbook channel
}));

// Multi-channel replay sends "replay_snapshot" messages before the timeline
// starts, providing initial state for each channel:
// {"type": "replay_snapshot", "channel": "orderbook", "coin": "BTC", "symbol": "BTC", "timestamp": ..., "data": {...}}
// {"type": "replay_snapshot", "channel": "funding", "coin": "BTC", "symbol": "BTC", "timestamp": ..., "data": {...}}
// Then interleaved historical_data messages follow in timestamp order

// Pause replay
ws.send(JSON.stringify({ op: "replay.pause" }));

// Resume replay
ws.send(JSON.stringify({ op: "replay.resume" }));

// Seek to specific timestamp
ws.send(JSON.stringify({
  op: "replay.seek",
  timestamp: 1681550000000
}));

// Stop replay
ws.send(JSON.stringify({ op: "replay.stop" }));
```

### Gap detection

`gap_detected` marks missing windows during replay.

JavaScript

```
// Gap detection during replay
ws.onmessage = (event) => {
  const msg = JSON.parse(event.data);

  if (msg.type === 'gap_detected') {
    console.log(`Gap in ${msg.channel}/${msg.symbol}:`);
    console.log(`  From: ${new Date(msg.gap_start).toISOString()}`);
    console.log(`  To: ${new Date(msg.gap_end).toISOString()}`);
    console.log(`  Duration: ${msg.duration_minutes} minutes`);
  }

  // Handle other message types...
  if (msg.type === 'historical_data') {
    // Process data
  }
};
```

Gap thresholds

- - **orderbook, candles, liquidations:** 2 minutes
- - **trades:** 60 minutes

### Backtesting

Feed synchronized historical market data through the same event loop you use for live handling.

Python

```
import asyncio, json, websockets

async def backtest_strategy():
    uri = "wss://api.0xarchive.io/ws?apiKey=0xa_your_api_key"
    async with websockets.connect(uri) as ws:
        # Replay orderbook + trades together at 50x speed
        await ws.send(json.dumps({
            "op": "replay",
            "channels": ["orderbook", "trades"],
            "symbol": "BTC",
            "start": 1704067200000,   # Jan 1 2024
            "end": 1704153600000,     # Jan 2 2024
            "speed": 50
        }))

        orderbook = None
        trades = []

        async for message in ws:
            msg = json.loads(message)

            if msg["type"] == "replay_snapshot":
                # Initial state before timeline starts
                if msg["channel"] == "orderbook":
                    orderbook = msg["data"]

            elif msg["type"] == "historical_data":
                if msg["channel"] == "orderbook":
                    orderbook = msg["data"]
                    # Run strategy on each orderbook update
                    signal = my_strategy(orderbook, trades)
                    if signal:
                        execute_paper_trade(signal, msg["timestamp"])
                elif msg["channel"] == "trades":
                    trades.append(msg["data"])

            elif msg["type"] == "gap_detected":
                print(f"Data gap: {msg['duration_minutes']}min at {msg['gap_start']}")

            elif msg["type"] == "replay_completed":
                print(f"Backtest done. {msg['snapshots_sent']} data points processed.")
                break

asyncio.run(backtest_strategy())
```

Tips

- Use multi-channel replay (orderbook + trades + funding) to get a complete market picture with synchronized timestamps.
- Begin at low speed (1-10x) to verify your strategy logic, then increase speed for full backtests.
- Handle replay_snapshot messages first to build initial state before the timeline begins.
- Monitor gap_detected messages: gaps in orderbook data (>2 min) or trades (>60 min) indicate periods where your backtest may be unreliable.
- Replay is limited to 1 task per connection. Open multiple connections to backtest different symbols in parallel.
- For bulk analysis over long periods, consider the REST API with cursor pagination instead of replay (no speed limit, lower credit cost).

## Limits

Subscription caps, replay limits, idle timeouts, and range constraints.

### WebSocket limits by tier

| Tier | Symbols | Historical Depth | Max Range/Request | Max Subscriptions | Max Replay Speed |
| --- | --- | --- | --- | --- | --- |
| Free | No WebSocket access | - | - | - | - |
| Build | All | 365 days | Unlimited | 25 | 50x |
| Pro | All | Unlimited | Unlimited | 100 | 100x |
| Enterprise | All | Unlimited | Unlimited | 200 | 1000x |

WebSocket access is available on Build tier and above. See [pricing](https://www.0xarchive.io/pricing/) for the current tier posture.

### Connection constraints

| Constraint | Limit | Description |
| --- | --- | --- |
| Message metering | `1 credit/msg` | Each WebSocket message counts as 1 API credit toward monthly quota |
| Idle timeout (with subscriptions) | `60 seconds` | Send ping every 30s to keep alive |
| Idle timeout (no subscriptions) | `5 minutes` | Connections without subscriptions timeout after 5 minutes |
| Subscription rate limit | `10/second` | Max subscribe/unsubscribe operations per second |
| Concurrent replay tasks | `1` | One replay per connection at a time (multi-channel counts as one replay) |
| Multi-channel constraint | `Same exchange` | All channels in a multi-channel replay must be from the same exchange (e.g., all Hyperliquid or all Lighter; HIP-3 and HIP-4 are separate exchanges and cannot be mixed) |
| Per-request range limit | `Tier-based` | Free: 30 days max, Build/Pro/Enterprise: Unlimited |
| Data availability | `Varies by channel` | Hyperliquid: April 2023+ (orderbook snapshot spacing varies by market activity and query window; OI/funding: May 2023+, candles: March 2025+, liquidations: December 2025+, L4: March 2026+). Lighter: August 2025+ (trades, candles, OI, funding), January 2026+ (L2 orderbook), March 2026+ (L3 orderbook). HIP-3: February 2026+ for trades, candles, orderbook, OI/funding, and liquidations; L4 March 2026+. HIP-4: May 2026+ for L2/L4 orderbook, trades, OI, and order lifecycle (no funding, no liquidations, no candles by design). |
