WebSocket
Connecting
Open a WebSocket, subscribe to symbols and keep the connection alive.
The WebSocket pushes live data as it changes, so you don't need to poll. It needs Pro+.
Connect
Pass your key as the api_key query parameter:
const ws = new WebSocket("wss://api.q4.sa/v1/ws/stocks?api_key=" + process.env.Q4_API_KEY);
ws.onopen = () => {
ws.send(JSON.stringify({ action: "subscribe", symbols: ["2222", "1120"] }));
};
ws.onmessage = (event) => {
const msg = JSON.parse(event.data);
if (msg.type === "quote") console.log(msg.symbol, msg.price);
};import asyncio, json, os, websockets
async def main():
url = "wss://api.q4.sa/v1/ws/stocks?api_key=" + os.environ["Q4_API_KEY"]
async with websockets.connect(url) as ws:
await ws.send(json.dumps({"action": "subscribe", "symbols": ["2222", "1120"]}))
async for raw in ws:
msg = json.loads(raw)
if msg["type"] == "quote":
print(msg["symbol"], msg["price"])
asyncio.run(main())Actions
| Action | Body | What it does |
|---|---|---|
subscribe | { "action": "subscribe", "symbols": [ … ] } | Start receiving data for these symbols. |
unsubscribe | { "action": "unsubscribe", "symbols": [ … ] } | Stop. |
snapshot | { "action": "snapshot", "symbols": [ … ] } | Send the current state once. |
ping | { "action": "ping" } | Replies { "type": "pong" }. |
Staying connected
- The server sends a ping frame every 30 seconds. Most clients answer it automatically.
- Connections are closed for maintenance about once a day. Reconnect with exponential backoff and subscribe again.
- Outside trading hours the connection stays open but quiet.
Limits
| Plan | Connections | Symbols per connection |
|---|---|---|
| Pro | 2 | 60 |
| Business | 5 | 120 |
| Enterprise | Custom | 200, or * for the whole market |
