For the complete documentation index, see llms.txt. This page is also available as Markdown.

GET /stream

Public WebSocket stream (legacy)

Public WebSocket stream (legacy).

operationId: connectStream

Declared server: https://api.testnet.nexus.xyz/v1. See Networks.

Not reachable through CCXT. WebSocket transport. Covered by the CCXT Pro channel map, not by a REST unified method.

Authentication: none declared. If access is controlled another way (a query token, for example), the description below says so.

Public WebSocket stream (legacy)

get
/stream

Public market-data WebSocket (legacy). No token and no credentials. Token auth was removed from this endpoint in ENG-3128 — the token store was per-instance, so a token minted on one instance was unknown to another during a rolling deploy and the upgrade failed with a spurious 401. The upgrade is served unauthenticated on purpose: this channel carries only public market data and never per-account data, so security is absent and there is no token parameter.

This is not GET /ws. That endpoint needs a token from POST /ws/token and speaks the op envelope (seq, seq_at_join, since, out_of_sync, subscribe acks); none of that exists here, and nothing below applies to it.

Subscribing. Send one untagged JSON message listing channels:

{"subscribe": ["book:BTC-USDX-PERP", "trades:BTC-USDX-PERP"]}

The first client message fixes the subscription for the life of the connection. A valid subscribe gets no acknowledgement (frames simply start arriving), there is no unsubscribe, and later messages are ignored, so reconnect to change channels.

Channels: book:{market_id} / book:*, trades:{market_id} / trades:*, market_status:{market_id} / market_status:*.

There is no default subscription (ENG-17188). A client that relied on the implicit all-markets subscription must now send an explicit subscribe. If the first message is not a valid subscribe, the server sends one error frame and closes the connection with code 1008 (policy violation), whose close reason is the same code, and no market data is ever sent:

{"type": "error", "code": "unknown_channel", "message": "unknown channel \"trade:*\" (1 unknown in total); known: book, trades, market_status, as <prefix>:* or <prefix>:<market_id>"}
  • invalid_subscribe: the message is not JSON of the form {"subscribe": [channel, ...]}, the list is empty, or the first frame is binary.

  • unknown_channel: the list names a channel outside the set above. One unknown channel refuses the whole subscribe rather than acking the rest, so a typo such as trade:* or book: fails loudly instead of delivering nothing. Market ids are not checked against the listed markets: book:NOPE is accepted and matches nothing.

A client that closes before sending a subscribe gets nothing.

No ADL on this socket. Auto-deleveraging settlement frames are withheld from this unauthenticated socket (ENG-17189), because they identify the accounts involved. adl:{market_id} and adl:* are not channels here, so a subscribe naming either is refused with unknown_channel. ADL history is served only on authenticated reads: GET /markets/{market_id}/adl-events (HMAC) and GET /account/{address}/adl-history (the caller's own account).

Frames. Each server frame is one JSON object tagged by type, with its fields inline — no op, channel or seq envelope:

  • {"type": "BookUpdate", "market_id": "BTC-USDX-PERP", "book": {"bids": [{"price": "64000.5", "quantity": "0.25", "order_count": 2}], "asks": [...], "sequence": 15995}}

  • {"type": "Trade", "market_id": "...", "trade": {...}} — id, symbol, price, amount, cost, side, timestamp, datetime, takerOrMaker, is_liquidation, info. price, amount and cost are JSON numbers, unlike the book's decimal strings.

  • {"type": "MarketHalted", "market_id": "...", "reason": "...", "timestamp": ...} and {"type": "MarketResumed", "market_id": "...", "timestamp": ...}

  • {"type": "gap", "missed": n} — this connection fell behind the server's broadcast buffer. n is a count on the shared broadcast, every channel for every market, not only the ones this connection subscribed to, so read it as "you may have lost up to n of your frames", not as an exact loss: a trades:BTC-USDX-PERP subscriber can see a large n while losing no BTC trade. Nothing is replayed and there is no per-channel sequence to resync from. The next BookUpdate is a full snapshot, so books heal on their own (or read GET /markets/{market_id}/orderbook); trades lost in a gap are not recoverable on this socket, so reconnect to resync, and read GET /markets/{market_id}/trades for the missed ones.

Book frames are snapshots, not deltas. Every BookUpdate carries the full top 20 levels per side: replace the local book, never merge into it. Levels are objects with decimal-string price and quantity and an integer order_count — not the [price, amount] pairs GET /markets/{market_id}/orderbook serves. Frames carry no timestamp (ENG-15966); stamp arrival time if you need the snapshot's age. sequence is monotonic per market but not contiguous: each write takes max(incoming, previous + 1) across two producers, so jumps between consecutive frames are normal and do not mean a frame was missed. It is the same number GET /markets/{market_id}/orderbook returns as nonce, so a REST snapshot and a stream frame can be ordered against each other.

Cadence. The book is polled from the engine about once a second and published on every cycle whether or not it changed, and it is also pushed when an engine OrderBookUpdate is folded in at fill time (ENG-12905). Expect roughly one frame per market per second plus one per book-moving fill.

Connection lifetime. The server sends no pings, expects no heartbeat and has no idle timeout of its own. It keeps reading the socket after the subscribe: a client ping gets a pong, and a client close frame ends the connection. On the public hosts the load balancer closes the connection about 30 s after the upgrade (the backend-service default timeout), with no close frame — clients see 1006. Treat it as a connection lifetime rather than an idle timeout, since a heartbeat does not extend it: reconnect and resubscribe. Because every book frame is a full snapshot, nothing needs replaying.

Responses
101

Switching Protocols — WebSocket upgrade.

No content

get/stream
GET /v1/stream HTTP/1.1
Host: api.testnet.nexus.xyz
Accept: */*
101

Switching Protocols — WebSocket upgrade.

No content


API version 0.9.122

Last updated