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

# WSS /ws/market

> Market-data WebSocket gateway. X-Api-Key at handshake. Channels: token_trade_matches, token_trade_settlements, token_book, token_ohlc, condition_lifecycle, system, plus all_* firehoses.

```
WSS wss://ws-gateway.dev.predictstreet.sde.adifoundation.ai/ws/market
```

Market-data gateway. Use for the public trade tape (matcher +
chain settlements), orderbook snapshots + deltas, OHLC candles, market
lifecycle, and the platform-wide status banner. Trying to subscribe to
a private channel (`user_orders`, `user_fills`, `vault_positions`) on
this gateway returns `{ "code": "forbidden" }` in the `rejected[]`
array — use [`/ws/user`](/api-reference/websocket/user) for
own-activity streams.

## Authentication

Same `X-Api-Key` scheme as the rest of the API — no separate auth
scheme for market data:

| How to send it                                                                                                  |
| --------------------------------------------------------------------------------------------------------------- |
| **`X-Api-Key: ps_live_<keyId>_<secret>`** header on the upgrade request                                         |
| **`?key=<token>`** query parameter — for browser clients that can't set custom headers on the WebSocket upgrade |

Market channels do not require any specific scope — any active key
can subscribe. Missing or invalid keys are rejected at handshake with
**`4401 <reason>`** (same close-code matrix as
[`/ws/user`](/api-reference/websocket/user#close-codes)). Revoking a
key closes every live socket bound to that `keyId` immediately via
Redis pub/sub.

## Connect greeting

```json theme={null}
{
  "type": "connected",
  "data": {
    "gateway":         "market",
    "authMethod":      "api_key",
    "protocolVersion": 2,
    "partnerId":       "cmofzsb0r0000b401xfeiyk2c"
  }
}
```

`partnerId` is the platform-side partner-record id corresponding to
your API key. Useful for correlating WS sessions to your own audit
trail without a separate REST call. Absent on JWT-authenticated
sockets (retail Privy flows).

## Available channels

| Channel                   | `ids` shape                                        | Server pushes                                                                                                                |
| ------------------------- | -------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------- |
| `token_trade_matches`     | one or more `tokenId` (decimal string)             | `trade_matched` per matcher fill                                                                                             |
| `token_trade_settlements` | one or more `tokenId` (decimal string)             | `trade_settled` on chain `OrderFilled`                                                                                       |
| `token_book`              | one or more `tokenId` (decimal string)             | `book_snapshot` (depth 100) on subscribe, then `book_update` / `book_delta`; `book_snapshot_failed` on snapshot fetch errors |
| `token_ohlc`              | one or more `tokenId`                              | `ohlc_update` (`interval: "s5"`)                                                                                             |
| `condition_lifecycle`     | one or more `conditionId` (lowercased bytes32 hex) | `market_paused` / `market_unpaused` / `market_resolved` / `market_status`                                                    |
| `system`                  | must be `["platform_status"]`                      | `platform_status` (frozen / maintenance banner)                                                                              |

See [Server events](/api-reference/websocket/events) for full payload
shapes per `type`.

<Note>
  **Live status:** `token_trade_matches`, `token_trade_settlements`,
  `token_book`, `token_ohlc`, and `system` push reliably today.
  `condition_lifecycle` accepts subscribes but most events are not
  yet emitted by upstream.
</Note>

## `tokenId` and `conditionId` come from REST

Subscribe by **on-chain native ids**, never by app symbol.

```bash theme={null}
# Pass the market SLUG (not symbol) to the root market-detail
# endpoint — breaking change 2026-05-16, see Markets overview.
curl -H "X-Api-Key: ps_live_..." \
  https://core.api.dev.predictstreet.sde.adifoundation.ai/api/markets/{slug}
```

```json theme={null}
{
  "symbol":      "NC26-BIN-83479265",
  "conditionId": "0x22a88c544e7ab9...",
  "yesTokenId":  "60550363974013526351721227761627460394700175914670861601864197814576471666136",
  "noTokenId":   "3448474776790199743770418424395373406530354266022486190942562054524211572097",
  ...
}
```

For neg-risk multi-outcome markets each question carries its own
`conditionId`; resolve outcome token ids through the on-chain
`NegRiskAdapter` before subscribing.

## Subscribe example

<CodeGroup>
  ```javascript Node — X-Api-Key header theme={null}
  import WebSocket from 'ws';

  const KEY = process.env.PREDICTSTREET_API_KEY;
  const ws = new WebSocket(
    'wss://ws-gateway.dev.predictstreet.sde.adifoundation.ai/ws/market',
    { headers: { 'X-Api-Key': KEY } },
  );

  ws.on('open', () => {
    ws.send(JSON.stringify({
      id: 1,
      cmd: 'subscribe',
      params: {
        subscriptions: [
          { channel: 'token_trade_matches',     ids: ['60550363974013526351721227761627460394700175914670861601864197814576471666136'] },
          { channel: 'token_trade_settlements', ids: ['60550363974013526351721227761627460394700175914670861601864197814576471666136'] },
          { channel: 'token_book',              ids: ['60550363974013526351721227761627460394700175914670861601864197814576471666136'] },
          { channel: 'token_ohlc',              ids: ['60550363974013526351721227761627460394700175914670861601864197814576471666136'] },
          { channel: 'condition_lifecycle',     ids: ['0x22a88c544e7ab9...'] },
          { channel: 'system',                  ids: ['platform_status'] },
        ],
      },
    }));
  });

  ws.on('message', (raw) => {
    const ev = JSON.parse(raw.toString('utf8'));
    // route on ev.type / ev.channel / ev.sid / ev.id
  });
  ```

  ```javascript Browser — ?key= query param theme={null}
  const KEY = 'ps_live_<keyId>_<secret>';
  const url = `wss://ws-gateway.dev.predictstreet.sde.adifoundation.ai/ws/market?key=${encodeURIComponent(KEY)}`;
  const ws  = new WebSocket(url);

  ws.addEventListener('open', () => {
    ws.send(JSON.stringify({
      id: 1, cmd: 'subscribe',
      params: { subscriptions: [{ channel: 'token_trade_matches', ids: ['60550363974013526351721227761627460394700175914670861601864197814576471666136'] }] },
    }));
  });
  ```

  ```python Python — X-Api-Key header theme={null}
  import asyncio, json, websockets

  KEY = 'ps_live_<keyId>_<secret>'
  URL = 'wss://ws-gateway.dev.predictstreet.sde.adifoundation.ai/ws/market'

  async def run():
      async with websockets.connect(
          URL, extra_headers={'X-Api-Key': KEY},
      ) as ws:
          await ws.send(json.dumps({
              'id': 1, 'cmd': 'subscribe',
              'params': {'subscriptions': [
                  {'channel': 'token_trade_matches', 'ids': ['60550363974013526351721227761627460394700175914670861601864197814576471666136']},
              ]},
          }))
          async for raw in ws:
              ev = json.loads(raw)

  asyncio.run(run())
  ```
</CodeGroup>

## Subscribe response

```json theme={null}
{
  "id": 1,
  "type": "subscribed",
  "accepted": [
    { "sid": 10, "channel": "token_trade_matches",     "ids": ["60550363974013526351721227761627460394700175914670861601864197814576471666136"] },
    { "sid": 11, "channel": "token_trade_settlements", "ids": ["60550363974013526351721227761627460394700175914670861601864197814576471666136"] },
    { "sid": 12, "channel": "token_book",              "ids": ["60550363974013526351721227761627460394700175914670861601864197814576471666136"] },
    { "sid": 13, "channel": "token_ohlc",              "ids": ["60550363974013526351721227761627460394700175914670861601864197814576471666136"] },
    { "sid": 14, "channel": "condition_lifecycle",     "ids": ["0x22a88c544e7ab9..."] },
    { "sid": 15, "channel": "system",                  "ids": ["platform_status"] }
  ],
  "rejected": []
}
```

## Rejection codes

| `code`                      | When                                                                                                                                                                                                  |
| --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `invalid_params`            | unknown channel, malformed `tokenId` / `conditionId`, missing required `ids`, or `system` `ids` not `["platform_status"]`                                                                             |
| `forbidden`                 | tried a private channel (`user_orders`, `user_fills`, `vault_positions`) on this gateway                                                                                                              |
| `subscription_cap_exceeded` | connection already holds the maximum number of subscriptions (256)                                                                                                                                    |
| `subscription_too_many_ids` | a single subscription / `add_ids` call exceeded the per-channel id cap (100). Message: `"subscription accepts at most 100 ids"`. Split your ids across multiple subscriptions on the same connection. |

## Related

<CardGroup cols={2}>
  <Card title="Commands" icon="terminal" href="/api-reference/websocket/commands">
    update\_subscription / unsubscribe / list\_subscriptions / ping.
  </Card>

  <Card title="Server events" icon="bolt" href="/api-reference/websocket/events">
    Full event payload catalog per channel.
  </Card>
</CardGroup>
