channel field. This page covers the Spot /ws protocol and payloads. For Testnet-Only Perpetuals, use Perpetual Subscriptions.
Subscribe and Unsubscribe
method is subscribe or unsubscribe. To unsubscribe, send the same subscription object you
subscribed with. Unsubscribing from one type does not affect other subscriptions.
Only subscribe and unsubscribe are supported. This API has no equivalent of posting REST
requests over the WebSocket.
Subscription Fields
These fields are rejected rather than silently ignored:
nSigFigs, mantissa, and
aggregateByTime. These are accepted and ignored, and echoed back in the acknowledgement: dex
(single DEX) and isPortfolioMargin (spot only).
Limits
Resubscribing to a type the client already holds refreshes its TTL and does not consume a second
slot.
Server Messages
Every server message is a two-field envelope:channel is the subscription type that produced the frame, with one exception: userEvents data
arrives with channel set to user.
Three channels carry control messages rather than data:
The acknowledgement echoes the subscription back, including ignored fields. On user types the
user
value is echoed in the format you sent it, even though the server normalizes it internally.
error to the echoed subscription. See Errors.
Snapshot-First Delivery
l2Book, candle, openOrders, userFills, spotState, and userTwapHistory send an initial snapshot on subscribe. The
server acknowledges, sends the snapshot, and only then starts streaming. Live updates that arrive
while the snapshot is being prepared are buffered and flushed after it, so a consumer never sees an
update before the baseline it applies to.
This ordering applies only within one connection. It does not give you a block height for the snapshot or a sequence number shared with REST. See Maintaining a Local Book.
Types at a Glance
Every type is a read-only view of public chain state, the same data REST serves without authentication. Subscribing to a user type exposes no keys and cannot place orders. Field encodings are listed in Overview.Market Types
l2Book
levels[0] is bids, descending by price. levels[1] is asks, ascending. Each frame replaces both
published sides; it is not a delta to merge by price. sz preserves raw base units. n is currently a zero placeholder, not a
usable count of resting orders.
GET /api/v1/orderbook/{symbol}, so switching between the REST
snapshot and this stream needs no re-sorting. See Market Data.
The frame has no block height or sequence. Its initial snapshot uses server time; live frames use
block time. Do not compare time with a REST nonce or use it to promise lossless recovery.
bbo
bbo[0] is the best bid or null, bbo[1] is the best ask or null. Emitted
only when the top of book changed from the previous block.
trades
tid is derived from the order id, block height, and post-fill remaining size, so two same-size
fills on one order in one block stay distinct. It is not the REST trade id and cannot be passed to
GET /api/v1/trade/{id}.
User Types
User types take auser address, given as ault1... or 0x....
orderUpdates
openOrders
orderUpdates.order; dex is always "ault".
For a complete inventory, follow every page of REST orders, which includes
conditional and TWAP parents, for each wallet or derived account you control. Reconcile changes
with orderUpdates and subsequent reads; these interfaces do not share one point-in-time view.
userFills
isSnapshot: true. Live frames carry
isSnapshot: false.
Realized fee amount and asset are used when available. Older records fall back to quote estimates and do not indicate that the value is an estimate. Use
User Fills and confirmed chain records to reconcile fees by currency. Native event granularity depends on the chain
version; see Trade and Fill Data before
building an indexer or treating raw events as these API records.
Against older chain nodes,
crossed may not reflect the actual leg: live fills default to
crossed: true with a taker-rate fee, and older snapshot rows read as crossed: false with a
maker-rate fee. cloid may also be absent on live fills from those nodes. For authoritative fees,
read User Fills.
userEvents
channel set to user, not userEvents. Each frame is one of two shapes: a
nonUserCancel array, or a fills array with the same shape as userFills.
nonUserCancel, which is the only place expiry is reported. A non-user
cancel is currently emitted only for expired orders. The fills shape duplicates userFills, so
there is no need to consume both for fills.
spotState
coin. There is no isSnapshot flag.
hold and total correspond to used and total on Balances. Free
balance is total minus hold.
Keyless Types
allMids
Additional Market and Strategy Channels
candle
Subscribe with{type: "candle", coin: "AULT/USDC", interval: "1m"}. Accepted intervals are
1m, 3m, 5m, 15m, 30m, 1h, 2h, 4h, 8h, 12h, 1d, 3d, 1w, 1M.
The initial array contains up to 300 bars; updates contain one bar. Each bar has
t, T (open/close milliseconds), s (symbol), i (interval), numeric o, c, h, l, v,
and n (trade count, zero for snapshot bars). These intervals differ from REST candle support.
activeAssetCtx
Subscribe with{type: "activeAssetCtx", coin: "AULT/USDC"}. The payload is {coin, ctx}.
Spot ctx.markPx, midPx and circulatingSupply are JSON numbers; last, bid, bidVolume,
ask, askVolume are decimal strings. circulatingSupply is a zero placeholder.
markPx is a Spot display fallback from mid/book/last and is not a Perp risk mark.
There are no 24-hour aggregates: fetch REST tickers. A missing bid/ask means that side is empty;
do not retain a previous quote. Missing 24-hour fields do not erase the separately loaded ticker.
userTwapHistory
Subscribe with{type: "userTwapHistory", user: "ault1..."}. Payload:
{isSnapshot, dex, user, history}. The snapshot has up to 100 newest parents. Each item has
coin, side, sz, depositAsset, numSlices, sliceIndex, oid, oidHex, status,
chainStatus, startTime, deadline, timestamp; priceTolerance, worstPx, closeReason
are optional. sz is human units of the payment asset: base for sells, quote for buys.
It is a strategy budget, not proof of full-parent escrow.
Live frames are emitted only in blocks with a slice execution. Placement and closure produce
no parent frame, so query REST orders to confirm those transitions.
chainBlock
Subscribe with{type: "chainBlock"}. Each frame contains numeric height and timestamp
(milliseconds). Optional hash, proposer, txCount, gasUsed, gasWanted may be absent.
hash is bare uppercase hex. A block frame cannot be used to replay missed data or to mark a point at which all subscriptions are in sync.