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

# WebSocket Channels

> Reference for all four StratAlerts WebSocket channels — required scopes, symbol subscription rules, event payloads, and subscribe/unsubscribe examples.

## Quotes, States, and Alerts

The WebSocket API organizes its event streams into four channels. Two channels — `quotes` and `states` — deliver per-symbol events and require you to subscribe with an explicit list of ticker symbols. The other two — `alerts.in_force` and `alerts.simultaneous_breaks` — are account-wide streams that deliver all events globally; no symbol list is needed. Each channel requires the `ws:connect` scope on your key plus the channel-specific scope listed below.

<Note>
  Your key must have **both** `ws:connect` and the channel-specific scope to subscribe. If your key is missing a channel's scope, that channel is silently excluded from the acknowledgment. Check the `channels` array in the `subscribed` response to confirm which subscriptions were accepted.
</Note>

<Warning>
  On `quotes` and `states` topics, `symbols` must be a JSON array — for example, `["AAPL"]`. If you pass a string such as `"AAPL"`, the server treats the payload as malformed and subscribes you to **zero** symbols. The channel is still echoed back in the `subscribed` acknowledgment, but no per-symbol events are delivered until you resubscribe with a proper array. Always wrap symbols in an array, even when subscribing to one ticker.
</Warning>

***

## `quotes`

Delivers real-time price updates as trades occur for each symbol you subscribe to.

| Property                 | Value         |
| ------------------------ | ------------- |
| **Required scope**       | `prices:read` |
| **Symbol list required** | Yes           |
| **Event type**           | `quote`       |

### Event payload

```json theme={null}
{
  "type": "quote",
  "ts": "2026-04-10T14:35:00.887341+00:00",
  "seq": "7",
  "data": {
    "symbol": "AAPL",
    "price": 198.50,
    "volume": 1234567,
    "event_ts": "2026-04-10T14:35:00.712000+00:00"
  }
}
```

| Field      | Type    | Description                                        |
| ---------- | ------- | -------------------------------------------------- |
| `symbol`   | string  | Uppercase ticker symbol                            |
| `price`    | number  | Trade price                                        |
| `volume`   | integer | Cumulative volume at the time of this update       |
| `event_ts` | string  | ISO 8601 timestamp of the originating market event |

### Subscribe

```json theme={null}
{
  "op": "subscribe",
  "topics": [
    { "channel": "quotes", "symbols": ["AAPL", "SPY", "QQQ"] }
  ]
}
```

### Unsubscribe

You can unsubscribe from individual symbols without affecting others. Symbols you are still subscribed to continue delivering events.

```json theme={null}
{
  "op": "unsubscribe",
  "topics": [
    { "channel": "quotes", "symbols": ["QQQ"] }
  ]
}
```

***

## `states`

Delivers real-time TFC state and setup updates for each symbol you subscribe to. A `state` event fires when a symbol's candle state changes on any tracked timeframe — for example, when a daily 2U break occurs or a weekly 1 completes.

| Property                 | Value         |
| ------------------------ | ------------- |
| **Required scope**       | `states:read` |
| **Symbol list required** | Yes           |
| **Event type**           | `state`       |

### Event payload

The `data` object contains the symbol's current state snapshot at the time of the update. The exact fields reflect the same structure returned by the `/states/{symbol}` REST endpoint.

```json theme={null}
{
  "type": "state",
  "ts": "2026-04-10T14:35:01.004512+00:00",
  "seq": "12",
  "data": {
    "symbol": "AAPL"
  }
}
```

<Note>
  The full state payload includes TFC colors, candle IDs per timeframe, and active setup data. The structure matches the `/states/{symbol}` REST endpoint response. Refer to the [REST states reference](/api/rest/states) for field-level documentation.
</Note>

### Subscribe

```json theme={null}
{
  "op": "subscribe",
  "topics": [
    { "channel": "states", "symbols": ["AAPL", "NVDA"] }
  ]
}
```

### Unsubscribe

```json theme={null}
{
  "op": "unsubscribe",
  "topics": [
    { "channel": "states", "symbols": ["NVDA"] }
  ]
}
```

***

## `alerts.in_force`

Delivers a pushed event each time an in-force alert fires anywhere in the scan universe. This channel is account-wide — once subscribed, you receive every in-force alert without specifying symbols.

| Property                 | Value            |
| ------------------------ | ---------------- |
| **Required scope**       | `alerts:read`    |
| **Symbol list required** | No               |
| **Event type**           | `alert.in_force` |

An in-force alert fires when price breaks the trigger level of a recognized setup, making the trade active. This corresponds to the same alerts surfaced in Mission Control's alerts stream and delivered via push notifications.

### Event payload

```json theme={null}
{
  "type": "alert.in_force",
  "ts": "2026-04-10T14:35:02.341800+00:00",
  "seq": "19",
  "data": {
    "symbol": "SPY",
    "timeframe": "Daily",
    "setup": "2-1-2U",
    "direction": "Up",
    "price": 561.40,
    "alert_ts": "2026-04-10T14:35:02.100000+00:00"
  }
}
```

<Note>
  The fields in `data` reflect the alert payload as produced by the StratAlerts alert engine. Field availability may vary by alert type and instrument. Always code defensively against missing keys.
</Note>

### Subscribe

No symbol list is needed. A single subscription receives all in-force alerts across every scanned instrument.

```json theme={null}
{
  "op": "subscribe",
  "topics": [
    { "channel": "alerts.in_force" }
  ]
}
```

### Unsubscribe

```json theme={null}
{
  "op": "unsubscribe",
  "topics": [
    { "channel": "alerts.in_force" }
  ]
}
```

***

## `alerts.simultaneous_breaks`

Delivers a pushed event each time a simultaneous break is detected — when multiple instruments break the same type of level in the same direction within a short time window. Like `alerts.in_force`, this is an account-wide channel with no symbol list.

| Property                 | Value                      |
| ------------------------ | -------------------------- |
| **Required scope**       | `alerts:read`              |
| **Symbol list required** | No                         |
| **Event type**           | `alert.simultaneous_break` |

Simultaneous breaks signal coordinated directional activity across multiple instruments and are surfaced separately in Mission Control. Subscribing to this channel lets you ingest those events programmatically.

### Event payload

```json theme={null}
{
  "type": "alert.simultaneous_break",
  "ts": "2026-04-10T14:35:05.908211+00:00",
  "seq": "24",
  "data": {
    "direction": "Up",
    "timeframe": "Daily",
    "symbols": ["SPY", "QQQ", "IWM"],
    "break_ts": "2026-04-10T14:35:05.700000+00:00"
  }
}
```

<Note>
  The fields in `data` reflect the simultaneous break payload as produced by the alert engine. Field availability may vary. Always code defensively against missing keys.
</Note>

### Subscribe

```json theme={null}
{
  "op": "subscribe",
  "topics": [
    { "channel": "alerts.simultaneous_breaks" }
  ]
}
```

### Unsubscribe

```json theme={null}
{
  "op": "unsubscribe",
  "topics": [
    { "channel": "alerts.simultaneous_breaks" }
  ]
}
```

***

## Subscribing to multiple channels at once

You can subscribe to multiple channels in a single message. The server processes all topics and returns one acknowledgment listing every channel it accepted.

```json theme={null}
{
  "op": "subscribe",
  "topics": [
    { "channel": "quotes", "symbols": ["AAPL", "SPY"] },
    { "channel": "states", "symbols": ["AAPL"] },
    { "channel": "alerts.in_force" },
    { "channel": "alerts.simultaneous_breaks" }
  ]
}
```

Response:

```json theme={null}
{
  "type": "subscribed",
  "ts": "2026-04-10T14:35:00.123456+00:00",
  "seq": "1",
  "data": {
    "channels": ["quotes", "states", "alerts.in_force", "alerts.simultaneous_breaks"]
  }
}
```

<Tip>
  Send all your subscriptions in one message immediately after connecting rather than as separate messages. This reduces round trips and ensures you do not miss events that fire during the gap between individual subscription requests.
</Tip>

## Channel scope summary

| Channel                      | Scope required               | Symbol list |
| ---------------------------- | ---------------------------- | ----------- |
| `quotes`                     | `ws:connect` + `prices:read` | Yes         |
| `states`                     | `ws:connect` + `states:read` | Yes         |
| `alerts.in_force`            | `ws:connect` + `alerts:read` | No          |
| `alerts.simultaneous_breaks` | `ws:connect` + `alerts:read` | No          |

## Related

<CardGroup cols={2}>
  <Card title="WebSocket overview" icon="plug" href="/api/websocket/overview">
    Connection setup, authentication, close codes, and reconnection strategy.
  </Card>

  <Card title="Authentication" icon="key" href="/api/authentication">
    How to obtain an API key and understand which scopes each key carries.
  </Card>
</CardGroup>
