> ## Documentation Index
> Fetch the complete documentation index at: https://docs.0xarchive.io/llms.txt
> Use this file to discover all available pages before exploring further.

# WebSocket protocol reference

> Use the documented WebSocket command and event shapes for connection, subscription, replay, gaps, and errors.

Every command your client sends over the WebSocket and every event the server sends back, with the fields each one needs. REST routes are described by [OpenAPI](/openapi); WebSocket messages are described here.

## Client commands

| Command | Purpose and fields |
| - | - |
| `subscribe` | Start a live stream for one channel.<br />Fields: `op`, `channel`; `symbol` for coin-specific channels; optional `interval_ms` on `lighter_orderbook` and `rh_lighter_orderbook` only |
| `unsubscribe` | Stop a live stream.<br />Fields: `op`, `channel`; `symbol` for coin-specific channels |
| `replay` | Replay a historical window.<br />Fields: `op`, exactly one non-empty `channel` or `channels`, `symbol`, `start`; optional `end` (defaults to now), `speed` for standard timed replay (default `1`, capped at your plan's standard replay speed), and `interval` on candle channels |
| `replay.pause` | Pause standard or core L4 replay.<br />Fields: `op` |
| `replay.resume` | Resume standard or core L4 replay.<br />Fields: `op` |
| `replay.seek` | Move standard replay to a timestamp. Standard replay only; core L4 rejects seek.<br />Fields: `op`, `timestamp` |
| `replay.stop` | Stop standard or core L4 replay.<br />Fields: `op` |
| `ping` | Keep the connection alive when the client does not rely on native ping frames.<br />Fields: `op` |

Times (`start`, `end`, `timestamp`) are Unix milliseconds; RFC 3339 strings are also accepted. `all_tickers` takes no `symbol`, and on `mempool` it is optional: leave it out to receive every pending transaction our Hyperliquid node receives.

```json theme={"theme":"github-dark"}
{
  "op": "subscribe",
  "channel": "orderbook",
  "symbol": "BTC"
}
```

`interval_ms` sets the maximum `lighter_orderbook` or `rh_lighter_orderbook` book rate, from `100` to `5000`. Leave it out for one book per second. Any other channel rejects it.

```json theme={"theme":"github-dark"}
{
  "op": "subscribe",
  "channel": "lighter_orderbook",
  "symbol": "BTC",
  "interval_ms": 250
}
```

`interval` sets the bar width for a candle replay: `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `1d`, or `1w`, with `1h` when left out.

The replay below covers one hour in January 2026, so this exact message needs the full retained archive of Build or above. On Free, send a window from the most recent 30 days.

```json theme={"theme":"github-dark"}
{
  "op": "replay",
  "channels": ["orderbook", "trades"],
  "symbol": "BTC",
  "start": 1767225600000,
  "end": 1767229200000,
  "speed": 10
}
```

## Server events

| Event | Meaning and what to do |
| - | - |
| `subscribed` | Confirms a live subscription. Mark the stream active |
| `unsubscribed` | Confirms a stopped subscription. Stop processing the channel |
| `pong` | Answers a `ping` command |
| `data` | Live data for an ordinary channel. Apply it by channel and keep the timestamp and symbol |
| `l4_snapshot` | Initial L4 state for an order-level channel. Replace local L4 state for that channel |
| `l4_batch` | Ordered L4 diffs after an L4 snapshot. Apply them in order and stop on an unsafe sequence or block gap. When an item carries the optional `insert_before`, insert the new order ahead of that order ID within its price level instead of appending |
| `replay_started` | Confirms replay window and standard replay speed when applicable. Start your run log |
| `replay_snapshot` | Initial state before replay timeline data. Build the baseline before processing `historical_data` |
| `historical_data` | A replay timeline record. Apply in the order received and keep the timestamp |
| `historical_tick_data` | A Lighter tick-mode checkpoint and its deltas. Apply the checkpoint before the deltas and keep the ordering metadata |
| `replay_paused` | Confirms a replay pause. Keep state; time stops advancing |
| `replay_resumed` | Confirms a replay resume. Continue processing |
| `replay_completed` | The replay reached its end. Close the run and label the output |
| `replay_stopped` | Confirms a replay stop. Close the run cleanly |
| `gap_detected` | A missing or discontinuous interval. Mark the output incomplete or rebuild |
| `error` | A command, authentication, access, or data error, or a live-stream lag notice. Branch on `error_code` and log `message`. Stop the affected workflow for a refused command; for `slow_consumer`, re-subscribe or restart the replay to resync. Codes are listed on [Errors](/errors#websocket-errors) |

```json theme={"theme":"github-dark"}
{
  "type": "gap_detected",
  "channel": "orderbook",
  "symbol": "BTC",
  "gap_start": 1767226200000,
  "gap_end": 1767226260000
}
```

Commands and events use different naming patterns. Dotted names such as `replay.pause`, `replay.resume`, `replay.seek`, and `replay.stop` are commands the client sends. Underscore names such as `replay_paused`, `replay_resumed`, `replay_snapshot`, `historical_data`, and `replay_completed` are events the server sends.

## Message envelope

Payload shapes differ by channel: order-book snapshots, trades, funding, and replay events carry different fields, and live Lighter `data` payloads differ from Lighter replay `historical_data` rows (see [Lighter channels](/websocket/lighter)). Keep the symbol, channel, venue family, timestamp, any request or correlation ID, and any gap state with what you store.

<ResponseField name="type" type="string">
  Event name, such as `data`, `l4_snapshot`, `replay_snapshot`, `historical_data`, `gap_detected`, or `error`.
</ResponseField>

<ResponseField name="channel" type="string">
  The market-data channel the event belongs to. Replay control events can use replay-specific names.
</ResponseField>

<ResponseField name="symbol" type="string">
  Symbol or pair in the venue family's format, as you subscribed to it.
</ResponseField>

<ResponseField name="timestamp" type="number">
  Event time when the channel sends one. Store it in the same run manifest as the replay or live stream.
</ResponseField>

## Validate commands before sending

Check each command before it leaves your client. A coin-specific command without a symbol, a replay without a symbol or start, and an unbounded replay window are client bugs.

* Send either a single `channel` or a `channels` list, never both by accident.
* Keep the symbol in its family's format: a pair, a builder prefix, an outcome side, or a Lighter market.
* For a bounded replay, send explicit `start` and `end`; include `speed` for standard timed replay or checkpoint metadata for core L4.
* Log refused commands, authentication failures, close events, and request or correlation IDs.
* When `gap_detected` arrives, mark the output incomplete or rebuild it.
* Wait for underscore event names; a dotted command name never comes back as an event.

For long-running jobs, keep one state object with the connection status, active subscriptions, last event time, replay window, gap events, and reconnect count. [Connection](/websocket/connection) shows one.

## Next step

Validate outbound commands against the [JSON schema for each command](/schemas/websocket-messages).


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.