> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.immix.xyz/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": "<your 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).