Before upgrade, authentication and connection/admission errors are HTTP responses. After upgrade, application errors arrive as error envelopes. A transport failure or a forced close can occur without a final application error message.
| HTTP status | Meaning |
|---|---|
401 | Missing or invalid API key |
429 | Rate limit or per-API-key connection limit reached |
503 | Server connection capacity unavailable |
X-WS-Error carries a short description. A simultaneous connection race can reject a socket just after upgrade with PolicyViolation, without an error envelope; wait and check existing connections before retrying. Do not assume every policy close has the same cause.
An account request can report several field errors together:
{
"msg_type": "error",
"id": "msg_675d3f4bbc7e4f27aadd0db8444f",
"request_id": "bad-account-sub",
"timestamp": "2026-10-26T15:00:00Z",
"v": 4,
"payload": {
"errors": [
{
"code": "MANDATORY_PARAM_EMPTY_OR_MALFORMED",
"field": "payload.account",
"message": "Missing parameter"
},
{
"code": "INVALID_PARAMETER",
"field": "payload.broker_id",
"message": "Invalid parameter"
}
]
}
}A single error uses payload.code, optional field and message. Multiple errors use the payload.errors array. Echoed request_id associates a rejection with its request even while other data and heartbeats are arriving.
| Account validation | Result |
|---|---|
Missing/blank payload.account | MANDATORY_PARAM_EMPTY_OR_MALFORMED |
| Account longer than 45 characters | INVALID_PARAMETER |
Missing, zero or negative payload.broker_id | INVALID_PARAMETER |
Explicit zero or negative payload.person_id | INVALID_PARAMETER |
Any account payload.resume_from | INVALID_PARAMETER because account replay is unsupported |
| Unknown action/channel, malformed envelope or timestamp outside one minute of UTC | Validation error on the affected field |
Omitted person_id uses the authenticated session person; an explicit value does not grant access to someone else's account. Authorization checks the selected exact account/broker owner and current channel permissions/site authority.
| Code | Meaning and action |
|---|---|
FORBIDDEN | Account/strategy authority denied. Correct access before retrying |
ALREADY_EXISTS | The channel and physical identity are already subscribed or pending. A different person override does not create a second account subscription |
NOT_FOUND | Unsubscribe requested an identity not currently subscribed |
TOO_MANY_SUBSCRIPTIONS | The relevant account or strategy limit was reached. Unsubscribe unused identities first |
SERVICE_UNAVAILABLE | The initial account snapshot or server connection capacity is unavailable. Retry the subscription with backoff |
TOO_MANY_REQUESTS | Request rate exceeded. After upgrade, delay and retry the request while keeping the healthy connection |
FRAGMENT | Unsupported WebSocket fragmentation or invalid JSON |
UNKNOWN | Unexpected server error. Retain diagnostic IDs and contact API support |
An unsubscribe acknowledgement follows a successful explicit unsubscribe. A pending account subscription can fail before its acknowledgement if the initial snapshot is unavailable. A missing update does not clear existing orders or positions.
Changes to API-key or account access can close the connection. If an active account subscription is no longer authorized, the server removes it and sends an unsolicited subscription.ack with action: "unsubscribe", its channel, account, broker ID and person ID. It has no request_id. Stop using that channel's cached state; do not automatically resubscribe in a tight loop. A denial before activation returns a correlated FORBIDDEN error instead.
Other subscriptions can remain active when one channel is removed. Correlate requested acknowledgements by request_id and handle unsolicited ones separately.
A missed application heartbeat can close with NormalClosure and reason Ping timeout. Slow consumption can produce that same reason, so it does not uniquely identify the cause. Do not infer an exact close deadline from the close code or reason.
The server can close a slow connection with reason Outbound queue full. Reconnect and resubscribe. Transport failures or server shutdown can end a connection without an application error. A normal close code can still require recovery.
Process incoming messages promptly, acknowledge JSON heartbeats, and move blocking REST, storage or computation work outside the receive loop. Protocol Ping/Pong does not replace heartbeat.ack.
| Situation | Action |
|---|---|
Invalid fields or FORBIDDEN | Correct the cause; keep other healthy subscriptions running |
| Duplicate subscription | Use the existing subscription or unsubscribe it before replacing it |
Snapshot SERVICE_UNAVAILABLE | Retry that subscription with backoff; connection may remain usable |
| Rate limit after upgrade | Delay the request. Reconnecting is unnecessary |
| Transport close or eviction | Reconnect with exponential backoff and jitter, then use the channel-specific rule below |
| Authority revoked | Mark affected state unavailable and obtain corrected authority before resubscribing |
For strategy.signal and strategy.live_fills, retain separate successfully processed cursors and request bounded replay. For strategy.positions, resubscribe and replace the full collection. For every account.* channel, resubscribe without resume_from and replace state from the new initial snapshot. Clear stale account state rather than merging the old socket's baseline. See Recovery and Gap Fill.