Use
sid to route inside your client; use id to identify which
specific subscribed entity the event belongs to.
Event catalog
user_orders (/ws/user, id = your wallet)
The gateway normalizes these frames to the fields above; a key with no
value for an event is left out.
marketId is the market symbol.
originalQuantity is the order size as placed (on order_placed,
order_cancelled and order_expired) and remainingQty the
unfilled size when the order was cancelled or expired, both in shares
(canonical decimal strings; a self-trade-prevention cancel can lack
both). On a cancel or expiry, originalQuantity - remainingQty is
what had filled when the order ended, not a final fill total.
orderType is LIMIT / MARKET, timeInForce
GTC / IOC / FOK, placedAt the time the exchange accepted the
order, and eventAt the time of a cancel, expiry or rejection (ISO
8601) — order those frames by eventAt, since their tsMs is the send
time.
Key your order state by orderId / clientOrderId. trade_failed
names the market in marketId when it can be resolved.
The order_* frames are state-change notifications, one per transition
of an order, not a snapshot of it: they carry no filledQty (a cancel
or expiry gives only the size filled by then, as above), and their
status is the event label, not the REST order status. For the current
state read GET /api/orders/{id};
the field-by-field mapping is in
user_orders frames vs REST order detail.
user_fills (/ws/user, id = your wallet)
vault_positions (/ws/user, ids = [your vault address])
Amounts are base-unit integers as decimal strings. These frames carry
no
tsMs; order them by blockNumber / logIndex.
vault_position_balance_changed.reason is the vault contract’s
bytes4 tag, sent as hex ("0x53504c54" = SPLT). Values: SPLT
(split), MERG (merge), INFL / OUTF (exchange moved tokens into /
out of the vault on a fill), REDM (redeem), CONV (neg-risk
conversion), EMER (emergency withdrawal). The list is open-ended;
treat unknown tags as a generic balance change. Hex values:
Server events.
vault_activity (/ws/user, ids = [your vault address])
The channel also carries the vault’s other on-chain events (
erc1155_balance,
position_split, positions_merged, position_redeemed,
order_digest_invalidated, emergency_*). Every shape, and how
trade_fill pairs maker and taker events:
Server events.
user_activity (/ws/user, no ids)
It also repeats order and trade events in an unnormalized form; use
user_orders / user_fills for those. For order sizes in particular,
read originalQuantity / remainingQty on user_orders: the raw
qty / remaining here are the event payload as written, and the same
size can be spelled differently on two events ("40.000000" and "40").
notifications (/ws/user, no ids, id = notification id)
The live side of the web app’s notification centre: display text,
created according to the preferences set in the web app, best-effort
and not re-sent after a disconnect. Use the typed channels above for
trading and accounting state.
dispute_intent (/ws/user, id = dispute intent id)
Status changes of disputes filed from the PredictStreet web app. A
challenge sent on-chain directly has no dispute intent, so API
integrations normally see nothing here; follow
GET /api/challenges?challengerWallet=<address> instead.
bond_payout_credited (/ws/user, id = challenge id)
The bond of a challenge you raised was credited back (override: bond
plus reward; void or emergency proposal clear: bond), and the amount is now
claimable from
pendingBondPayouts on the oracle with
withdrawBondPayout(to). See Challenges.
me_limits_invalidated (/ws/user, id = transaction hash)
Your wallet’s on-chain deposit tier, caps or a deposit / trading /
withdrawal restriction changed. The frame carries no values — re-read
GET /api/me/deposit-limits.
dispute_intent, bond_payout_credited and me_limits_invalidated
take your wallet as the only id on an API-key socket
("ids": ["0x…"], the greeting’s walletAddress) and no ids on a
JWT session. Full shapes and examples for all four channels:
Server events.
token_trade_matches (/ws/market, id = tokenId)
Fires the moment the matcher prints a trade — fastest tape feed. On a
binary market each trade is published on both outcome tokens (the NO
frame at price
1 − p, same tradeId); if you subscribe to both,
keep the frame whose outcomeIndex equals takerOutcomeIndex (or
dedupe on tradeId) before counting trades or volume.
token_trade_settlements (/ws/market, id = tokenId)
Fires when the platform indexes an on-chain
OrderFilled event. The
exchange emits one per filled order (each maker order and the taker
order of a match), so one match produces several frames, each
describing the order in orderHash. Use it for accounting-grade
confirmations of your own orders, keyed by orderHash; don’t add the
frames up as independent trades.
Example:
token_book (/ws/market, id = tokenId)
seq is monotonically increasing. After subscribe the server pushes
one book_snapshot (depth 100), then one book_update (the full
state) per book change. Right after each book_update comes a
book_delta for the same change, carrying the same seq and
data.prevSeq; the delta is skipped when the gateway doesn’t hold the
previous state, so it never sends a divergent delta. Apply one stream,
not both: either book_update frames, or book_snapshot +
book_delta frames. In either stream, a frame whose data.prevSeq
differs from the last seq you applied means you missed a change. On
such a gap, or when a market you’d expect to be active goes quiet,
issue
get_book_snapshot
to force a fresh snapshot. See
Reconnect — orderbook resync.
What a book frame holds. book_update is not just the best bid
and ask: it is the complete book after the change,
every resting price level on both sides, aggregated per price. Levels
whose total size is below a small dust threshold are left out of every
book frame, the same filter the REST orderbook applies. book_snapshot
is capped at 100 levels per side, but prices sit on a 0.01 grid, so a
side never has more than 99 levels and a snapshot also carries the
whole book. book_delta carries the same change as a diff. Apply
book_update frames, or book_snapshot + book_delta frames, not
both.
Both book_snapshot and book_update envelopes carry a hash field
(16-hex truncated SHA-256 over canonical (bids, asks) — price +
quantity only, count excluded). The same hash function is applied to
the REST orderbook response. A client that maintains its own book view
can hash it the same way and compare against the envelope hash to
detect drift between the WS-applied state and the authoritative server
view. book_delta envelopes omit hash. To check the book after
applying a delta, compare your hash with the hash of the
book_update that has the same seq — it arrives just before the
delta.
token_ohlc (/ws/market, id = tokenId)
Rolling 5-second candles built from the
trade_matched tape, pushed
whenever a trade prints inside the active window. isClosed: false while the bar is still
accumulating; isClosed: true is the final tick of the bar.
market_price_tick (/ws/market, id = lowercased <symbol>:<outcomeIndex>)
The live edge of
GET /api/markets/{symbol}/price-history: at most
about one frame per second per outcome, only while the market is OPEN
and only when the outcome’s best bid, best ask or last trade changed.
No backfill — seed from ?range=live.
all_trade_matches / all_trade_settlements / all_books (/ws/market, no ids)
Firehoses of the per-token frames for every token on the platform, with
the frame’s
tokenId as id. all_trade_matches still carries two
frames per binary trade, a connection that also holds the per-token
channel gets each frame once per sid, and all_books is high-volume.
Details: Server events.
global_activity (/ws/market, no ids, id = tradeId)
One frame per matched trade platform-wide, in the taker’s view (their
outcome, side and price), with market / event titles and the taker’s
username attached when available. Seed from
GET /api/activity/recent,
which serves the same fields.
condition_lifecycle (/ws/market, id = conditionId)
These are the only frames on this channel. Nothing is pushed on
subscribe, and resolution or status changes are not sent here.
Subscribe to
market_lifecycle (status_changed, market_resolved)
for those, and read the current status from GET /api/markets/{slug}.
market_lifecycle (/ws/market, id = lowercased market symbol)
Keyed by the market
symbol. It carries status, dispute and resolution;
condition_lifecycle carries only the on-chain trading pause. Optional
fields are omitted when absent rather than sent as null.
crypto_price_tick (/ws/market, id = lowercased instrumentId)
The underlying-asset price for crypto markets,
keyed by instrument (
btc-usd). price is an unscaled integer as a
decimal string — render as price / 10 ** decimals with a bigint or
decimal helper. at is the observation time and the point’s
x-coordinate; src is "datastreams" (~1/s live spot) or
"candlestick" (~1/min candle close). See
Crypto price feeds.
Example:
system (/ws/market, id = "platform_status")
To detect a platform freeze, poll
GET /api/platform/status, which
returns { frozen, reason, since, activeNotices }.