Repository navigation
Install: pip install oxarchive==1.12.0
Builds on 1.11.0. Two venues, Hyperliquid and Lighter; Lighter now has two
deployments in the SDK, mainnet (client.lighter) and Robinhood Chain
(client.rh_lighter). The SDK adopts API version 2026-10-01: stable error
codes, has_more on every paged response, the symbol and venue of every
per-symbol response, client.capabilities(), and replay for every L4 and
full-depth channel.
Upgrading from 1.7
The last release on PyPI before this one is 1.7.0; versions 1.7.1 to 1.11.0
were not published, and their changes are listed below. These are the
changes that can break code written against 1.7.0:
- Lighter
funding_rateis a fractional, non-annualized rate, no longer a
percent (1.10.0, Breaking). Remove any division by 100. - Times without a time zone are read as UTC on every method, not as the
machine's local time (this release, Fixed). - Methods that called routes the API does not serve are removed, with their
async versions:client.hyperliquid.hip4.l2_orderbook,
client.spot.orders.flow()andtpsl(), and
client.hyperliquid.hip3.liquidations.by_user()(this release, Removed). - Parameters the API never applied raise
TypeErrorinstead of being
ignored, such asuserorstatusonclient.spot.orders.history()
(this release, Changed). - WebSocket:
subscribe()raisesValueErrorfor a channel without live
data (candles,hip3_candles,hip4_orderbook,hip4_open_interest,
spot_twap),replay()raises it for a channel without replay, and
Lighter replay messages have the live shapes (this release).stream(),
multi_stream()andstream_stop()are deprecated because the server no
longer streams bulk data (1.11.0, Deprecated). - In an L4 snapshot from
l4_orderbook.get(), each resting order's
timestampis an RFC 3339 string, withtimestamp_msbeside it (this
release, Added). SpotPairandSpotTwapStatushave the fields the API returns (1.8.0,
Fixed).
Added
- API version 2026-10-01. Every REST request, sync and async, sends
0xArchive-Version: 2026-10-01(oxarchive.API_VERSION,
oxarchive.API_VERSION_HEADER), andOxArchiveWsconnects with
version=2026-10-01. The SDK parses the shapes this version selects:- Data quality responses, the public coverage summary and
/v1/symbolsanswer with the standard{success, data, meta}envelope;
client.data_quality.*andclient.symbols.list()return the same
models as before. - Record times that were integer milliseconds are RFC 3339 strings with an
integer companion in a field ending_ms.CvdBucket,
Hip3OracleExternalPrice,Hip3OracleDiscoveryBounds,
LighterLiquidationandLighterLiquidationVolumehavetimestampas a
UTCdatetimeandtimestamp_msas Unix milliseconds.
LiquidationLevels,LiquidationLevelsHistoryItemand
TriggerLevelsHistoryItemaddsnapshot_ts_ms(snapshot_tsis RFC
3339). In an L4 snapshot froml4_orderbook.get()(adict), each
resting order'stimestampis an RFC 3339 string withtimestamp_ms
beside it; an unknown queue time isNonewithtimestamp_ms0. - Lighter and Robinhood Chain replay messages have the live shapes: books
{coin, time, levels}, a trade message holds a list with one leg, and
open interest and funding carry{coin, ctx}.
- Data quality responses, the public coverage summary and
- Error codes.
OxArchiveErrorexposeserror_code, the stable code from the
error body (for exampleinvalid_parameter,invalid_symbol,
range_before_coverage,unsupported_for_venue), withstatus(the HTTP
status, the same value ascode),request_id,param,valid_values
anddetails(the whole error body, including route-specific fields such
asavailable_on). A body without a code, such as a proxy error page, gets
one derived from the status. The public set isoxarchive.ERROR_CODESand
theErrorCodetype;WEBSOCKET_ERROR_CODESnames the two WebSocket-only
codes,slow_consumerandendpoint_unsupported.WsErrorhas
error_code.str()of an error includes the code. - Pagination state.
CursorResponse.has_morecomes frommeta.has_more; on
a route that does not send it, it is true exactly whennext_cursoris
set.ResponseMeta.has_moreis typed. The iterators (cvd.iterate()and
the positionsiterate_*()helpers, sync and async) stop whenhas_more
is false. - The symbol and venue of a response.
ResponseMeta.symbol(the canonical
public symbol) andResponseMeta.venue(Venue:hyperliquid,hip3,
hip4,spot,lighterorrh-lighter;VENUESlists them). Every
paged method now returnsmeta. A record a method returns on its own
(order book, funding rate, open interest, instrument, spot pair,
freshness, summary, liquidation and trigger levels, HIP-3 oracle, HIP-4
outcome and question, breadth snapshot, wallet classification and the
data quality results) carries the response's meta asresponse_meta. client.capabilities()andacapabilities()forGET /v1/capabilities:
oneCapabilityper venue and datatype, with its REST routes, WebSocket
channels,live,replay,available_from,cadence,page_limit,
intervalsandnotes.client.data_quality.status_coverage()andastatus_coverage()for the
public coverage summary at/v1/status/coverage.- Filters the API now applies:
side="buy"orside="sell"(TradeSide) ontrades.list(),
trades.history()andtrades.recent(), and their async versions, on
every venue. The API filters before paging, so a full page holdslimit
matching trades.triggeredonorders.history()for Hyperliquid core, HIP-3 and HIP-4.depthonl2_orderbook.history()(Hyperliquid core and HIP-3).
depthonorderbook.history()applies on every venue, including HIP-3,
HIP-4 and spot.
- Consistent verbs, as aliases of the existing methods:
trades.history()andahistory()(the same methods aslist()and
alist()),client.spot.twap.history()andahistory()(by_symbol()
andaby_symbol()), andclient.hyperliquid.hip4.get_price_history()and
aget_price_history()(get_prices()andaget_prices()). Every existing
name keeps working. - WebSocket replay for every L4 channel (
hip3_l4_diffs,hip3_l4_orders,
hip4_l4_diffs,hip4_l4_orders,spot_l4_diffs,spot_l4_orders, as
well asl4_diffsandl4_orders) and for the full-depth L2 channels
orderbook_fullandhip3_orderbook_full. These replays are bulk: one
l4_snapshotfrom the nearest checkpoint at or beforestart, then
orderedl4_batchmessages;speedis ignored,replay.seekis refused,
and each replays on its own. oxarchive.websocket.WS_CHANNELS: oneWsChannelSpecper channel (venue,
datatype,live,replay,bulk_replay), mirroring/v1/capabilities,
withLIVE_CHANNELS,REPLAY_CHANNELS,BULK_REPLAY_CHANNELSand
L4_REPLAY_CHANNELS.subscribe()refuses a channel without live data
(now alsocandles,hip3_candles,hip4_orderbook,
hip4_open_interestandspot_twap),replay()a channel without
replay (ticker,all_tickers,spot_orderbook,spot_trades,
spot_twap), andmulti_replay()also the bulk channels, each with
ValueErrorbefore anything is sent.spot_twapis listed with neither
live nor replay, since/v1/capabilitieslists spot TWAP as REST only;
its error (REST_ONLY_ERROR) says so.OxArchiveWs.on_replay_data(): every replayed record with its channel,
(channel, coin, timestamp, record). Lighter and Robinhood Chain records
are decoded with the live parsers (OrderBook,list[Trade],
LighterMarketContextUpdate);decode_lighter_payload()applies the same
decoding to any payload.WsSubscribed.version,WsReplayStarted.version
andWsReplayStarted.symbolare typed.- Lighter on Robinhood Chain:
client.rh_lighter(RhLighterClient), served
under/v1/rh-lighter. It has the same resources asclient.lighterexcept
the L3 order book and the L1 account resolver:instruments,orderbook,
trades(list()canonical up tometa.finalized_through,recent()
preliminary),candles,open_interest,funding,liquidations,
positions, andget_freshness(),get_summary(),get_price_history().
Markets are USDG-quoted: perps use uppercase symbols (BTC), spot markets
dashed symbols (AAPL-USDG). Trades and liquidations start at the venue
launch, 2026-06-26 20:10:26 UTC; candles start 2026-06-26 20:10 UTC; order
book, open interest and funding start 2026-08-22 18:43 UTC. - Lighter liquidations on both deployments:
client.lighter.liquidationsand
client.rh_lighter.liquidationswithhistory()andvolume()(and async
ahistory()/avolume()), typed asLighterLiquidationand
LighterLiquidationVolume. A row keeps both sides' account fields. On
Robinhood Chain, rows from before live capture were backfilled from the
venue's finalized export and havesource == "bucket"and an empty
raw_json; rows captured live havesource == "ws"and the venue's raw
JSON. Volume buckets carrytotal_usdandcount. - Account positions on four clients with the same method names:
client.hyperliquid.positions,client.hyperliquid.hip3.positions,
client.lighter.positionsandclient.rh_lighter.positions.get(key, timestamp=None, symbol=None): open positions now, or as of any
instant (an exact hour serves the hourly snapshot; any other instant is
reconstructed from the change log). ReturnsWalletPositions
(positions,account,account_seen). On Lighter,accountholds
position aggregates only (totals, long/short value,n_positions).history(key, start, end),changes(key, start, end): hourly position
rows and the change log of every leg that moved a position.market(symbol, hour=None, side=None, min_value=None),
market_summary(symbol, start=None, end=None),all(hour): every open
position in a market (withmeta.totals), long/short aggregates, and a
bulk listing across markets at one hour.account(key)andaccount_history(key, start, end): the account
summary now and hourly. On Hyperliquid and HIP-3 it is the clearinghouse
summary (HIP-3 takes an optionaldex); on Lighter and Robinhood Chain it
holds position aggregates (totals, long/short value,n_positions).
Lighter market methods takeinclude_system.keyis a 0x address on Hyperliquid and HIP-3, and an integer account
index on Lighter.client.lighter.accounts.by_l1(l1_address)resolves an
L1 address to its account indices (Lighter mainnet only).- Cursor-following iterators:
iterate_history(),iterate_changes(),
iterate_market(),iterate_market_summary(),iterate_all(),
iterate_account_history(),client.lighter.accounts.iterate_by_l1(),
andaiterate_*async versions. Every method has ana-prefixed async
version. - Typed models:
Position,PositionLeverage,PositionCumFunding,
PositionChange,MarketPosition,MarketPositionsSummary,
AccountSummary,WalletPositions,LighterL1Account,
LighterL1Accounts. client.data_quality.positions_freshness()(and
apositions_freshness()): onePositionsFreshnessrow per venue with
the latest live and hourly snapshots, the live snapshot's age and
quality,stale,built_throughandfinalized_through.- Coverage: Hyperliquid change log from 2025-05-25, HIP-3 from 2025-10-13,
hourly history from 2026-06-07, live every 5 minutes; Lighter mainnet from
2025-01-17 and Robinhood Chain from 2026-06-26, hourly, live every
2 minutes. Position rows are billed like trades, 1,000 rows per credit;
the account summary routes andby_l1()are billed at the per-request
minimum.
ResponseMetaandCursorResponse.meta: the response'smeta, typed, with
finalized_through,requested_end,clamped_to,coverage_from,
notice, and the new optional fieldsas_of,snapshot_ts,source,
quality,stale,totalsandbuilt_through. Set on every paged
method. Unknown fields are kept.trades.recent()still returns a plain
list, so thepreliminary_row_countthe API sends on the Lighter
/recentresponse is not surfaced in this release.- Live Lighter on Robinhood Chain WebSocket channels
rh_lighter_orderbook,
rh_lighter_trades,rh_lighter_open_interestandrh_lighter_funding,
with the same message shapes as the mainnetlighter_*channels, served on
wss://api.0xarchive.io/ws.rh_lighter_orderbookacceptsinterval_ms
(100 to 5000, default one book per second). New helpers
subscribe_rh_lighter_orderbook(),subscribe_rh_lighter_trades(),
subscribe_rh_lighter_open_interest(),subscribe_rh_lighter_funding()
and theirunsubscribe_*counterparts, and handlers
on_rh_lighter_orderbook(),on_rh_lighter_trades()and
on_rh_lighter_market_context(). Robinhood Chain messages never reach the
mainneton_lighter_*handlers; without a dedicated handler, books and
trades fall back toon_orderbook()andon_trades(). rh_lighter_candlesfor replay. All fiverh_lighter_*channels support
historical replay and multi-channel replay within their family.RH_LIGHTER_LIVE_CHANNELS,RH_LIGHTER_REPLAY_ONLY_CHANNELS,
RH_LIGHTER_REPLAY_CHANNELS,RH_LIGHTER_SUBSCRIPTION_ERRORand
LIGHTER_BOOK_CHANNELSinoxarchive.websocket.orders.flow()andaflow()takecursor(Hyperliquid, HIP-3 and HIP-4).
The API pages order flow: a page holds the oldestlimitbuckets of the
window, andnext_cursoris set while more may follow. Pass it back as
cursorwith the samestart,endandintervaluntil it isNone.
Before this, acursorkeyword was accepted and silently dropped, so every
call returned the first page.- Webhooks:
client.webhooks(WebhooksResource) covers all 21 operations
under/v1/webhooks, each with ana-prefixed async version:
event_types(),limits();list_endpoints(),create_endpoint(),
delete_endpoint(),enable_endpoint(),rotate_secret(),
test_endpoint();list_deliveries(),redeliver();
list_subscriptions(),create_subscription(),update_subscription(),
delete_subscription(),resume_subscription(),
resume_all_subscriptions();dry_run(),estimate();
list_addresses(),add_address(),delete_address(). A subscription
configuration is passed asconfig, a dict or a
WebhookSubscriptionConfig. Subscriptions report their pause state
(status,pause_reason,pause_message, suppressed counts), and a
resume returns the missed window asWebhookResumeGap.limits()
reports the plan's caps, today's delivery budget and the paused count.
Webhook delivery needs a paid plan;estimate()anddry_run()are
available on every plan. - Webhook signature verification in
oxarchive.webhook_signature:
WebhookVerifier,verify_webhook(),verify_webhook_signature(),
parse_signature_header(),WebhookEvent,WebhookSignature,
WebhookSignatureErrorand the header name constants. It verifies the raw
request bytes, accepts everyv1=signature in the header (two during a
secret rotation), enforces a replay window (5 minutes by default) and
compares in constant time. - Webhook models:
WebhookEventType(withWebhookEventTypeParam,
WebhookEventTypeMetric,WebhookCostFloor),WebhookEndpoint,
WebhookEndpointCreated,WebhookEndpointSecret,
WebhookSubscriptionConfig,WebhookSubscriptionCondition,
WebhookSubscription,WebhookSubscriptionResume,
WebhookSubscriptionResumeAll,WebhookResumeGap,
WebhookResumeReplayWindow,WebhookDelivery,WebhookDeliveryQueued,
WebhookRedelivery,WebhookWatchedAddress,WebhookLimits,
WebhookLimitUsage,WebhookDeliveryBudget,WebhookPausedSubscriptions,
WebhookDryRun,WebhookEstimate,WebhookPreviewWindow,
WebhookPreviewOccurrence,WebhookEstimateDayCount,
WebhookEstimateRung,WebhookEstimateDistributionand
WebhookEstimateBasis. Every webhook model keeps unknown fields. - Cumulative volume delta:
client.hyperliquid.cvdand
client.hyperliquid.hip3.cvdwithhistory()(one page; pass
next_cursorback unchanged with the samestart,endandinterval)
anditerate(), which follows the cursor, plusahistory()and
aiterate(). Buckets areCvdBucket; intervals1mto1w
(CvdInterval).cumulative_deltarestarts on every page. - HIP-3 oracle:
client.hyperliquid.hip3.oracle.external_price(symbol)and
discovery_bounds(symbol)(andaexternal_price(),
adiscovery_bounds()), typed asHip3OracleExternalPriceand
Hip3OracleDiscoveryBounds. - HIP-4 questions:
client.hyperliquid.hip4.questions.list()(cursor paged)
andget(question_id), the flat helpers
client.hyperliquid.hip4.list_questions()andget_question(), and their
async versions, typed asHip4Question. - Wallet classification:
client.hyperliquid.wallets.classify()and
client.hyperliquid.hip3.wallets.classify()(andaclassify()), with
every filter, sort andlimit/offsetpaging, typed as
WalletClassification,ClassifiedWalletandWalletClassifyMetrics.
datetakes a date, aYYYY-MM-DDstring or a datetime (a datetime
without a time zone is UTC). - Hyperliquid core breadth:
client.hyperliquid.breadthwithcurrent()and
history()(andacurrent(),ahistory()), the same resource as HIP-3
breadth, served from 2026-08-24. Core responses carry emptynamespaces. - The public symbol universe:
client.symbols.list()andalist(), one
SymbolEntryper market across every venue family, with data types and
coverage dates. - Full-depth L2 WebSocket channels
orderbook_full(Hyperliquid core) and
hip3_orderbook_full(HIP-3), with helperssubscribe_orderbook_full(),
subscribe_hip3_orderbook_full()and theirunsubscribe_*counterparts,
andFULL_DEPTH_L2_CHANNELSinoxarchive.websocket. A subscription or a
replay opens with anl4_snapshotof every price level, thenl4_batch
messages of changed levels, delivered toon_l4_snapshot()and
on_l4_batch(). Stored full-depth history is also on REST
l2_orderbook.history()anddiffs(). client.lighter.l3_orderbook.get()andhistory()takeaccount.- The package ships a
py.typedmarker (PEP 561), so type checkers read its
annotations. TheTyping :: Typedclassifier was already declared.
Changed
- The venue is named "Lighter" throughout docstrings, messages and the
README (was "Lighter.xyz"). client.hyperliquid.trades.recent()still refuses before sending (the API
does not serve it for Hyperliquid core), now with
error_code == "unsupported_for_venue"and a message that names
trades.history()and the venues that serverecent().- HIP-3, HIP-4 and spot L4 channels are no longer refused by
replay().
L4_LIVE_ONLY_CHANNELSis empty andL4_LIVE_ONLY_ERRORis no longer
raised; both are deprecated and kept so imports keep working. - Docstrings and the README list live and replay per channel as
/v1/capabilitiesdoes:hip3_open_interestandhip3_fundingstream
live as well as replay;hip3_candles,hip4_orderbookand
hip4_open_interestare replay-only;spot_twapneither streams nor
replays. subscribe_hip4_orderbook(),subscribe_hip4_open_interest()and
subscribe_spot_twap()raiseValueErrorbefore anything is sent. The
server accepts these subscriptions but sends no data on them: HIP-4 order
book and open interest replay only (follow the live HIP-4 book on
hip4_l4_diffs), and spot TWAP statuses are served over REST only
(client.spot.twap).WsChannelincludes the fiverh_lighter_*channels,orderbook_fulland
hip3_orderbook_full. Before, the acknowledgement, snapshot and batch
messages of the two full-depth channels failed to parse.rh_lighter_candlesraisesValueErrorwithRH_LIGHTER_SUBSCRIPTION_ERROR
on a live subscribe, like the other replay-only Lighter channels.interval_msis accepted onrh_lighter_orderbookas well as
lighter_orderbook. The out-of-range error names the channel it was
passed for.- Data quality docstrings list every venue scope:
hyperliquid,hip3,
hip4,spot,lighterandrh-lighter. LighterClientshares its resources withRhLighterClientthrough a common
base class; its paths and behavior are unchanged.- Parameters the API never applied are removed, and passing one now raises
TypeErrorbefore anything is sent instead of returning unfiltered data:
user,status,order_typeandtriggeredon
client.spot.orders.history()(core, HIP-3 and HIP-4 order history keep
them);depthonl4_orderbook.history()and
lighter.l3_orderbook.history()(it still applies toget()); and
granularityonlighter.l3_orderbook.history(). client.hyperliquid.hip3.breadth.history()andahistory()accept
interval="1m". The API serves 1-minute buckets on breadth, open
interest, funding, price and liquidation-volume history for every venue.
The other methods already passintervalthrough unchanged.- The order-flow docstring and README list the buckets the API serves:
1m
(the default),5m,15mand1h. The docstring used to suggest4hand
1d, which the API refuses.
Removed
- Methods that called routes the API does not serve, so every call failed
with a 404:client.hyperliquid.hip4.l2_orderbook(get(),history(),
diffs()and their async versions). HIP-4 has no full-depth L2 route;
usehip4.orderbookandhip4.l4_orderbook.client.hyperliquid.hip4.orders.trigger_levels()and
trigger_levels_history().client.spot.orders.flow(),tpsl(),trigger_levels()and
trigger_levels_history(). Spot serves order history only.client.hyperliquid.hip3.liquidations.by_user(). The per-user route
exists for Hyperliquid core only.
- The async versions of those methods go with them. The affected resources
are nowHip4OrdersResource,SpotOrdersResourceand
Hip3LiquidationsResource; Hyperliquid core and HIP-3 keep
OrdersResource, and Hyperliquid core keepsLiquidationsResource.
Fixed
import oxarchiveraisedTypeErroron Python 3.9, which the package
declares as supported. Two fields ofSymbolDataTypeCoverage
(historical_coverageandcadence) used theX | Noneannotation
syntax, which Python 3.9 cannot evaluate. They useOptionalnow, and the
test suite passes on Python 3.9.hip4.outcomes.get_by_slug()URL-encodes the slug. Slugs with spaces,
colons,#or/reached the wrong route before.trades.list()andalist()sendcursorback exactly as the API
returned it. A trades cursor is an opaque string such as
"1790640000578_218303497631402"(Lighter adds a third part), and it was
converted as if it were a timestamp, so asking for the second page raised
ValueErroror sent a different cursor. Integer and datetime cursors are
still accepted.CoinFreshness.fundingis optional. HIP-4 has no funding, and
client.hyperliquid.hip4.get_freshness()raised a validation error on
every response.data_quality.symbol_coverage()andasymbol_coverage()send the symbol
as given, URL-encoded as one path segment. They upper-cased it, which
turned case-sensitive HIP-3 symbols such askm:US500into a symbol
with no data, and they did not encode the#of HIP-4 symbols, which cut
the path short.SpotTableFreshnesshas the shape the API returns:symbol,coin,
exchange,measured_at, andorderbook,trades,l4_diffs,
l4_checkpoints,ordersandtwapasDataTypeFreshness. Its
tablesfield was never filled;tablesis now a property that returns
the datasets present.- Times without a time zone are UTC on every method. Before, a naive
datetimeand an ISO string without an offset ("2026-09-01",
"2026-09-01T00:00:00") were read as the machine's local time, so the
same call asked for a different window on machines in different time
zones. A date alone is now midnight UTC and an offset-less date-time is
UTC. A naivedatetime.now()is local wall-clock time; for the current
time pass an aware datetime such asdatetime.now(timezone.utc). Every
resource now converts times with one shared helper, and a value that is
not a timestamp raisesValueErrorinstead of being dropped from the
request.
Documentation
- README sections on the API version, pagination with
has_more, response
metadata, capabilities and error codes; the trades, orders, L2, L3, L4 and
WebSocket replay sections describe the filters and replays above. The
channel tables mirror/v1/capabilities. - The README's coverage table gives each dataset's first served instant on
every venue, as/v1/capabilitiesreports it, and the docstrings give the
same dates. It replaces month-only dates (Hyperliquid "April 2023+", HIP-3
"February 2026+", HIP-4 "May 2026+", spot TWAP "May 2026"), lists
Hyperliquid liquidations from 2025-12-22 (was "May 2025+"), and corrects
the spot L4 start (2026-05-05 22:57 UTC; PURR-USDC from 2026-03-11 01:03
UTC) and the spot candle start (2025-03-22 10:50 UTC). - The Quick Start runs as pasted on any plan: it reads an active HIP-3
market (xyz:TSLA), finds a real wallet for the positions call instead of
a placeholder address, and reads the last hour of order book history. - Examples read recent windows (the last hour, day or week), which every
plan can reach, instead of fixed dates. Several of those dates fell before
the dataset's coverage (candles, the Lighter order book, L2, L3 and L4,
order history and liquidations) or outside the Free plan's 30-day history.
HIP-4 examples find an open outcome instead of a settled one. - The Lighter tick-level example uses
orderbook.history_tick().
orderbook.history()returns snapshots and cannot parse tick data, and its
docstring now says so. - Market counts are no longer pinned;
client.rh_lighter.instruments.list()
andclient.spot.pairs.list()return the current sets. - The HIP-3 coin table is removed, since builders list and delist markets;
callclient.hyperliquid.hip3.instruments.list()for the current set. - Documentation links point at docs.0xarchive.io.
- The breadth
history()docstring saysstartdefaults to 24 hours before
now, as the API applies it, rather than 24 hours beforeend. - The README's order-flow example pages a full day at
1m, following
next_cursoruntil it isNone, and theflow()docstring describes
paging. - A README section on webhooks: plan limits, pauses and resumes, the event
catalog, configuration, previews, verifying deliveries, secret rotation and
retries. - README sections for cumulative volume delta, the HIP-3 oracle, HIP-4
questions, wallet classification, the symbol universe and the full-depth L2
WebSocket channels.