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

# WebSocket

> GET /v1/ws. Ops subscribe, unsubscribe, ping. Up to 200 channels per socket.

Open `wss://api.raze.bot/v1/ws` (or `wss://ws.raze.bot`, the same socket) with the same key as REST (`?apiKey=` from a browser, `x-api-key` from a server). Send JSON ops, receive JSON frames.

```
→ {"op":"subscribe","id":"t1","channel":"trades","chain":"sol","token":"<mint>"}
← {"type":"subscribed","id":"t1","channel":"trades"}
← {"id":"t1","channel":"trades","chain":"sol","token":"<mint>","type":"snapshot","data":[Trade, …]}
← {"id":"t1","channel":"trades","chain":"sol","token":"<mint>","type":"trade","data":Trade}
→ {"op":"unsubscribe","id":"t1"}
← {"type":"unsubscribed","id":"t1"}
→ {"op":"ping"}
← {"type":"pong"}
```

## Ops

| Field | Used by | Notes |
| - | - | - |
| `op` | all | `subscribe`, `unsubscribe` or `ping` |
| `id` | `subscribe` (optional), `unsubscribe` | Your name for the subscription; every frame of it carries this `id`. Omitted, the server assigns `s1`, `s2`, … An `id` already in use is refused. |
| `channel` | `subscribe` | `trades`, `candles`, `token`, `launchpad`, `prices` or `wallet` |
| `chain` | `subscribe` | Required by `trades`, `candles`, `token`; optional filter on `launchpad`; `sol` for `wallet` |
| `token` | `subscribe` | Token address, for `trades`, `candles`, `token` |
| `interval` | `subscribe` | `candles`: `1s`, `5s`, `15s`, `30s`, `1m`, `5m`, `15m`, `30m`, `1h`, `4h`, `12h`, `1d`, `1w` (default `1m`) |
| `unit` | `subscribe` | `candles`: `usd` (default) or `marketCap` |
| `board` | `subscribe` | `launchpad`: `new`, `graduating` or `graduated` |
| `wallet` | `subscribe` | `wallet`: a Solana address |

## Frames

Every data frame repeats what it belongs to, so one handler can route frames of many subscriptions:

```json theme={null}
{
  "id": "chart",
  "channel": "candles",
  "chain": "sol",
  "token": "DvNcJZTiSMD1RBCtZ2J31mh7s42CVCwrzGapv1Lypump",
  "interval": "1s",
  "unit": "usd",
  "type": "candle",
  "data": { "time": 1790813481000, "open": 0.00062699892, "high": 0.00063716686, "low": 0.00062699892, "close": 0.00063716686, "volume": 1.27 }
}
```

| `type` | When |
| - | - |
| `subscribed` | The subscription is open; its `snapshot` follows |
| `unsubscribed` | The subscription is closed |
| `pong` | Answer to `ping` |
| `snapshot` | First frame of every subscription. Another may follow on the same subscription (after `lagged`, every 15 s on `token`, or when the server reads the history again); it replaces what you hold |
| `trade`, `candle`, `tick`, `add`, `update`, `remove` | Changes; see [Channels](/streaming/channels) |
| `retract` | Solana `trades` only: trades already sent whose block lost its fork; remove them. See [retract](/streaming/channels#retract) |
| `lagged` | You fell behind and lost `dropped` frames |
| `error` | A refused op or a channel that could not start; see [Errors](/get-started/errors#live-errors) |

Route frames on `type` and ignore a `type` you do not know; never treat it as a trade.

## Subscribe on the URL

Query parameters of the upgrade URL subscribe one channel right away, with the same names as the op:

```
wss://api.raze.bot/v1/ws?apiKey=KEY&channel=trades&chain=sol&token=MINT
wss://api.raze.bot/v1/ws?apiKey=KEY&channel=launchpad&board=new
```

More subscriptions can be added on the same socket with `subscribe` ops.

## Lifecycle

* Up to **200** subscriptions per socket.
* The server sends a WebSocket ping every **20 s**; browsers answer it on their own. `{"op":"ping"}` is an extra, application-level round trip.
* Closing the socket ends every subscription on it. To resume after a drop, reconnect and subscribe again: each subscription starts with a fresh `snapshot`.
* While the server is at capacity, the upgrade of a **new** socket answers `503` (`server_busy`, `Retry-After: 30`) instead of `101`. A browser only sees the connection fail, so reconnect with a backoff of at least 30 s. Open sockets keep running and can still subscribe.

## A token page in one socket

```javascript theme={null}
const ws = new WebSocket(`wss://api.raze.bot/v1/ws?apiKey=${KEY}`);
const sub = (id, channel, extra) => ws.send(JSON.stringify({ op: "subscribe", id, channel, ...extra }));

ws.onopen = () => {
  sub("tape", "trades", { chain: "sol", token: mint });
  sub("chart", "candles", { chain: "sol", token: mint, interval: "1s" });
  sub("head", "token", { chain: "sol", token: mint });
};

ws.onmessage = (e) => {
  const f = JSON.parse(e.data);
  switch (`${f.id}:${f.type}`) {
    case "tape:snapshot": tape.reset(f.data); break;          // last 100 trades, newest first
    case "tape:trade":    tape.prepend(f.data); break;
    case "tape:retract":  tape.remove(f.data); break;         // Solana: rows of a block that lost its fork
    case "chart:snapshot": chart.setData(f.data); break;      // last 300 candles, oldest first
    case "chart:candle":  chart.update(f.data); break;        // same time = replace, new time = append
    case "head:snapshot": header.render(f.data); break;       // full Token
    case "head:tick":     header.price(f.data.priceUsd, f.data.marketCapUsd); break;
  }
};
```


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.