Error Handling & Reconnection
HTTP errors (during handshake)
If authentication or rate limiting fails, the server rejects the WebSocket upgrade with an HTTP error:
| HTTP Code | Reason | Action |
|---|---|---|
400 | Malformed request | Fix your WebSocket client |
401 | Missing API key | Add X-API-Key header |
403 | Invalid, revoked, or expired key | Contact administrator for a new key |
429 | Rate limit or connection limit exceeded | Wait and retry with backoff |
WebSocket close codes
Once connected, the server may close your connection with a close frame. The reason field tells you why:
| Code | Reason | Meaning | Should reconnect? |
|---|---|---|---|
1000 | key_expired | Your API key’s expiration date has passed | No – get a new key |
1000 | key_revoked | Administrator revoked your key | No – get a new key |
1008 | too_slow | You fell 10+ messages behind (lagging consumer) | Yes |
1008 | rate_limit_exceeded | You sent too many messages to the server (>3/min) | Yes – stop sending messages |
1009 | frame_too_large | You sent a frame larger than 1 KB | Yes – stop sending large frames |
Recommended reconnection strategy
Exponential backoff
Attempt 1: wait 1 second
Attempt 2: wait 2 seconds
Attempt 3: wait 4 seconds
Attempt 4: wait 8 seconds
...
Cap: 300 seconds (5 minutes)
Decision logic
On disconnect:
|
|-- Close reason = "key_expired" or "key_revoked"?
| → Stop. Your key is no longer valid.
|
|-- Close reason = "rate_limit_exceeded"?
| → Wait 60s, then reconnect. Stop sending messages.
|
|-- Close reason = "too_slow"?
| → Reconnect immediately. Process messages faster.
|
|-- HTTP 429?
| → Back off. You're connecting too frequently.
|
|-- Unexpected disconnect / network error?
→ Reconnect with exponential backoff.
Heartbeat-based health check
Monitor heartbeats to detect silent disconnections:
import asyncio
HEARTBEAT_TIMEOUT = 35 # seconds
async def monitor_connection(ws):
while True:
try:
msg = await asyncio.wait_for(ws.recv(), timeout=HEARTBEAT_TIMEOUT)
data = json.loads(msg)
if data["type"] == "announcement":
handle_announcement(data)
except asyncio.TimeoutError:
print("No heartbeat received -- reconnecting")
break # Exit loop and reconnect
The server sends heartbeats every 30 seconds. If you receive nothing for 35 seconds, assume the connection is dead and reconnect.