# WebSocket channels

Channels decide which articles reach your connection. Subscribe to as many as you need, up to 200.

## Channel reference

| Channel | Example | Matches |
| --- | --- | --- |
| `all` | `all` | Firehose: every article. |
| `ticker:{SYMBOL}` | `ticker:AAPL` | Articles tagged with a stock or ETF ticker. [GET /tickers](/docs/tickers) lists every symbol that already has at least one article. |
| `category:{id}` | `category:stocks` | Articles in a category. Live coverage is `stocks`. |
| `type:{id}` | `type:press_release` | Stock articles use `news` (stock news), `press_release` and `legal`. |
| `keyword:{text}` | `keyword:rate cut` | Case-insensitive phrase match on title and summary (2–60 characters). |
| `source:{domain}` | `source:businesswire.com` | Every article from one publisher domain. |

## Matching rules

- **OR across channels:** you get an article if it matches any channel you're subscribed to.
- **Delivered once:** an article matching several channels arrives once, with all of them listed in `matched`.
- **Case-insensitive:** `ticker:aapl` equals `ticker:AAPL`.
- **Keywords** are matched as whole phrases against the title and the summary. On `/v1/stream` the summary is still empty, so a phrase that appears only in the summary matches `/v1/stream/summaries` and REST.

## Combining conditions (AND)

Channels are OR-only, which keeps matching fast. For AND conditions, subscribe to the narrower channel and filter in your client. For example, "press releases about my holdings":

```python
HOLDINGS = {"AAPL", "MSFT", "NVDA"}
await ws.send(json.dumps({"action": "subscribe", "channels": [f"ticker:{t}" for t in HOLDINGS]}))

async for raw in ws:
 msg = json.loads(raw)
 if msg["type"] == "article" and msg["data"].get("type") == "press_release":
 alert(msg["data"])
```

## The firehose

`all` delivers every article, typically tens of thousands a day across all categories. Make sure your consumer keeps up. A client that falls too far behind is disconnected with code `4030`.
