Overview
markets-service exposes a realtime feed at GET /v1/ws. Connect once and multiplex any
number of channel subscriptions over the same socket. Every stream starts with a snapshot and
then delivers incremental updates, so you never poll GET /v1/book or GET /v1/trades in a
loop.
- Endpoint —
wss://api.numofx.com/v1/ws - Framing — JSON text frames
- Model — snapshot, then a strictly increasing stream of deltas you can resume after a reconnect
Every server frame that belongs to a market carries the
seq it reflects. The snapshot
frame is taken at a specific seq; each following update is the next seq. A gap in the
seq you receive means you missed an event — resume (see Resume after
reconnect).Channels
The
orders channel is scoped to the authenticated owner address. You must send a valid
auth frame before subscribing to it, and you only ever receive your own order events.
Client frames
Send these as JSON text frames. Theop field selects the operation.
Subscribe
One of
subscribe, unsubscribe, auth, ping.book, trades, or orders.Canonical market symbol such as
USDCcNGN-SEP16-2026, or an asset_address:sub_id pair.
Required for book and trades. Optional for orders, where it scopes the stream to a
single market.Optional. The last
seq you processed. When present, the server replays events after that
point instead of sending a fresh snapshot. See Resume after
reconnect.(channel, market) is a no-op.
Unsubscribe
ack frame.
Ping
{ "type": "pong" }. The server also sends protocol-level WebSocket
pings every 15 seconds and drops the connection on missed pongs, so most clients do not need to
send ping themselves.
Auth
Required before subscribing to the privateorders channel. See
Authentication.
Server frames
Thetype field identifies the frame.
Frame shape:
Update payloads
Thedata on an update frame is a compact delta, not the whole book.
snapshot payload mirrors the matching REST response: book snapshots use the same shape
as GET /v1/book, and trades snapshots use the trade list from GET /v1/trades.
Subscribe and snapshot consistency
On subscribe, the server:1
Registers your subscription and buffers live deltas
Nothing is dropped between the read and the first frame.
2
Reads the snapshot at a consistent boundary seq
The snapshot data and its
seq come from a single consistent read.3
Sends the snapshot, then flushes deltas after the boundary
Buffered deltas with
seq <= boundary are dropped, so you never double-apply an event
already reflected in the snapshot.Resume after reconnect
Track the highestseq you have applied per (channel, market). On reconnect, subscribe with
since_seq set to that value:
- If the events after
since_seqare still retained, the server replays them and goes live — no snapshot, no gap. - If
since_seqis older than the retention horizon, the server sendserrorwith coderesume_too_old, followed by a freshsnapshot. Discard your local state and rebuild from the snapshot.
Authentication
Theorders channel requires a signed auth frame. Authentication uses an EIP-191
personal_sign signature over a canonical message, recovered to your owner address.
Build and sign this exact message (unix seconds, no trailing newline):
auth frame:
Your owner address,
0x + 40 hex characters. Recovery must match this address.The
personal_sign signature over the canonical message.A unique value per auth frame.
Unix seconds when the frame was signed. Rejected if far in the future.
Unix seconds when the frame stops being valid. Keep the window short; the server enforces a
maximum TTL.
{ "type": "ack", "message": "authenticated" } and the
connection is authorized for that address until it closes. On failure it replies with an
error frame, code auth_failed.
Error codes
error frames carry a code and a human-readable message.

