Skip to content

Message Types

Every server-to-client frame carries a type field that uniquely identifies its shape. Use this as the discriminator in your message handler. JSON Schemas for each type are available in the repository under schemas/.

Universal conventions:

  • All time fields are epoch milliseconds (Date.now() integers).
  • All address fields are lowercase EVM addresses (0x + 40 hex).
  • All chain values are lowercase: arbitrum | base | ethereum | unichain | hyperevm.
  • Numeric fields use float64 unless explicitly typed as decimal string (amount0, amount1 in LP events use strings to preserve uint256 precision).
  • Prices and sizes are in human units (e.g. WETH/USDC price = USDC per WETH, size = WETH count) unless noted otherwise.

Discriminator table

typeDescriptionApplicable venues
quoteTop-of-book snapshotAll
printSingle trade executionAll
fundingPerpetual funding rateCLOB perps, oracle perps
depthAMM tick-liquidity snapshot + market-impact estimatesAMM spot
liquidityLP Mint or Burn eventAMM spot
rate_marketYield-market snapshot (APY, PT price, TVL, expiry)pendle, spectra
rate_depthDepth-at-size APY quotependle only
ammbookConsolidated NBBO across all four Arbitrum AMMsammbook virtual
ammliquidity_snapshotOne-time LP-event backfill on subscribeammliquidity virtual
arbflagCross-venue arb-gap edge signalarbflag virtual (super_admin)
spreadSame-venue cross-pool spread signaluni, univ4
feed_stale / feed_liveUpstream feed staleness transitionsBroadcast to all
server_closingPlanned restart noticeBroadcast to all
authedAPI key auth successConnection-level
errorAction rejectedConnection-level

quote — top-of-book snapshot

Emitted on every book update. Shape varies slightly by venue class:

  • CLOB venues (hl, dydx): full depth array. bids[0] = best bid, asks[0] = best ask.
  • AMM venues: typically one level per fee tier. OrderLevel.fee is the pool fee in ppm (500 = 0.05%).
  • Oracle perps (gmx, vertex, ostium): single-level synthetic mid + spread model.
FieldTypeNotes
exchangestringVenue id
symbolstringCanonical symbol
bidsOrderLevel[]Descending by price
asksOrderLevel[]Ascending by price
bids[].fee / asks[].feeinteger (ppm)AMM venues only. 500 = 0.05%.
bids[].lastSwapMsintegerAMM venues only. Age of the pool’s last on-chain swap in ms.
timeintegerServer broadcast timestamp (epoch ms)
{ "type": "quote", "exchange": "hl", "symbol": "ETH",
"bids": [{"price": 3499.5, "size": 12.4}, {"price": 3499.0, "size": 31.1}],
"asks": [{"price": 3500.5, "size": 8.7}],
"time": 1748275200000 }

AMM example with fee tier:

{ "type": "quote", "exchange": "uni", "symbol": "WETH/USDC",
"bids": [{"price": 3499.12, "size": 5.2, "fee": 500, "lastSwapMs": 1100}],
"asks": [{"price": 3500.88, "size": 5.2, "fee": 500, "lastSwapMs": 1100}],
"time": 1748275200000 }

One trade. Emitted on every on-chain swap or HL matching event.

FieldTypeNotes
exchangestringVenue id
symbolstring
pricenumberExecution price in human units
sizenumberTrade size in base-token units
sideinteger0 = bid hit (seller initiated); 1 = ask lift (buyer initiated); 2 = unknown
timeintegerEpoch ms
tickintegerAMM/yield venues only. Pool tick at time of swap.
blockNumberintegerOn-chain venues only.
txIndexintegerOn-chain venues only. Use with blockNumber for deduplication.
logSenderstringAMM venues only. Router/aggregator address that submitted the swap.
d_*numberHL and dYdX only. Stat-engine fields — see table below.

For Pendle/Spectra, side applies to the PT leg: 1 = trade bought PT; 0 = trade sold PT.

Stat-engine fields (d_* — HL and dYdX prints)

These fields are emitted on HL and dYdX V4 prints with the same shape and semantics. They are absent on all other venues.

FieldUnitsRangeDescription
d_tickratetrades/sec[0, ∞)Trade arrival rate over the last 1 s window
d_volumeratecontracts/sec[0, ∞)Volume velocity over the last 1 s window
d_quoterateL2 updates/sec[0, ∞)Quote-update velocity over the last 1 s window
d_hawkesevents/sec[0, ~1000+]Hawkes self-exciting intensity (all sides). Treat as elevated when > 5× 30-day mean — not a probability.
d_hawkesBevents/secsameHawkes intensity, bid-side prints
d_hawkesAevents/secsameHawkes intensity, ask-side prints
d_lobimbdimensionless[−1, +1]LOB imbalance from top 10 L2 levels. −1 = all on ask; +1 = all on bid; 0 = balanced
d_volumeimbcontracts(−∞, +∞)Signed volume over last 1 s: buyVol − sellVol. Positive = net buying.
d_bidqtycontracts[0, ∞)Total bid-side quantity in the L2 snapshot
d_askqtycontracts[0, ∞)Total ask-side quantity in the L2 snapshot

Hawkes parameters: µ=0.1, α=2.0, β=0.0005/ms. The absolute level is venue/symbol-specific; compare against a rolling baseline rather than a fixed threshold.


funding — perpetual funding rate

Emitted approximately every 60 seconds per venue per symbol.

FieldTypeNotes
ratePctnumberAnnualized percentage, signed. +10.95 = longs pay shorts at 10.95%/yr.
intervalHrsnumberVenue’s native payment cadence. HL/dYdX = 8h; Ostium = 24h; GMX/Vertex = 1h.
timeintegerEpoch ms

ratePct is always annualized regardless of intervalHrs, so cross-venue comparisons are direct.

Conversions:

  • Per-hour rate (decimal): ratePct / 100 / (365 * 24)
  • Per-payment-interval rate: ratePct / 100 / (365 * 24 / intervalHrs)
{ "type": "funding", "exchange": "hl", "symbol": "ETH",
"ratePct": 10.95, "intervalHrs": 8, "time": 1748275200000 }

depth — AMM concentrated-liquidity snapshot

AMM venues only (uni, univ4, univ4chain, sushi, pancake). Emitted on every Mint/Burn event, throttled to 200 ms per symbol.

FieldTypeNotes
currentTickintegerActive pool tick at snapshot time
ticksobject[]Tick boundaries near currentTick. Each has price, liquidityDelta (signed), cumLiquidity.
impactsobject[]Pre-computed market-impact estimates at $1k / $10k / $100k / $1M notional
impacts[].usdnumberTrade notional in USD
impacts[].buyPricenumberEffective price when buying at this size
impacts[].sellPricenumberEffective price when selling at this size
impacts[].buyPctnumber% premium paid over mid — always ≥ 0
impacts[].sellPctnumber% discount received vs. mid — always ≥ 0
{ "type": "depth", "exchange": "uni", "symbol": "WETH/USDC",
"currentTick": 196234, "time": 1748275200000,
"ticks": [...],
"impacts": [
{"usd": 1000, "buyPrice": 3500.35, "sellPrice": 3499.65, "buyPct": 0.020, "sellPct": 0.020},
{"usd": 10000, "buyPrice": 3501.20, "sellPrice": 3498.80, "buyPct": 0.060, "sellPct": 0.060},
{"usd": 100000, "buyPrice": 3505.00, "sellPrice": 3495.00, "buyPct": 0.180, "sellPct": 0.180},
{"usd": 1000000, "buyPrice": 3540.00, "sellPrice": 3460.00, "buyPct": 1.130, "sellPct": 1.130}
]
}

liquidity — AMM LP Mint/Burn event

One Mint or Burn event on an AMM pool.

FieldTypeNotes
actionstring"mint" = LP adds; "burn" = LP removes
feeTierintegerPool fee in ppm. 500 = 0.05%.
tickLower / tickUpperintegerint24 price range for this position
amountstringRaw uint128 liquidity delta (string to preserve precision)
amount0 / amount1stringRaw token amounts in smallest units (wei / 6-decimal USDC). Divide by 10^decimals for human units.
amountUsdnumberPlatform-estimated USD notional. May be 0 if price feed was unavailable.
ownerstringLP position owner address
blockNumber / txIndexintegerOn-chain location; use for ordering and deduplication
{ "type": "liquidity", "exchange": "uni", "symbol": "WETH/USDC",
"feeTier": 500, "action": "mint",
"tickLower": 195000, "tickUpper": 197000,
"amountUsd": 25000, "time": 1748275200000,
"amount": "12500000000000000000",
"amount0": "3570000000000000000",
"amount1": "12500000000",
"owner": "0xabc...", "blockNumber": 290845001, "txIndex": 17 }

rate_market — yield-market snapshot

Per-market snapshot for Pendle and Spectra. Emitted ~5 s (Pendle) / ~30 s (Spectra).

FieldTypeNotes
addressstringUnique market key (per chain). Use with GET /v1/history/rates/:address.
chainstringarbitrum | base | ethereum
symbolstringHuman-readable PT symbol (e.g. PT-weETH-25JUN2026)
impliedApynumberImplied APY as decimal fraction. 0.131 = 13.1%/yr.
underlyingApynumberUnderlying asset APY
lpApynumberLP fee APY. Always 0 for Spectra v1.
ptPricenumberPendle: USD. Spectra: fraction of IBT (1.0 = at-parity).
ytPricenumberYT price in USD (Pendle)
expiryintegerPT maturity as epoch ms
daysToExpirynumberCalendar days remaining
tvlnumberPendle: USD. Spectra v1: underlying asset units (no USD oracle path).
volume24hnumber24h swap volume. Always 0 for Spectra v1.
{ "type": "rate_market", "exchange": "pendle", "chain": "ethereum",
"address": "0xabc...", "symbol": "PT-weETH-25JUN2026",
"underlyingApy": 0.031, "impliedApy": 0.058, "lpApy": 0.012,
"ptPrice": 0.985, "ytPrice": 0.015,
"expiry": 1751155200000, "daysToExpiry": 28.5,
"tvl": 12500000, "volume24h": 450000,
"time": 1748275200000 }

rate_depth — yield-market depth-at-size

Pendle only. Emitted per poll cycle for individually-subscribed rate markets. Replaces the traditional price-level DOM for rate venues — “price” is an implied APY and cost of execution is size-conditional.

FieldTypeNotes
midRatenumberCurrent mid APY (decimal fraction)
levelsobject[]Sorted ascending by sizeUsd. Each level has sizeUsd, buyRate, sellRate, spreadBps.
levels[].spreadBpsnumberTotal bid-ask spread in APY basis points at that size

Short-dated markets exhibit wider APY spreads for the same price-impact because a given bps of price impact maps to more APY bps as daysToExpiry shrinks.


ammbook — consolidated AMM NBBO

Cross-venue best-bid / best-ask across the four Arbitrum AMMs (uni, univ4, sushi, pancake). One bid and one ask per contributing venue; bids sorted descending, asks sorted ascending.

arbGap is present only when the highest bid (across venues) exceeds the lowest ask on a different venue — a cross-venue arb gap exists.

{ "type": "ammbook", "symbol": "WETH/USDC",
"bids": [
{"exchange": "univ4", "price": 3500.18, "size": 4.1, "feeBps": 3, "time": 1748275200001},
{"exchange": "uni", "price": 3500.15, "size": 3.9, "feeBps": 5, "time": 1748275200001}
],
"asks": [
{"exchange": "sushi", "price": 3500.22, "size": 3.5, "feeBps": 5, "time": 1748275200000},
{"exchange": "uni", "price": 3500.30, "size": 4.0, "feeBps": 5, "time": 1748275200001}
],
"midPrice": 3500.20, "spreadBps": 0.11, "time": 1748275200001 }

ammliquidity_snapshot — LP-event backfill

Sent once on ammliquidity:<symbol> subscribe. Contains up to 1,000 recent liquidity events across all four Arbitrum AMM venues, sorted oldest-first. After this snapshot, subsequent Mint/Burn events arrive as individual liquidity frames.


arbflag — cross-venue arb edge signal

Edge-triggered: one frame on gap open (status: "open"), one on gap close (status: "closed"). Not a continuous stream.

Gated: requires role super_admin.


spread — cross-pool spread (same venue)

Fired when, within a single AMM venue, the best bid in one fee tier exceeds the best ask in another fee tier. Distinct from arbflag (which is cross-venue).

Available on uni and univ4 only.


feed_stale / feed_live

Broadcast to all connected clients on upstream feed staleness transitions. See WebSocket — Heartbeat for thresholds.

{ "type": "feed_stale", "exchange": "hl", "staleSec": 67.4 }
{ "type": "feed_live", "exchange": "hl" }

server_closing

Sent before a planned restart. See WebSocket — Reconnect.

{ "type": "server_closing", "reconnectIn": 5000 }

authed

Reply to a successful {"action":"auth", "key":"mk_live_..."} message.

{ "type": "authed", "tier": "api", "symbolLimit": 100 }

symbolLimit is null for super_admin (unlimited).


error

Sent when the server rejects a client action. The connection remains open after most errors; auth_failed may be followed by a close frame.

{ "type": "error", "code": "symbol_limit_reached", "message": "Tier 'none' allows 3 symbols; you have 3." }

See Errors for the full code reference and retry guidance.