WebSocket API
The Atlas WebSocket endpoint mirrors the host used for HTTPS. Production URL:
wss://atlas.mavr.finance/ws?token=<access_token>Pass the same short-lived JWT access token used for REST (Authentication) as the token query parameter. The server validates it during the HTTP upgrade; invalid or expired tokens typically yield an abnormal close (for example codes such as 1006 / TLS or proxy rejection — reference clients also treat 1000 normal and 1005 no-status as non-abnormal).
Clients send no application frames; all payloads are JSON messages from server to client.
Message envelope
Section titled “Message envelope”Every broadcast matches the BroadcastMessage shape used in atlas-web (frontends/atlas-web/src/types/ws.ts):
| Field | Type | Meaning |
|---|---|---|
kind | string | Logical channel / topic (see table below). |
message_type | string (optional) | "snapshot" — replace local collection for that kind; "delta" — upsert rows and apply removed keys. Defaults to snapshot when omitted (message_type ?? "snapshot" in the reference client). |
seq | number (optional) | Monotonic sequence per connection / broadcast stream. Use for gap detection (see Sequence numbers). |
ts | string or omitted/null | Server timestamp (RFC 3339 when present). May be missing on malformed payloads. |
data | object | Kind-specific payload; may be {}, string-encoded JSON, or null depending on kind. |
Example skeleton:
{ "kind": "positions", "message_type": "delta", "seq": 1234, "ts": "2026-05-20T10:00:00.123456Z", "data": { }}Operational note: heartbeat
Section titled “Operational note: heartbeat”The server emits periodic heartbeat messages so idle connections stay warm and clients can refresh “last message” timers. Heartbeats carry kind: "heartbeat" and no meaningful data. They are not listed in the TypeScript WsKind union but are part of the live protocol.
Payload shapes (merge-oriented kinds)
Section titled “Payload shapes (merge-oriented kinds)”Several kinds use the same pattern:
message_type: "snapshot"— replace the entire local cache for that domain with the rows indata(after parsing).message_type: "delta"— upsert rows keyed by the domain’s natural id and delete ids listed inremoved.
For positions, the reference parser accepts data.positions, data.rows, data.items, nested envelopes, or a bare JSON array / double-encoded string (parsePositionsWsData in frontends/atlas-web/src/lib/positionSnapshotEnvelope.ts). Removed keys are string ids (e.g. position_line_key).
For cash_balance, ocp, and payment_order, the broadcaster prefers explicit arrays (cash_balances, ocp_positions, payment_orders) but still accepts legacy upsert for compatibility.
Kind reference
Section titled “Kind reference”The application kinds defined as WsKind in frontends/atlas-web/src/types/ws.ts behave as follows (plus heartbeat above). “Reference client” denotes frontends/atlas-web/src/api/ws.ts.
kind | Snapshot vs delta | Suggested client action |
|---|---|---|
positions | Snapshot replaces full position map; delta upserts rows and deletes removed keys. | Merge into keyed map. Reference client skips an empty snapshot if the store already has rows from REST /positions/snapshot (avoids clobbering enriched rows when the broadcaster returns [] on failure). |
trades | Same pattern: data.trades + data.removed (trade ids). | Merge / remove by trade_id. |
blotter | Same pattern: data.entries + data.removed. | Merge blotter rows; remove by id list. |
orders | Signal-only in reference client (parses then discards row arrays). | Invalidate / refetch orders from REST; atlas-web calls invalidateWsQueries(["orders"]). |
curves | No structured merge in reference client. | Invalidate / refetch curves REST queries. |
dividends | — | Invalidate / refetch dividends REST queries. |
coupons | — | Invalidate / refetch coupons REST queries. |
report_generated | Event payload (not snapshot/delta). Fields include report_id, run_id, entity_id, optional desk_id, business_date, version, optional seal_hash_sha256. | Update local report/catalogue state if modeled; invalidate reports, v2, catalogue queries. |
report_edit | Event payload: run_id, optional report_id, optional desk_id, user_id, section_code, optional edited_at. | Patch edit metadata; invalidate section + catalogue (+ report id when present). |
report_locked | Event payload: desk_id, business_date, optional locked_at. | Patch lock state for desk/date. |
cash_balance | Snapshot replaces balances; delta merges cash_balances (or upsert) and removes composite keys in removed. | Merge keyed cash rows (reference: Zustand setSnapshot / applyDelta). |
ocp | Same for open-currency positions: ocp_positions / upsert, removed. | Merge keyed OCP rows. |
payment_order | Same for payment orders: payment_orders / upsert, removed (ids). | Merge + invalidate payment-orders REST queries. |
Row-level schemas for positions, trades, and blotter align with the corresponding REST snapshots where applicable.
Reference client: reconnection and watchdog
Section titled “Reference client: reconnection and watchdog”The atlas-web client (AtlasWebSocketClient in frontends/atlas-web/src/api/ws.ts) implements:
Exponential backoff
Section titled “Exponential backoff”After a non-clean disconnect (and after ctor failures), it schedules reconnect with delay reconnect, starting at 1000 ms, doubling each attempt (×2), capped at 30_000 ms. Backoff resets to 1000 ms on successful onopen. Tab visibility (visibilitychange → visible) and browser online trigger an immediate reconnect attempt when status is disconnected or error (resetting backoff).
45-second watchdog
Section titled “45-second watchdog”If no message (including heartbeats) arrives for 45 seconds (DEAD_CONNECTION_MS), the client treats the socket as dead, marks status disconnected, and calls connect() again. The check runs on a 10-second interval timer while connected.
Sequence numbers
Section titled “Sequence numbers”When seq is present, the reference client stores lastSeq for diagnostics only; it does not automatically recover from gaps.
Recommended integration behavior: if seq is strictly increasing and you observe seq > expected + 1, assume missed messages: refetch authoritative snapshots over REST (or reconnect and wait for server snapshots) for affected domains rather than continuing from a partially stale cache.