# Stream events

Source: https://langbot.ai/docs/api/websocket/stream

`WS /v1/stream`

The live record over one WebSocket, filtered on the server, after your plan's delay.

**Auth.** None. Without a token the call is served as Free (the Free delay and request budget, shared per IP); send `Authorization: Bearer lb_…` for your plan's.

**Limits.** Counts toward your plan's concurrent streams, WebSocket and SSE together (1, 5 or 20). Served at your plan's delay (+60 s Free, +10 s Builder, +2 s Standard).

## Parameters

### Query parameters

| Name | Type | Required | Description |
|---|---|---|---|
| `events` | string | no | Comma-separated event ids (`ev_…`). Empty: every event your plan allows. |
| `phrases` | string | no | Comma-separated phrase keys; filters `phrase_detected` only. |
| `types` | string | no | Comma-separated event types; default everything but `transcript_delta`. |
| `subjects` | string | no | Comma-separated typed-fact subjects (`fact_extracted`). |
| `context` | string | no | Context kinds to opt in to: `on_air`, `topic`, `near_miss`, `typed` or `all`. |
| `token` | string | no | Your token, for browsers that cannot set headers on the upgrade. Elsewhere use `Authorization`. |

## Request

**curl**

```bash
# any WebSocket client, for example websocat
websocat -H "Authorization: Bearer $LANGBOT_API_TOKEN" \
  "wss://api.langbot.ai/v1/stream?phrases=tariff&types=phrase_detected"
```

**Python**

```python
from langbot import LangbotClient

async with LangbotClient() as lb:
    async for evt in lb.stream(phrases=["tariff"], types=["phrase_detected"]):
        print(evt.event_id, evt.phrase, evt.t_spoken)
```

**TypeScript**

```ts
import { LangbotClient } from "@langbotai/sdk";

const lb = new LangbotClient();
for await (const evt of lb.stream({ phrases: ["tariff"], types: ["phrase_detected"] })) {
  console.log(evt.event_id, evt.phrase, evt.t_spoken);
}
```

## Response

`101 Switching Protocols`

```text
{"type":"hello","seq":48212,"ts":1793566860000,"filters":{"events":[],"phrases":["tariff"],"types":["phrase_detected"],"subjects":[],"context":[]},"delay_ms":60000,"plan":"anonymous","effective_plan":"free","user_id":null,"agent":null}
{"id":"evt_01M6CQ02PR3SVZ3TV7FCXH7E09","type":"phrase_detected","event_id":"ev_kxexamplemention_26nov01","phrase":"tariff","t_spoken":1793566809000,"t_emitted":1793566809076,"verdict":{"counts":true,"reason":"mention 1 (1 needed)","role":null},"…":"…"}
{"type":"ping","ts":1793566880000}
```

`hello` comes first, then events and control frames, one JSON object per message. Ops, backpressure, reconnects and close codes: [Protocol](https://langbot.ai/docs/websocket).

## Errors

| Status | `code` | When |
|---|---|---|
| 1008 | `rate_limited` | Your plan's concurrent streams are all open (an error frame, then close 1008). |
| 1008 | `token_invalid` | The token was not recognised (an error frame, then close 1008). |
| 1008 | `validation_error` | `types` or `context` named an unknown value. |
| 401 | `token_invalid` | A token was sent and not recognised. Send a valid one, or none to call anonymously. |
| 422 | `validation_error` | A parameter failed validation; `detail[].loc` names it. |
| 429 | `rate_limited` | Over your request budget; wait `Retry-After` seconds. |

Every error body is `{"detail": …, "code": "…"}`; branch on `code`. All codes: [Errors](https://langbot.ai/docs/api#errors).
