| Field | Meaning |
|---|---|
type | Concrete event type (e.g. trade, book_snapshot, platform_status) |
sid | Connection-local subscription id you got from the subscribed response |
channel | One of the channel names from the catalog |
id | The token / condition / system id this event belongs to (omitted on user_activity since the channel is wallet-scoped) |
data | Event-specific payload (catalog below) |
sid to route inside your client; use id to identify which
specific subscribed entity matched.
user_activity (/ws/user, no id)
type | data |
|---|---|
order_placed | exchange payload |
order_cancelled | exchange payload |
trade_matched | off-chain match — exchange payload + recipient-side side. Trade is in DB as matched, not yet on-chain confirmed. |
trade_fill | on-chain settlement confirmed — { side: 'maker' | 'taker', orderHash, makerVault, takerVault, makerAssetId, takerAssetId, makerAmount, takerAmount, fee, blockNumber, txHash }. After this fires, /api/me/balances reflects the trade. |
trade_failed | settlement-leg revert — { orderId, reason, reasonText, txHash }. Locked balance refunded; treat as never settled. |
vault.deploy_confirmed | auto-deploy job mined — { vaultAddress, txHash, blockNumber } |
vault.deposit_confirmed | chain.deposit indexed — { vaultAddress, token, amount, ledgerAfter, txHash } |
user_paused | { user, untilBlock, txHash, blockNumber } |
user_unpaused | { user, txHash, blockNumber } |
trade_failed.reason is the raw 4-byte selector of the on-chain
custom error. The most common is 0xc56873ba = OrderExpired() — see
CTFExchange — MatchFailed reason codes.
vault_activity (/ws/user, ids = vault address[])
Same shape as user_activity but keyed by vault address, not
authenticated wallet. Use it when a single API key needs to watch
many vaults (e.g. multi_wallet partners with N sub-accounts, or
custodial brokers managing multiple end-user vaults). id on each
push is the lower-cased vault address.
Required scope: portfolio:read. Subscription must include at least
one vault id; subscribing without ids returns
{ code: 'invalid_params' }.
type | data |
|---|---|
trade_fill | Same payload as user_activity → trade_fill, but id is the lower-cased vault address. data.side is 'maker' or 'taker' from this vault’s perspective. |
vault.deploy_confirmed,
vault.deposit_confirmed) flow through user_activity only — they
key by wallet, not vault.
all_trades (/ws/market, no id) — firehose
Public chain-confirmed trade firehose across every market. Same
payload shape as token_trades → trade, but emitted regardless of
which token the trade settled. No scope, no ids — every connected
client receives every trade.
Use when building a public ticker / volume scanner. Filter
client-side by data.tokenId or data.marketSymbol. Note that
high-volume markets can push hundreds of events/sec; scope your
client buffers accordingly.
all_books (/ws/market, no id) — firehose
Public order-book delta firehose across every token. Same payload
shape as token_book events, emitted regardless of token. No
scope, no ids.
Use sparingly — book deltas are the noisiest WS surface. Most
partners are better served subscribing to token_book for the
specific markets they trade.
token_trades (/ws/market, id = tokenId) ✅ live
type | data |
|---|---|
trade | { tokenId, marketSymbol, outcomeIndex, tradeId?, price, qty, side, ts, txHash?, blockNumber? } |
marketSymbol and outcomeIndex are emitted on every trade — partners
who subscribe by tokenId but render by (marketSymbol, outcome)
don’t need a separate lookup. tradeId is the matcher-assigned trade
id; txHash / blockNumber appear once the trade settles on-chain
(gateway receives them from chain-watcher).
Live observed example:
GET /api/markets/{symbol}/trades for history.
token_book (/ws/market, id = tokenId) ⚠️ pending
type | data |
|---|---|
book_snapshot | { tokenId, marketSymbol, outcomeIndex, bids, asks, seq, ts } — initial state on subscribe |
book_update | { tokenId, marketSymbol, outcomeIndex, seq, prevSeq, bids, asks, ts } — full top-of-book state at seq (not just the changed levels) |
book_delta | { tokenId, marketSymbol, outcomeIndex, seq, prevSeq, changes, ts } — diff against prevSeq; derived from book_update |
book_update and book_delta are emitted for every matcher book
change — book_update is the raw full-depth replacement, book_delta
is the computed diff. Most integrators want book_delta; book_update
is there for clients that prefer to replay state wholesale without
applying diffs. Subscribing to token_book will push both event
types by default — filter on type client-side if you only want one.
Subscription is accepted today, but neither book_snapshot nor
book_delta is currently pushed by the gateway. Until the
matcher → gateway book pipeline ships, poll
GET /api/markets/{symbol}/orderbook?outcome=N&depth=20 on demand.
When live: seq is monotonically increasing. After subscribe the
server pushes exactly one book_snapshot immediately, then
book_delta events where delta.prevSeq == previously_seen_seq. If
your client sees a gap (delta.prevSeq != last_seen_seq),
unsubscribe and resubscribe to force a fresh snapshot. See
Reconnect — orderbook resync.
condition_status (/ws/market, id = conditionId) ⚠️ pending
type | data |
|---|---|
market_paused | { conditionId, txHash?, blockNumber?, ts } |
market_unpaused | { conditionId, txHash?, blockNumber?, ts } |
market_resolved | { conditionId, resolution, payouts?, txHash?, blockNumber?, ts } |
market_status | { conditionId, status, reason?, ts } |
system (/ws/market, id = "platform_status") ✅ live
type | data |
|---|---|
platform_status | passthrough payload from the platform-status producer |