WebSocket messages
All messages are JSON text frames.
Client → server
| Action | Example | Purpose |
|---|---|---|
auth | {"action":"auth","api_key":"mna-live-..."} | Authenticate if you didn't pass api_key in the URL. |
subscribe | {"action":"subscribe","channels":["ticker:AAPL"]} | Add channels. |
unsubscribe | {"action":"unsubscribe","channels":["ticker:AAPL"]} | Remove channels. Use ["*"] to remove all. |
list | {"action":"list"} | Get your current subscriptions. |
ping | {"action":"ping"} | Application-level ping. The server replies with pong. |
Server → client
| Type | When |
|---|---|
welcome | After successful authentication. stream is immediate or summaries, and message says whether this socket waits for the summary. |
subscribed / unsubscribed | Confirms a subscription change, with the channels changed and your new total. |
subscriptions | Reply to list. |
article | A new article matching your channels. matched lists the channels it matched. |
heartbeat | Every 30 seconds, so you can detect dead connections. |
pong | Reply to ping. |
error | A non-fatal problem with your last message. The connection stays open. |
article
{
"type": "article",
"matched": [
"ticker:AAPL"
],
"data": {
"id": "art_9f2c1d7e4b8a6035",
"title": "Apple unveils new on-device AI features, shares rise in premarket trading",
"url": "https://www.example-publisher.com/markets/apple-ai-features",
"source": {
"name": "Example Publisher",
"domain": "example-publisher.com"
},
"publisher": "Example Publisher",
"published_at": "2026-10-06T12:31:04Z",
"ingested_at": "2026-10-06T12:31:09Z",
"category": "stocks",
"type": "news",
"tickers": [
"AAPL"
],
"listings": [
{
"symbol": "AAPL",
"exchange": "NASDAQ"
}
],
"snippet": "Apple on Tuesday introduced a set of on-device AI features for iPhone and Mac, sending the stock higher before the open.",
"summary": "Apple announced new on-device AI features for iPhone and Mac. Shares rose about 2% in premarket trading as analysts called the update a catalyst for the upgrade cycle.",
"body": null,
"entities": [
{
"type": "company",
"name": "Apple Inc.",
"symbol": "AAPL"
},
{
"type": "product",
"name": "iPhone"
}
],
"language": "en"
}
}heartbeat
{
"type": "heartbeat",
"time": "2026-10-06T12:31:30Z"
}error
{
"type": "error",
"code": "invalid_channel",
"message": "Unknown channel prefix 'tickr'. See /docs/websocket-channels."
}| Error code | Meaning |
|---|---|
invalid_message | Not valid JSON, or missing action. |
unknown_action | The action isn't one listed above. |
invalid_channel | Malformed channel or unknown prefix. |
too_many_subscriptions | The subscribe would exceed 200 channels. Nothing was added. |
not_authenticated | You sent a command before authenticating. |
Close codes
| Code | Meaning |
|---|---|
1000 | Normal close (you or the server closed cleanly). |
1001 | Server restart during a deploy. Reconnect immediately. |
4001 | Missing or invalid API key. |
4003 | Your plan doesn't include the WebSocket stream (Pro required). |
4008 | Too many concurrent connections for your account (3 on Stream). |
4009 | Authentication timed out: no key in the URL and no auth message within 10 seconds. |
4029 | You sent more than 20 control messages per second. |
4030 | Your client fell too far behind (send buffer full). Read faster or narrow your subscriptions. |
Reconnect on 1001, 1006 and 4030. Don't auto-reconnect on 4001 or 4003, because the same key will fail again.