> 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.

# Authentication

**`POST /v1/ws-tickets — sent`**

```json title="POST /v1/ws-tickets — sent"
{
  "stream": "trading"
}
```

**`POST /v1/ws-tickets — received`**

```json title="POST /v1/ws-tickets — received"
{
  "ticket": "<string>",
  "expiresAtNs": "<string>",
  "stream": "trading"
}
```

**`The session is open and authenticated — received`**

```json title="The session is open and authenticated — received"
{
  "event": "sessionOpened",
  "msgType": "sessionOpened",
  "data": {
    "capabilities": [
      "users:manage"
    ],
    "expiresAtNs": "<string>"
  }
}
```

**`Re-authenticate the session — sent`**

```json title="Re-authenticate the session — sent"
{
  "op": "auth",
  "reqId": "<string>",
  "params": {
    "token": "<string>"
  }
}
```

**`Authentication succeeded — received`**

```json title="Authentication succeeded — received"
{
  "op": "auth",
  "reqId": "<string>",
  "success": true,
  "session": {
    "capabilities": [
      "users:manage"
    ],
    "expiresAtNs": "<string>"
  }
}
```

**`A request was refused — received`**

```json title="A request was refused — received"
{
  "op": "auth",
  "reqId": "<string>",
  "success": false,
  "code": "NOT_PRIMED",
  "message": "<string>",
  "retryable": true
}
```

**`This session's credential lapses soon — received`**

```json title="This session's credential lapses soon — received"
{
  "event": "sessionExpiring",
  "msgType": "sessionExpiring",
  "data": {
    "expiresAtNs": "<string>",
    "inMs": 0
  }
}
```

Each frame is its shape, read off the contract: `<string>` stands for a value, and a union shows its first form.

**URL** — No public environment serves this socket yet.

## Credentials

### `ticket`

**Sent as** query parameter `ticket`

The browser's credential: a short-lived, single-use ticket from trading-gateway's `POST /v1/ws-tickets`, on the handshake URL. One of the two schemes, never both.

### `bearer`

**Sent as** header `Authorization: Bearer …` (JWT)

Every other client's credential: the access token as `Authorization: Bearer …` on the handshake, stating an expiry. One of the two schemes, never both.

## Create a WebSocket ticket

**REST API** `POST /v1/ws-tickets`

Exchanges your bearer token for a ticket that opens the trading WebSocket once: pass it as `?ticket=` on the WebSocket URL before `expiresAtNs`. It carries your identity and never outlives your token; never cache or log it. No `Idempotency-Key`: every call mints a new ticket. [The guide](/guides/rest-api-guide#websocket-tickets).

### Request parameters

| Parameter | Type   | Required | Description                                              |
| --------- | ------ | -------- | -------------------------------------------------------- |
| `stream`  | string | Yes      | The WebSocket stream the ticket opens. One of `trading`. |

### Response parameters

| Parameter     | Type   | Required | Description                                                                                                                                                                                |
| ------------- | ------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `ticket`      | string | Yes      | Opaque and URL-safe as served: put it in the WebSocket URL as `?ticket=` unchanged, and never parse it. It opens one session, once.                                                        |
| `expiresAtNs` | string | Yes      | When the ticket stops opening sessions, in epoch nanoseconds: the ticket's lifetime, or your token's expiry if that comes first. Open the WebSocket before then, or create another ticket. |
| `stream`      | string | Yes      | The stream the ticket opens. One of `trading`.                                                                                                                                             |

### Refusals

| Status | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| ------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| 400    | Refused at the door — nothing reached the platform and the key was not journaled: a missing or malformed `Idempotency-Key` or `If-Match`, malformed JSON, a body `userId`, a body restating the path or `If-Match` differently, a money string off its `pattern` (an exponent, a plus sign, a bare point, surrounding whitespace) or past its `maxLength`, or one no value here can state (over 18 fractional digits, or past a 64-bit integer at its own scale), or any other value outside the schema.                                                                                                            |
| 401    | No bearer token, or one that does not verify.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| 403    | Authenticated, but not admitted. `FORBIDDEN_PRINCIPAL`: a token with no `org_id`, a non-ASCII `org_id` or `sub`, a disabled user, or a local binding with no user. `AWAITING_ADMISSION`: your user is not yet admitted — every route but `GET /me` answers this until an administrator admits you. `ORG_NOT_ACTIVE`: your organisation is suspended, pending activation, retired or unregistered. The record owners' 403s (`CAPABILITY_DENIED`, `SELF_APPROVAL`, `NOT_PROPOSER`, …) are refusals on the platform's stream: they carry the position header, and a retried key replays them with `Idempotent-Replay`. |
| 429    | Shed at once: `INBOX_FULL` or `IN_FLIGHT_FULL` (this member's bounds; nothing queued, the key not journaled), the intake's or the ticket route's `RATE_LIMITED`, or the orders owner's `RATE_CEILING` (the organisation's per-minute ceiling — a refusal on the stream, replayed like any, so its `retryable` is `false` and the order goes again under a fresh key). `Retry-After` says when.                                                                                                                                                                                                                      |
| 503    | This member cannot mint tickets now: `NOT_PRIMED` — it is still catching up; retry shortly — or `TICKETS_UNAVAILABLE` — it holds no ticket signing key, so a retry here changes nothing: a browser cannot open the trading WebSocket through this member until it serves tickets, and any other client sends its bearer token on the WebSocket handshake instead.                                                                                                                                                                                                                                                   |

## The session is open and authenticated

The first frame of every session, sent before the client says anything — unless access was revoked between the handshake and this frame, when the first frame is `sessionClosing` (`PRINCIPAL_REVOKED`, 4003, not retryable) instead. The session was authenticated on its handshake, so there is no `auth` to ack, and this carries what the ack carries — the grant, never the grantee. Subscribe straight away. To renew the credential before `expiresAtNs`, re-auth over the open socket with `op: auth`, for the same principal; its answer is `authAck`.

| Parameter        | Type             | Required | Description                                                                                                                                                                                           |
| ---------------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `event`          | string           | Yes      | `sessionOpened`                                                                                                                                                                                       |
| `msgType`        | string           | Yes      | `sessionOpened`                                                                                                                                                                                       |
| `data`           | object           | Yes      | What this session may do and until when — the grant, never the grantee: no identifier rides it. Read at admission and fixed for the session.                                                          |
| > `capabilities` | array of strings | Yes      | Scope strings in choice order — the same vocabulary as the HTTP lane's GET /me, published here as an enum rather than promised in prose. Shape your affordances from these, never from a token claim. |
| > `expiresAtNs`  | string           | Yes      | When this session's credential lapses and the session is closed. "0" for a roster binding, which never expires (local and test only).                                                                 |

## Re-authenticate the session

**Op** `auth`

The in-band re-auth: a session is authenticated on its handshake (a `ticket` or a bearer token), and this op renews its credential over the open socket — answer the `sessionExpiring` hint with it, or schedule it off `expiresAtNs`. It is never the way in: from 1.4.0 a handshake without a credential is refused, so no session ever owes it. The answer carries the GRANT, not the grantee — what this session may do and until when, with no identifier in it, because the client presented the token and already knows who it is.

A session may re-auth with a fresh credential for the SAME principal, which renews its lease. A credential naming a different principal is refused FORBIDDEN\_PRINCIPAL and the session keeps the one it was opened with: the identity is immutable for the life of the socket.

### Request parameters

| Parameter | Type   | Required | Description                                                                                     |
| --------- | ------ | -------- | ----------------------------------------------------------------------------------------------- |
| `op`      | string | Yes      | `auth`                                                                                          |
| `reqId`   | string | Yes      | Echoed byte-exact on the answer. Printable ASCII, escape-free; anything else answers MALFORMED. |
| `params`  | object | Yes      |                                                                                                 |
| > `token` | string | Yes      | The bearer token, verbatim.                                                                     |

### Response parameters

The grant, never the grantee. `capabilities` are the register row's bits — not token claims, so they reflect what an administrator has granted rather than what was true when the token was issued — read **at admission** and fixed for the session. An administrator clearing one does not change an open session's grant: re-auth over the socket to pick up the new set. `expiresAtNs` is when the session closes; schedule a re-auth off it rather than decoding the token.

| Parameter        | Type             | Required | Description                                                                                                                                                                                           |
| ---------------- | ---------------- | -------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `op`             | string           | Yes      | `auth`                                                                                                                                                                                                |
| `reqId`          | string           | Yes      | Echoed byte-exact on the answer. Printable ASCII, escape-free; anything else answers MALFORMED.                                                                                                       |
| `success`        | boolean          | Yes      | `true`                                                                                                                                                                                                |
| `session`        | object           | Yes      | What this session may do and until when — the grant, never the grantee: no identifier rides it. Read at admission and fixed for the session.                                                          |
| > `capabilities` | array of strings | Yes      | Scope strings in choice order — the same vocabulary as the HTTP lane's GET /me, published here as an enum rather than promised in prose. Shape your affordances from these, never from a token claim. |
| > `expiresAtNs`  | string           | Yes      | When this session's credential lapses and the session is closed. "0" for a roster binding, which never expires (local and test only).                                                                 |

### Refusal parameters

| Parameter          | Type             | Required | Description                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                             |
| ------------------ | ---------------- | -------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `op`               | string           | Yes      | The op being answered, or "error" when it could not be read.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                            |
| `reqId`            | string, nullable | Yes      |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `success`          | boolean          | Yes      | `false`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| `code`             | string           | Yes      | A closed enum, but tolerate an unknown value: codes are appended as the surface grows, and `retryable` tells you what to do whatever the code says. The door's codes — `INVALID_*`, `UNKNOWN_INSTRUMENT`, `UNKNOWN_ACCOUNT`, `UNKNOWN_ORDER`, `NOT_SERVING`, `OWNER_ABSENT`, `BACKPRESSURE` — arrived in 1.1.0 beside the ops that write, and are the whole of what that version added here. A client generated against 1.0.0 meets them the first time it sends a write. `UNAUTHENTICATED` is **not emitted from 1.4.0**: every session is authenticated on its handshake, so no op can arrive before authentication. It stays in the set, which is append-only. `OWNER_ABSENT` is **reserved and not emitted by this version**: when the orders owner is not established, a write refuses `NOT_SERVING` today. It is published so that a client's handling of it is written once rather than added later, but do not expect to observe it before a release says otherwise. One of `NOT_PRIMED`, `UNAUTHENTICATED`, `SESSION_EXPIRED`, `RATE_LIMITED`, `MALFORMED`, `UNKNOWN_OP`, `INVALID_TOKEN`, `FORBIDDEN_PRINCIPAL`, `ORG_NOT_ACTIVE`, `AWAITING_ADMISSION`, `FORBIDDEN_CAPABILITY`, `UNKNOWN_TOPIC`, `TOPIC_NOT_ACTIVE`, `TOO_MANY_TOPICS`, `INVALID_FIELD`, `INVALID_PRICE`, `INVALID_QTY`, `INVALID_CLIENT_ORDER_ID`, `UNKNOWN_INSTRUMENT`, `UNKNOWN_ACCOUNT`, `UNKNOWN_ORDER`, `NOT_SERVING`, `OWNER_ABSENT`, `BACKPRESSURE`. |
| `message`          | string           | Yes      | Display text. May change between versions; never parse it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| `retryable`        | boolean          | Yes      |                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                         |
| `failedTopicIndex` | integer          | No       | Present on a topic refusal: the zero-based index into `params.topics` AS SENT of the entry that caused it.                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |

## This session's credential lapses soon

Sent once per credential, one lead time before the lapse. Re-auth over the open socket with a fresh credential for the same principal and keep your subscriptions; renewing re-arms the hint. It exists because a client that schedules its own refresh may simply not be running when its timer fires — a throttled background tab — where an inbound frame is something the browser will deliver.

| Parameter       | Type    | Required | Description       |
| --------------- | ------- | -------- | ----------------- |
| `event`         | string  | Yes      | `sessionExpiring` |
| `msgType`       | string  | Yes      | `sessionExpiring` |
| `data`          | object  | Yes      |                   |
| > `expiresAtNs` | string  | Yes      |                   |
| > `inMs`        | integer | Yes      |                   |