Skip to main content

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.
  • Endpointwss://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. The op field selects the operation.

Subscribe

op
string
required
One of subscribe, unsubscribe, auth, ping.
channel
string
book, trades, or orders.
market
string
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.
since_seq
integer
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.
Subscriptions are idempotent — subscribing again to the same (channel, market) is a no-op.

Unsubscribe

The server replies with an ack frame.

Ping

The server replies with { "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 private orders channel. See Authentication.

Server frames

The type field identifies the frame. Frame shape:

Update payloads

The data on an update frame is a compact delta, not the whole book.
The 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 highest seq you have applied per (channel, market). On reconnect, subscribe with since_seq set to that value:
  • If the events after since_seq are still retained, the server replays them and goes live — no snapshot, no gap.
  • If since_seq is older than the retention horizon, the server sends error with code resume_too_old, followed by a fresh snapshot. Discard your local state and rebuild from the snapshot.

Authentication

The orders 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):
Then send the fields in an auth frame:
address
string
required
Your owner address, 0x + 40 hex characters. Recovery must match this address.
signature
string
required
The personal_sign signature over the canonical message.
nonce
string
required
A unique value per auth frame.
issued_at
integer
required
Unix seconds when the frame was signed. Rejected if far in the future.
expiry
integer
required
Unix seconds when the frame stops being valid. Keep the window short; the server enforces a maximum TTL.
On success the server replies { "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.
The server enforces backpressure. If your client cannot keep up with the send rate, the connection is closed with slow_consumer. Reconnect and resume with since_seq rather than holding a slow socket open.