> ## Documentation Index
> Fetch the complete documentation index at: https://docs.testnet.dev.adipredictstreet.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Message shapes

> Outbound event envelope and the per-channel event catalog.

Every server-to-client push uses the same canonical envelope:

```json theme={null}
{
  "type": "<event_type>",
  "sid": 12,
  "channel": "token_trade_matches",
  "id": "60550363974013526...",
  "serverTs": 1778783112456,
  "data": { ... }
}
```

| Field      | Meaning                                                                                                                                                                                                                                                                                                                                                    |
| ---------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `type`     | Concrete event type (e.g. `trade_matched`, `trade_settled`, `book_snapshot`, `platform_status`)                                                                                                                                                                                                                                                            |
| `sid`      | Connection-local subscription id you got from the `subscribed` response                                                                                                                                                                                                                                                                                    |
| `channel`  | One of the channel names from the catalog                                                                                                                                                                                                                                                                                                                  |
| `id`       | The token / condition / vault / system id that matched (omitted on wallet-scoped channels — `user_orders`, `user_fills`)                                                                                                                                                                                                                                   |
| `serverTs` | Server wall-clock at frame emission, ms since epoch. Present on **every** outbound frame — including `connected`, ACKs, errors, and pong. Use as an authoritative ordering anchor between events arriving on the two transports (the REST companion is the `X-Server-Time` header).                                                                        |
| `seq`      | Monotonic per-channel sequence number — present on `book_snapshot` / `book_update` / `book_delta` (matcher's per-token counter). A jump greater than 1 on the same `id` means a frame was missed and the client should resync. Other event types omit it.                                                                                                  |
| `hash`     | Canonical 16-hex SHA-256 prefix of the book state on `book_snapshot` / `book_update`. The same hash is returned by [`GET /api/markets/{symbol}/orderbook`](/concepts/markets/orderbook) — clients can compare WS view against REST snapshot to detect drift. `book_delta` deliberately omits the hash (a delta is a transformation, not a state snapshot). |
| `data`     | Event-specific payload (see below). Public events carry `tokenId` + `conditionId` + `outcomeIndex` so clients can render by either identifier; resolve symbols through REST if needed. Timestamps in `data` are emitted as `tsMs` (number, ms since epoch).                                                                                                |

Use `sid` to route inside your client; use `id` to identify which
specific subscribed entity the event belongs to.

## Event catalog

### `user_orders` (`/ws/user`, no `id`)

| `type`            | `data`                    |
| ----------------- | ------------------------- |
| `order_placed`    | exchange payload verbatim |
| `order_cancelled` | exchange payload verbatim |

### `user_fills` (`/ws/user`, no `id`)

| `type`      | `data`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                           |
| ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `user_fill` | match-time notification (matcher) — `{ walletAddress, side: 'buy' \| 'sell', tradeId, orderId, clientOrderId?, tokenId, conditionId, outcomeIndex, price, quantity, source: 'matcher', tsMs }`. `fee` / `txHash` / `blockNumber` / on-chain `orderHash` are intentionally omitted; poll [`GET /api/me/trades`](/api-reference/portfolio/me-trades) for the post-settlement view with resolved fee. Full payload reference: [user\_fill](/api-reference/websocket/user#user_fill-vs-apimetrades). |

### `vault_positions` (`/ws/user`, `ids` = vault address\[])

| `type`                           | `data`                                                                                                                                                                                             |
| -------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `vault_position_balance_changed` | `{ vaultAddress, tokenId, conditionId, outcomeIndex, balanceAfter, reason, txHash, blockNumber, tsMs }` — emitted on any ERC-1155 mirror change for the vault                                      |
| `vault_position_split`           | `{ vaultAddress, conditionId, collateralToken, amount, txHash, blockNumber, tsMs }`                                                                                                                |
| `vault_position_merged`          | `{ vaultAddress, conditionId, collateralToken, amount, txHash, blockNumber, tsMs }`                                                                                                                |
| `vault_position_redeemed`        | `{ vaultAddress, conditionId, payouts, txHash, blockNumber, tsMs }` — `payouts` is an `{ [outcomeIndex]: amount }` map; multi-outcome (neg-risk) redeems can pay both YES and NO in the same event |

`vault_position_balance_changed.reason` is a 4-byte ASCII tag from
the upstream chain producer. Known values: `"OUTF"` (output filled —
trade-side credit), `"INFL"` (non-trade inflow), `"SPLT"` /
`"MERG"` / `"REDM"` (split / merge / redeem), `"XFER"` (direct
ERC-1155 transfer). The list is open-ended; treat unknown tags as a
generic balance change.

### `token_trade_matches` (`/ws/market`, `id` = `tokenId`)

| `type`          | `data`                                                                                            |
| --------------- | ------------------------------------------------------------------------------------------------- |
| `trade_matched` | `{ tokenId, conditionId, outcomeIndex, tradeId, price, quantity, side, source: "matcher", tsMs }` |

Fires the moment the matcher prints a trade — fastest tape feed.

### `token_trade_settlements` (`/ws/market`, `id` = `tokenId`)

| `type`          | `data`                                                                                                                 |
| --------------- | ---------------------------------------------------------------------------------------------------------------------- |
| `trade_settled` | `{ tokenId, conditionId, outcomeIndex, orderHash, txHash, blockNumber, price, quantity, side, source: "chain", tsMs }` |

Fires when chain-watcher indexes the on-chain `OrderFilled` event for
the matched trade. Use this for accounting-grade trade confirmations.

Example:

```json theme={null}
{
  "type":    "trade_settled",
  "sid":     13,
  "channel": "token_trade_settlements",
  "id":      "12345...",
  "data": {
    "tokenId":      "12345...",
    "conditionId":  "0xabc...",
    "outcomeIndex": 0,
    "orderHash":    "0x84a930f9e902ae91...",
    "txHash":       "0xc01780b2c76494d8...",
    "blockNumber":  1234567,
    "price":        "0.52",
    "quantity":     "30",
    "side":         "buy",
    "source":       "chain",
    "tsMs":         1776949200000
  }
}
```

### `token_book` (`/ws/market`, `id` = `tokenId`)

| `type`                 | `data`                                                                                                                                                        |
| ---------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `book_snapshot`        | `{ tokenId, conditionId, outcomeIndex, bids, asks, seq, tsMs }` — initial state on subscribe (depth 100)                                                      |
| `book_update`          | `{ tokenId, conditionId, outcomeIndex, seq, prevSeq, bids, asks, tsMs }` — full top-of-book state at `seq`                                                    |
| `book_delta`           | `{ tokenId, conditionId, outcomeIndex, seq, prevSeq, changes, tsMs }` — diff against `prevSeq`; only emitted when the gateway has contiguous local book state |
| `book_snapshot_failed` | `{ tokenId, reason, tsMs }` — snapshot fetch could not be completed (response to `get_book_snapshot`)                                                         |

`seq` is monotonically increasing. After subscribe the server pushes
one `book_snapshot` (depth 100), then `book_update` events.
`book_delta` is emitted only when local book state is contiguous —
the gateway will not emit a divergent delta on a missed frame. If
your client sees a `book_delta` gap (`delta.prevSeq != last_seen_seq`)
or no updates for a market you'd expect to be active, issue
[`get_book_snapshot`](/concepts/websocket/subscriptions#snapshot-refresh-get_book_snapshot)
to force a fresh snapshot. See
[Reconnect — orderbook resync](/concepts/websocket/reconnect#orderbook-resync).

Both `book_snapshot` and `book_update` envelopes carry a `hash` field
(16-hex truncated SHA-256 over canonical `(bids, asks)` — price +
quantity only, count excluded). The same hash function is applied to
the REST orderbook response. A client that maintains its own book view
can hash it the same way and compare against the envelope `hash` to
detect drift between the WS-applied state and the authoritative server
view. `book_delta` envelopes omit `hash` because applying a delta does
not produce a state snapshot — instead, compare your post-apply local
hash against the next `book_update.hash`.

### `token_ohlc` (`/ws/market`, `id` = `tokenId`)

| `type`        | `data`                                                                                                         |
| ------------- | -------------------------------------------------------------------------------------------------------------- |
| `ohlc_update` | `{ tokenId, conditionId, outcomeIndex, interval: "s5", time, open, high, low, close, volume, isClosed, tsMs }` |

Rolling 5-second candles emitted by the matcher whenever a trade prints
inside the active window. `isClosed: false` while the bar is still
accumulating; `isClosed: true` is the final tick of the bar.

### `condition_lifecycle` (`/ws/market`, `id` = `conditionId`)

| `type`            | `data`                                                                                                                                                |
| ----------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `market_paused`   | `{ conditionId, txHash?, blockNumber?, tsMs }` — fired once on the chain transition into a paused state                                               |
| `market_unpaused` | `{ conditionId, txHash?, blockNumber?, tsMs }` — fired once on the chain transition out of a paused state                                             |
| `market_resolved` | `{ conditionId, resolution, payouts?, txHash?, blockNumber?, tsMs }` — fired once when oracle resolves the condition                                  |
| `market_status`   | `{ conditionId, status, reason?, tsMs }` — current authoritative status (catch-all). `status` is one of `OPEN`, `PAUSED`, `RESOLVED`, `EXPIRED`, etc. |

`market_paused` / `market_unpaused` / `market_resolved` are
chain-anchored transitions (one push per on-chain change, with
`txHash` evidence). `market_status` is the current-state mirror —
emitted on subscribe and on every status change. Route by what you
need: audit trail → transitions; UI badge → `market_status`.

### `system` (`/ws/market`, `id` = `"platform_status"`)

| `type`            | `data`                                                |
| ----------------- | ----------------------------------------------------- |
| `platform_status` | passthrough payload from the platform-status producer |

Example:

```json theme={null}
{
  "type": "platform_status",
  "sid": 15,
  "channel": "system",
  "id": "platform_status",
  "data": {
    "frozen": true,
    "reason": "scheduled-maintenance",
    "since": "2026-04-23T18:00:00Z",
    "etaUnfreeze": "2026-04-23T18:30:00Z"
  }
}
```
