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

# Live stream

> wss://api-id.cabalspy.xyz/v1/stream: every trade of your users' verified wallets and every new thesis, reply, reaction and removal, pushed live over a WebSocket. Pro plan and up.

The live stream pushes two kinds of events over one WebSocket:

* **Trades**: every trade of your users' verified wallets the moment it is indexed, with the trader's CabalSpy ID profile. It is the live version of [Latest trades](/cabalspy-id/latest) and sends the same trade objects.
* **Theses**: every new [thesis](/cabalspy-id/theses), reply, reaction and removal, on all tokens or on one token. Theses are public, so these events are not limited to your users.

The stream is included from the **Pro** plan. Instances in development or sandbox mode can use it for testing.

<Tip>
  For theses only, use the dedicated [theses stream](/cabalspy-id/theses-stream): it is included on every plan, lets you subscribe to up to 200 tokens per connection and supports the instance reach.
</Tip>

## Connecting

Open a WebSocket and pass your API key as the `api_key` or `apiKey` query parameter, or as an Authorization Bearer header. Choose what you receive with `events`. There is nothing else to subscribe to, the connection starts streaming right away.

```text theme={null}
wss://api-id.cabalspy.xyz/v1/stream?apiKey=YOUR_KEY
wss://api-id.cabalspy.xyz/v1/stream?apiKey=YOUR_KEY&events=theses&blockchain=solana&mint=TOKEN_MINT
wss://api-id.cabalspy.xyz/v1/stream?apiKey=YOUR_KEY&events=trades,theses
```

<ParamField query="apiKey" type="string" required>
  Your API key. `api_key` works too, or an Authorization Bearer header.
</ParamField>

<ParamField query="events" default="trades" type="string">
  `trades`, `theses` or `trades,theses`.
</ParamField>

<ParamField query="blockchain" type="string">
  Only events on this chain. One of solana, bnb, base, eth, rh. Empty means every chain.
</ParamField>

<ParamField query="mint" type="string">
  Only thesis events of this token. Needs blockchain. Trades are not filtered by mint.
</ParamField>

<ParamField query="scope" default="instance" type="string">
  `global` streams trades of every CabalSpy ID user. Enterprise plan only.
</ParamField>

<ParamField query="instance" type="string">
  Your Instance ID. Only needed when your account has several instances.
</ParamField>

<CodeGroup>
  ```javascript JavaScript theme={null}
  const ws = new WebSocket("wss://api-id.cabalspy.xyz/v1/stream?apiKey=YOUR_KEY&events=trades,theses&blockchain=solana");

  ws.onmessage = (e) => {
    const msg = JSON.parse(e.data);
    switch (msg.event) {
      case "trade":
        console.log(msg.data.trader?.username, msg.data.transaction_type, msg.data.token_symbol, msg.data.value_usd);
        break;
      case "thesis":
        console.log("new thesis on", msg.data.mint, "by", msg.data.author.username);
        break;
      case "error":
        console.error(msg.error.code, msg.error.message);
        break;
    }
  };
  ```

  ```python Python theme={null}
  import asyncio, json, websockets

  async def main():
      url = "wss://api-id.cabalspy.xyz/v1/stream?apiKey=YOUR_KEY&events=trades,theses&blockchain=solana"
      async with websockets.connect(url) as ws:
          async for raw in ws:
              msg = json.loads(raw)
              if msg["event"] == "trade":
                  t = msg["data"]
                  print(t["trader"] and t["trader"]["username"], t["transaction_type"], t["token_symbol"])
              elif msg["event"].startswith("thesis"):
                  print(msg["event"], msg["data"]["mint"])
              elif msg["event"] == "error":
                  print("error", msg["error"])

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

## Messages

Every message is a JSON object with an `event` field.

| Event | When | Content |
| - | - | - |
| `subscribed` | Right after connecting. | `data.blockchain` (a chain or `all`), `data.events`, `data.mint` and `data.scope`. |
| `trade` | A trade of one of your users. | `data`, a trade object as in [Latest trades](/cabalspy-id/latest). |
| `thesis` | A new thesis. | `data`, the thesis. |
| `thesis.reply` | A new reply. | `data`, the reply. |
| `thesis.reaction` | Reactions on a post changed. | `data.id` and `data.reactions`, the new counts. |
| `thesis.removed` | A post was deleted or hidden after reports. | `data.id`. |
| `heartbeat` | After 30 seconds without a message from you. | `ts`, Unix time in seconds. |
| `pong` | After you send `ping`. | Nothing else. |
| `error` | The connection is refused. | `error.code` and `error.message`. The server then closes with code 4403. |

```json subscribed theme={null}
{ "event": "subscribed", "data": { "blockchain": "solana", "events": ["theses", "trades"], "mint": null, "scope": "instance" } }
```

```json trade theme={null}
{
  "event": "trade",
  "data": {
    "signature": "5xr8abc...",
    "blockchain": "solana",
    "wallet": "7j7AA3HZR2zEjwAQEKPFh2qucLY4fqZpB9iodf39w8xW",
    "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
    "transaction_type": "buy",
    "token_symbol": "invisibull",
    "token_name": "invisibull",
    "token_logo": "https://...",
    "token_amount": 22113972.03,
    "value": 1.66,
    "value_usd": 137.44,
    "currency": "SOL",
    "timestamp": "2026-10-13T08:03:58Z",
    "trader": {
      "csid_id": "0b7c4a52-3f1e-4f43-9d0a-2b5e7c1d9a11",
      "username": "MazeCCC",
      "name": "Maze",
      "image_url": "https://pbs.twimg.com/profile_images/.../photo.jpg",
      "kol": true
    }
  }
}
```

```json heartbeat theme={null}
{ "event": "heartbeat", "ts": 1791878575 }
```

```json error theme={null}
{ "event": "error", "error": { "code": "plan_required", "message": "The live stream is included from the Pro plan. Your plan: starter." } }
```

### Thesis events

Thesis events carry `blockchain` and `mint` in `data` next to the fields of the post. `thesis` and `thesis.reply` contain the full object as in [List theses](/cabalspy-id/theses-list#response).

```json thesis theme={null}
{
  "event": "thesis",
  "data": {
    "blockchain": "solana",
    "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump",
    "id": "8d1f5a2e-6c4b-4e0f-9a7d-1b2c3d4e5f60",
    "chain": "solana",
    "kind": "thesis",
    "parent_id": null,
    "body": "Strong community, still early.",
    "stance": "bull",
    "author": { "csid_id": "0b7c4a52-3f1e-4f43-9d0a-2b5e7c1d9a11", "username": "MazeCCC", "name": "Maze", "image_url": "https://pbs.twimg.com/profile_images/.../photo.jpg", "kol_badge": true, "profile_url": "https://id.cabalspy.xyz/u/MazeCCC" },
    "likes": 0,
    "replies": 0,
    "reactions": {},
    "my_reactions": [],
    "via": "Example Terminal",
    "created_at": "2026-10-13T09:12:44.512113+00:00",
    "is_mine": false,
    "position": { "private": true }
  }
}
```

```json thesis.reaction theme={null}
{ "event": "thesis.reaction", "data": { "blockchain": "solana", "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump", "id": "8d1f5a2e-6c4b-4e0f-9a7d-1b2c3d4e5f60", "reactions": { "like": 5 } } }
```

```json thesis.removed theme={null}
{ "event": "thesis.removed", "data": { "blockchain": "solana", "mint": "3Pkrq4MmLvDXyn1fa3sz5MekKRkZkc1iLDcz5AzWpump", "id": "8d1f5a2e-6c4b-4e0f-9a7d-1b2c3d4e5f60" } }
```

Client-side apps without an API key can follow one token's theses on the public websocket of the [browser API](/cabalspy-id/theses-browser-api#live-websocket).

## Staying connected

Send the text `ping` at any time to check the connection, the server answers with `pong`. When you send nothing for 30 seconds, the server sends a `heartbeat`. At the same time it picks up users who joined or left your instance and checks that your key is still valid. A revoked or disabled key ends the connection.

Reconnect with a short backoff when the connection drops, and use [Latest trades](/cabalspy-id/latest) or [List theses](/cabalspy-id/theses-list) to fill any gap.

## Limits and errors

Each API key can hold at most 5 stream connections at once.

| Code | Meaning |
| - | - |
| invalid\_api\_key | API key missing, invalid or not enabled for CabalSpy ID. |
| plan\_required | The stream is included from the Pro plan. |
| invalid\_parameter | blockchain, events or mint invalid. |
| missing\_parameter | mint was passed without blockchain. |
| scope\_not\_allowed | scope=global needs the Enterprise plan. |
| too\_many\_connections | At most 5 stream connections per API key. |


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