/ws/market gateway:
Both are display feeds: they are unsigned, ephemeral, and always
re-confirmed by the read model on the next REST fetch. Never treat a
frame as settlement evidence — the authoritative frozen open is
cryptoWindow.openPrice on the market payload.
crypto_price_tick
- Gateway:
/ws/market ids: one or more crypto instrument ids —BTC-USD,ETH-USD, … (the value oncrypto.instrumentId/event.cryptoSeries.instrumentId). Case-insensitive; the ack echoes them lower-cased.- Required scope: none. The market gateway also accepts anonymous handshakes, so a signed-out browser can subscribe.
- Pushes:
crypto_price_tick
How to consume it
- Fetch the curve once —
GET /api/markets/{symbol}/crypto-price-history?range=10m. - Subscribe to
crypto_price_tickfor that market’sinstrumentId. - Append each tick at its own
at, dropping any tick not newer than the last point you hold.
(instrumentId, at) and duplicates are possible
(multiple producer replicas relaying the same candle). De-duplicating by
at makes them harmless.
The gateway drops ticks that arrive too late to be useful (about 3
minutes for the live feed, 6 for the candle feed) rather than drawing a
stale point on a live chart. The next tick covers the gap.
crypto_window_opened
Fires once per Up/Down window, when the oracle freezes the window’s
open price — the price the window’s close is measured against. The pin
is write-once, so the value in this frame is final.
It rides the per-market market_lifecycle channel, so a window’s page
needs one subscription for the open pin, the status transitions and the
resolution:
- Gateway:
/ws/market ids: one or more marketsymbols (lower-cased; the ack echoes them lower-cased)- Required scope: none
- Pushes:
crypto_window_opened,status_changed,market_disputed,market_resolved
A frame missing
price or decimals is dropped by the gateway rather
than forwarded — a blank open would be indistinguishable from “not
frozen yet”, which is a different state.
The other frames on this channel are market-scoped lifecycle events:
Worked example
BigInt (or a decimal library) — an 18-decimal integer
does not fit a JS number.