Streams referenceQuickNode-compatible

L2 Order Book

Aggregated price levels per coin, 1–100 levels deep. Guaranteed never crossed.

Top-of-book and depth by price level for a single coin. Subscribe with {coin, n_levels}; the first message is a full snapshot, then one update per block. Levels carry price, aggregated size, and resting-order count.

Method
hyperliquid.OrderBookStreaming/StreamL2Book
Endpoint
stream.hyperliquidrpc.com:443 · gRPC over TLS (HTTP/2)
Auth
API key in x-api-key metadata
Volume
One update per block per subscribed coin gives predictable, low-bandwidth depth. Use n_levels: 1 as a top-of-book ticker.

When to use it

This is the default book surface for pricing: market-making quote engines, spread monitors, execution algos that need depth, and any dashboard that shows a ladder. You choose the depth (n_levels, 1–100), the server does the aggregation, and every message is a consistent post-block view that is guaranteed never crossed. There are no “bid above ask” states to defend against.

If you need to know whose orders sit at each level, or your model depends on queue position, use the L4 book instead. If you only need a single price, n_levels: 1 here is a perfectly good top-of-book ticker.

Method

// stream.hyperliquidrpc.com:443 — gRPC over TLS (HTTP/2)// auth: API key in x-api-key metadata · server reflection enabledpackage hyperliquid; service OrderBookStreaming {  // Full snapshot first, then one full refresh per block. Never crossed.  rpc StreamL2Book (L2BookRequest) returns (stream L2BookUpdate);}

This service is wire-compatible with QuickNode's order-book proto, so generated stubs work unchanged after swapping the endpoint and key.

Subscribe

# Streams JSON-encoded messages until you disconnect.grpcurl -H 'x-api-key: YOUR_KEY' \  -d '{"coin":"BTC","n_levels":20}' \  stream.hyperliquidrpc.com:443 \  hyperliquid.OrderBookStreaming/StreamL2Book

coin is required and takes exactly one market per subscription; open one stream per coin you track. Bids and asks arrive best-price-first in levels.

Message fields

FieldTypeDescription
coinstringMarket symbol.
levelsLevel[][2]Bids and asks arrays, best price first.
pxstringPrice level.Byte-exact decimal string.
szstringAggregated size resting at the level.Byte-exact decimal string.
nuint32Number of resting orders at the level.
block_heightuint64Block this state corresponds to.

Fields typed string that carry numbers are byte-exact decimal strings, verbatim from the node. Compare and store them as strings or arbitrary-precision decimals. Never parseFloat a price you intend to reconcile.

Server-side filters

  • coin: required, one market per subscription
  • n_levels: 1 to 100

Filters are applied on the server, so filtered-out messages never leave our edge. You only pay for what you subscribe to. Request shapes for every stream family are on Filtering; backfill semantics on Replay & backfill.

Semantics & gotchas

Snapshot-then-updates: first message is a full book snapshot, then one full refresh per block. The book is guaranteed never crossed.

  • Each message is a full refresh, not a diff. Replace your local book state wholesale on every update. There is nothing to merge, which also means a dropped message costs you one block, not book integrity.
  • One coin per subscription. The request takes a single coin. Multiplex by opening one stream per market; updates are one-per-block, so even dozens of subscriptions stay cheap.
  • Cadence is the block, not the order. You see the book as of each block, not every intra-block change. For order-level granularity use the L4 book or raw book diffs.
  • Never crossed is a guarantee. Best bid is always strictly below best ask. You can drop the defensive checks other feeds force on you.

Sample message

{  "coin": "BTC",  "block_height": 612408133,  "time": "2026-06-09T08:14:02.418Z",  "is_snapshot": false,  "levels": [    [      { "px": "67011.0", "sz": "3.41280", "n": 14 },      { "px": "67010.0", "sz": "1.20019", "n": 6 }    ],    [      { "px": "67012.0", "sz": "2.88457", "n": 11 },      { "px": "67013.0", "sz": "5.10022", "n": 19 }    ]  ]}

One update per block per subscribed coin gives predictable, low-bandwidth depth. Use n_levels: 1 as a top-of-book ticker.

Recipes

Top-of-book ticker

Subscribe with n_levels: 1 and you get best bid/ask once per block: a low-bandwidth price feed for any of the 462+ markets, with resting-order counts included.

grpcurl -H 'x-api-key: YOUR_KEY' \  -d '{"coin":"HYPE","n_levels":1}' \  stream.hyperliquidrpc.com:443 \  hyperliquid.OrderBookStreaming/StreamL2Book

Mid-price and spread

levels[0] is bids and levels[1] is asks, best first. Compute mid and spread with decimals. The px strings are byte-exact, so two consumers of the same block always agree.

from decimal import Decimal for msg in stub.StreamL2Book(request, metadata=meta):    best_bid = Decimal(msg.levels[0][0].px)    best_ask = Decimal(msg.levels[1][0].px)    mid = (best_bid + best_ask) / 2    spread_bps = (best_ask - best_bid) / mid * 10_000

Depth imbalance signal

Sum sz across the top N levels on each side and track the ratio. Because every message is a consistent post-block snapshot, the signal needs no sequencing logic at all.

from decimal import Decimal def depth(levels):    return sum(Decimal(l.sz) for l in levels) for msg in stub.StreamL2Book(request, metadata=meta):    bid_depth, ask_depth = depth(msg.levels[0]), depth(msg.levels[1])    imbalance = bid_depth / (bid_depth + ask_depth)

Related