> For clean Markdown of any page, append .md to the page URL. > For a complete documentation index, see https://docs.immix.xyz/guides/quickstart/llms.txt. > For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.immix.xyz/_mcp/server. # Quickstart This walks the market-data WebSocket end to end: connect, authenticate, subscribe, read frames. You need a token first — see [Authentication](/guides/authentication). #### Connect Open a WebSocket to the production endpoint. One connection carries every topic you subscribe to. ```text wss://marketdata.immix.xyz ``` #### Authenticate Send your token as a message once the socket is open — the socket authenticates by message, not in the handshake: ```json {"op": "auth", "reqId": "auth-1", "params": {"token": ""}} ``` The acknowledgement echoes your `reqId`. Wait for it before you subscribe: ```json {"op": "auth", "reqId": "auth-1", "success": true} ``` A token that does not verify is answered `"success": false` with `"error": "invalid_token"`. #### Subscribe A topic is a dotted string: the channel, then the instrument's symbol. ```json {"op": "subscribe", "reqId": "sub-1", "params": {"topics": ["trade.OKX@BTC/USDT", "tob.OKX@BTC/USDT"]}} ``` The acknowledgement answers every topic on its own, in the order you sent them, so one bad symbol never rejects the batch: ```json {"op": "subscribe", "reqId": "sub-1", "success": true, "topics": [{"topic": "trade.OKX@BTC/USDT", "state": "live"}, {"topic": "tob.OKX@BTC/USDT", "state": "live"}]} ``` #### Read frames Every data frame names its event and its topic: ```json {"event": "trade", "topic": "trade.OKX@BTC/USDT", "seq": "…", "seqTs": "…", "data": [{"px": "64887.7", "qty": "0.002", "side": "buy", "tradeId": "…", "exchTs": "…"}]} ``` Prices and quantities are exact decimal strings: parse them with a decimal type, never a float. Sequence numbers and timestamps are decimal strings too, because they exceed what a JSON number holds exactly. ## The same in Python ```python import asyncio import json import os import websockets # pip install websockets URL = "wss://marketdata.immix.xyz" async def expect_ack(ws, op: str) -> None: """Read until the acknowledgement of `op` — a heartbeat may arrive first.""" async for raw in ws: frame = json.loads(raw) if frame.get("op") == op: if not frame.get("success"): raise SystemExit(f"{op} refused: {frame.get('error')}") return async def main() -> None: async with websockets.connect(URL) as ws: await ws.send(json.dumps({"op": "auth", "reqId": "auth-1", "params": {"token": os.environ["IMMIX_TOKEN"]}})) await expect_ack(ws, "auth") await ws.send(json.dumps({"op": "subscribe", "reqId": "sub-1", "params": {"topics": ["trade.OKX@BTC/USDT"]}})) async for raw in ws: frame = json.loads(raw) if frame.get("event") == "trade": for fill in frame["data"]: print(frame["topic"], fill["side"], fill["qty"], "@", fill["px"]) asyncio.run(main()) ``` ## What to know next * **Heartbeats.** Every session receives a heartbeat carrying `streamAgeMs`, the stream-freshness floor: it tells a quiet market from a stalled stream. * **Falling behind.** A session that cannot keep up is disconnected, not throttled. Reconnect, authenticate and subscribe again: a latest-image topic such as `tob` pushes its current image when you subscribe, and a synced book its snapshot. * **Books.** A book topic may answer `syncing` rather than `live`: its snapshot arrives the moment the book is synced. A stale marker means the book cannot be trusted until the restatement that follows it. * **Conflation.** Append a conflation tier to a topic to receive it at a fixed cadence rather than every update — the tiers, every channel and every frame are in the [Market Data WebSocket reference](/api-reference/market-data/overview). > Stream trades from the market-data socket