WebSockets

The exchange pushes real-time updates over a WebSocket endpoint at /ws on the same host as the REST API:

wss://api.testnet.mnx.fi/ws   (testnet)
wss://api.app.mnx.fi/ws      (production)

The protocol is topic-based publish/subscribe: you send a SUBSCRIBE message listing topics, and the server pushes a JSON message whenever an event occurs on one of them.

Subscribing

const ws = new WebSocket('wss://api.testnet.mnx.fi/ws')

ws.onopen = () => {
  ws.send(
    JSON.stringify({
      type: 'SUBSCRIBE',
      topics: ['prices:1', 'market:1:orderbook'],
    })
  )
}

ws.onmessage = (event) => {
  const message = JSON.parse(event.data)
  // Server events: { topics: string[], timestamp, data: { type, ... } }
  // Control acks:  { type: 'SUBSCRIBED' | 'SUBSCRIBE_REJECTED' | ... }
}

The server acknowledges with { "type": "SUBSCRIBED", "topics": [...] }. Topics you are not allowed to subscribe to come back in a SUBSCRIBE_REJECTED message instead. Unsubscribe the same way with { "type": "UNSUBSCRIBE", "topics": [...] }. Event messages carry the topics they were published to, a timestamp, and a data object whose type field identifies the event.

Topics

TopicScopeWhat it carries
prices:<market_id>PublicOracle price updates (PRICE_UPDATED).
funding:<market_id>PublicFunding rate updates (FUNDING_RATE_UPDATED). Funding is the periodic payment between longs and shorts that keeps a perpetual's price anchored to the underlying.
market:<market_id>:orderbookPublicAggregated order book level deltas and refresh signals.
market:<market_id>:statsPublicAggregate market statistics.
user:<user_id>PrivateAll events for your account across markets: orders, positions, balances, leverage adjustments, liquidations, deposits, and withdrawals. The recommended single subscription for account state.
deposits:<user_id>PrivateDeposit events only.
orders:<market_id>:<user_id>, positions:<market_id>:<user_id>, liquidations:<market_id>:<user_id>PrivateGranular per-market slices of your account events. Every user-owned event is also emitted to user:<user_id>, so subscribe to these only when you want narrower streams.

Authenticating for private topics

Private topics require the same credentials as the REST API (see Authentication & signing), supplied inside the SUBSCRIBE message — either an authorization field with a full header value ("Bearer <token>" or "Key <api-key>") or an authToken field with a bearer token value:

{
  "type": "SUBSCRIBE",
  "topics": ["user:123"],
  "authorization": "Key <api-key>"
}

The authenticated user must match the user_id in the topic; otherwise the topic is rejected. Once a connection has authenticated, later SUBSCRIBE messages on the same connection can omit the credential.

Event types

Key data.type values (amounts in WebSocket payloads are raw 1e18-scaled integers — see Getting started):

Keeping an order book in sync

To mirror a market's order book, combine REST snapshots with additive deltas:

  1. Subscribe to market:<market_id>:orderbook.
  2. Fetch a snapshot from GET /v0/orderbook/by-market/:market_id (50 levels per side by default).
  3. Apply ORDERBOOK_LEVEL_DELTA events additively on top. Each delta carries a deltaId for duplicate-delivery protection and a readAfter coordinate; a snapshot already includes all deltas at or below its sequence, so do not re-apply older deltas after a snapshot lands.
  4. On BATCH_ABORTED — the coarse refresh signal for paths that cannot be expressed as a precise level delta — refetch the snapshot (using the event's readAfter).

Connection lifecycle