WebSocket Streaming
Artery multiplexes four upstream WebSocket feeds onto a single client
connection. You subscribe by provider + market_id, and Artery routes
matching events to your client.
Endpoint
wss://api.artery.questflow.ai/v1/stream?token=<your-api-key>
Pass the API key as token= in the query string — the WS spec doesn't carry
headers, so this is the standard way to authenticate a browser-initiated
connection.
Quick test
bash# Generate a stream-scoped key
TOKEN=$(curl -sS -X POST https://api.artery.questflow.ai/keys \
-H "Content-Type: application/json" \
-d '{"name":"ws-test","userId":"u1","scopes":["stream"]}' \
| python3 -c "import sys,json; print(json.load(sys.stdin)['plaintext'])")
# Connect and subscribe (using websocat or wscat)
wscat -c "wss://api.artery.questflow.ai/v1/stream?token=$TOKEN" \
-x '{"type":"subscribe","channels":["artery:stream:hyperliquid_perp:*"]}'
# → {"type":"subscribed","subscription_id":"..."}
# → {"type":"event","subscription_id":"...","data":{...}} (every ~50ms)Wire protocol
Channels are identified by flat strings of the form
artery:stream:{provider}:{marketKey}. Use * as marketKey to match
all markets for that provider/feed.
json// → server
{
"type": "subscribe",
"channels": [
"artery:stream:polymarket:0xCONDITION_ID",
"artery:stream:kalshi:KX-T",
"artery:stream:hyperliquid_perp:BTC",
"artery:stream:hyperliquid_perp:*"
]
}
// ← server
{ "type": "subscribed", "subscription_id": "uuid-1" }
// streamed events
{
"type": "event",
"subscription_id": "uuid-1",
"data": {
"type": "hyperliquid.allMids",
"provider": "hyperliquid_perp",
"marketId": "BTC",
"payload": { /* native upstream JSON */ },
"receivedAt": 1714928400123
}
}Each event's type is {provider}.{native_event_type} — for example
polymarket.price_change, kalshi.orderbook_delta, hyperliquid.l2Book.
| Channel | What it carries |
|---|---|
artery:stream:hyperliquid_perp:* | All HL allMids updates (every ~50ms) |
artery:stream:hyperliquid_perp:BTC | HL l2Book for BTC perp (when l2Book worker is enabled) |
artery:stream:hyperliquid_perp:100000421 | HIP-4 outcome asset id |
artery:stream:polymarket:<token_id> | Polymarket price_change / last_trade_price for one token |
artery:stream:kalshi:<ticker> | Kalshi orderbook_delta (planned — RSA-gated) |
Subscription limits
| Tier | Concurrent WS connections |
|---|---|
free | 1 |
builder | 5 |
pro | 50 |
enterprise | unlimited |
Each connection can hold up to 1000 active subscriptions.
Heartbeat
Every 30 seconds the server pushes a JSON keepalive frame:
json{ "type": "pong" }Clients don't have to reply — the server tracks the timestamp of any
inbound frame as proof-of-life. Connections with no inbound frame for >60
seconds are closed (close code 1001).
Clients can send {"type":"ping"} to bump their last-seen counter and
will get back {"type":"pong"} as ack.
json// → server (optional, only if you want to be explicit)
{ "type": "ping" }
// ← server
{ "type": "pong" }Per-provider notes
- Polymarket: V2 protocol (
{ type: 'market', assets_ids, custom_feature_enabled: true }) - Kalshi: public channels only for now (private channels require RSA upload — planned)
- Hyperliquid: 1000 subs/conn limit; 10 unique users across user-scoped subs
- HyperEVM DEX: no WebSocket (HyperEVM RPC doesn't expose WS JSON-RPC) — use polling