Skip to main content

L4 Book Updates Dataset

Updated on
Jun 10, 2026

Overview

The StreamL4BookUpdates stream delivers typed order-level book changes as NEW, UPDATE, and REMOVE diffs for one or more coins. It gives clients per-order L4 movement without consuming full L4 book snapshots every block, and without parsing JSON-encoded payloads: every diff is a strongly typed protobuf message.

gRPC Service: OrderBookStreaming
gRPC Method: StreamL4BookUpdates
Update Model: Full reset snapshot on subscribe, then typed per-order diffs per block

How It Works

  1. On subscribe: The first message has snapshot: true and contains every resting order as a L4_ORDER_DIFF_TYPE_NEW diff, a full reset snapshot of the book
  2. Per block thereafter: Each L4BookUpdatesUpdate contains typed diffs for orders that changed: NEW (order entered the book), UPDATE (order size changed), REMOVE (order left the book, sz is omitted)
  3. Apply diffs to a local order map keyed by oid to maintain the current book

Unlike StreamL4Book, which sends diffs as a JSON-encoded data string, every field here is a typed protobuf field, so no secondary JSON parsing is required. A single stream can cover multiple coins (or all coins with an empty coins list).

Data Structure

Each L4BookUpdatesUpdate message contains the typed diffs for one block:

{
"time": 1781109115476,
"height": 586405189,
"diffs": [
{ "diff_type": "L4_ORDER_DIFF_TYPE_NEW", "coin": "ETH", "oid": 54764586686,
"user": "0x768484F7e2EBB675C57838366C02Ae99ba2A9B08", "side": "B", "px": "1649.1", "sz": "1.022" }
]
}

Request Parameters

FieldTypeRequiredDescription
coinsrepeated stringNoList of symbols to subscribe to (e.g., "BTC", "ETH"). Empty means all coins

Coin Naming

The coins parameter follows Hyperliquid's naming convention, which unambiguously distinguishes perpetuals from spot:

  • Perpetuals: Human-readable names, such as "BTC", "ETH", "HYPE", "SOL"
  • Spot tokens: @{index} format, such as "@1", "@107", "@142", "@166"
  • Outcome markets (HIP-4): #N format. Each outcome has two #N coins, one per side (Yes and No). Multi-price question markets consist of multiple grouped outcomes (price buckets plus a fallback), each with its own Yes/No coin pair. Use the outcomeMeta endpoint to map coin indices to market names and sides.
  • Exception: "PURR/USDC" is the only spot coin with a readable name

There is no overlap between formats. "BTC" always refers to the BTC perpetual; spot BTC is "@142". To discover @index mappings for spot tokens, query the meta or spotMeta info endpoints.

Response Fields

L4BookUpdatesUpdate

FieldTypeDescription
timeuint64Block timestamp in milliseconds
heightuint64Block height
snapshotboolTrue when the diffs carry a full reset snapshot of all resting orders (sent on subscribe)
diffsL4OrderDiff[]Typed per-order diffs for this block

L4OrderDiff

FieldTypeDescription
diff_typeL4OrderDiffTypeL4_ORDER_DIFF_TYPE_NEW (order entered the book), L4_ORDER_DIFF_TYPE_UPDATE (order size changed), or L4_ORDER_DIFF_TYPE_REMOVE (order left the book)
coinstringSymbol (e.g., "BTC", "ETH")
oiduint64Unique order ID
userstringEthereum address of the order owner
sidestring"A" (Ask/Sell) or "B" (Bid/Buy)
pxstringOrder price as a decimal string
szstringNew/current order size for NEW and UPDATE diffs. Omitted on REMOVE

Proto Definition

StreamL4BookUpdates is defined in orderbook.proto:

service OrderBookStreaming {
rpc StreamL4BookUpdates (L4BookUpdatesRequest) returns (stream L4BookUpdatesUpdate);
}

message L4BookUpdatesRequest {
repeated string coins = 1;
}

enum L4OrderDiffType {
L4_ORDER_DIFF_TYPE_UNSPECIFIED = 0;
L4_ORDER_DIFF_TYPE_NEW = 1;
L4_ORDER_DIFF_TYPE_UPDATE = 2;
L4_ORDER_DIFF_TYPE_REMOVE = 3;
}

message L4BookUpdatesUpdate {
uint64 time = 1;
uint64 height = 2;
repeated L4OrderDiff diffs = 3;
bool snapshot = 4;
}

message L4OrderDiff {
L4OrderDiffType diff_type = 1;
string coin = 2;
uint64 oid = 3;
string user = 4;
string side = 5;
string px = 6;
string sz = 7;
}

Example Updates

Initial Snapshot (first message, truncated)

The first message has snapshot: true and contains every resting order as a NEW diff:

{
"time": 1781109063794,
"height": 586404872,
"snapshot": true,
"diffs": [
{ "diff_type": "L4_ORDER_DIFF_TYPE_NEW", "coin": "BTC", "oid": 54764492622,
"user": "0x039442e06b482Bf01A1a65742cf061bD73A80f31", "side": "B", "px": "62963", "sz": "0.00009" },
{ "diff_type": "L4_ORDER_DIFF_TYPE_NEW", "coin": "BTC", "oid": 54764537698,
"user": "0x3643290CD5DE72b37d2f10A351Ce57c30d103969", "side": "B", "px": "62963", "sz": "0.00024" },
{ "diff_type": "L4_ORDER_DIFF_TYPE_NEW", "coin": "BTC", "oid": 54764482173,
"user": "0x4547B9E33F07965711f67d0bE2423939A4E33aF5", "side": "B", "px": "62955", "sz": "0.00015" }
]
}
Per-Block Update with Removals

sz is omitted on REMOVE diffs:

{
"time": 1781109083796,
"height": 586404997,
"diffs": [
{ "diff_type": "L4_ORDER_DIFF_TYPE_REMOVE", "coin": "BTC", "oid": 54764554671,
"user": "0xc64cc00B46101bd40aA1C3121195E85c0B0918d8", "side": "B", "px": "62389.0" },
{ "diff_type": "L4_ORDER_DIFF_TYPE_REMOVE", "coin": "BTC", "oid": 54764557274,
"user": "0xc64cc00B46101bd40aA1C3121195E85c0B0918d8", "side": "B", "px": "62421.0" }
]
}
New Order and Size Update

A new order entering the book:

{
"time": 1781109115476,
"height": 586405189,
"diffs": [
{ "diff_type": "L4_ORDER_DIFF_TYPE_NEW", "coin": "ETH", "oid": 54764586686,
"user": "0x768484F7e2EBB675C57838366C02Ae99ba2A9B08", "side": "B", "px": "1649.1", "sz": "1.022" }
]
}

A size change on a resting order (sz is the new current size):

{ "diff_type": "L4_ORDER_DIFF_TYPE_UPDATE", "coin": "ETH", "oid": 54764551695,
"user": "0x4547B9E33F07965711f67d0bE2423939A4E33aF5", "side": "B", "px": "1702.9", "sz": "0.0032" }

API Usage

gRPC Streaming
// Single coin
const request = {
coins: ['BTC']
};

// Multiple coins in one stream
const multiRequest = {
coins: ['BTC', 'ETH']
};

// All coins
const allCoinsRequest = {
coins: []
};

gRPC Only

StreamL4BookUpdates is only available via the gRPC Streaming API (OrderBookStreaming service). It is not available through JSON-RPC or WebSocket.

Comparison: L4 Book Updates vs L4 Book vs Book Updates Dataset

FeatureStreamL4BookUpdatesStreamL4BookBOOK_UPDATES
GranularityIndividual orders, typed diffsIndividual ordersIndividual order-level diffs
Diff encodingTyped protobuf (NEW/UPDATE/REMOVE)JSON-encoded data stringJSON objects
Includes current stateYes (reset snapshot as NEW diffs)Yes (initial snapshot)No (forward-only)
Needs REST bootstrapNoNoYes
Coins per streamMultiple (or all coins)One coin per streamFilterable
Per-order detailsUser, oid, side, px, szUser, oid, triggers, timestamps, tifUser, oid, size
Best forPer-order book tracking without JSON parsingFull order detail (triggers, tif, cloid)Customers who only need book updates

Important Notes


  • Reset snapshot on subscribe and reconnect: The first message has snapshot: true with all resting orders as NEW diffs. Clear any local state and rebuild from it
  • REMOVE omits sz: Remove diffs identify the order by oid (with coin, user, side, px) but carry no size. Delete the order from your local map
  • Typed alternative to StreamL4Book: If you need trigger info, timestamps, tif, or cloid per order, use StreamL4Book; if you need lean typed per-order movement, use this stream
  • zstd compression recommended: Enable zstd compression on your gRPC channel to reduce bandwidth, especially when streaming multiple coins

  • StreamL4Book - Full order book at order granularity with snapshot + JSON-encoded diffs
  • StreamL2BookDiff - Incremental L2 price-level changes with sequence numbers
  • Orders - Order lifecycle events (open, filled, canceled, etc.)
Share this doc