Broker WebSocket
The same realtime channel the Trader WebSocket uses, but from the back-office side. With an admin or manager (dealer) session you connect once and stream live account events for the clients in your book — balances, margin, money movements, status changes, and session activity — so your CRM or risk desk stays in sync without polling.
What you get
- Live account summaries (balance / equity / margin) for your clients.
- account_update when an account's fields change (leverage, status, prop/config you pushed).
- money_change on every deposit / withdrawal / adjustment / credit.
- liquidation events when a client hits a margin call or stop-out.
- session events (a client logged in / was disconnected).
Your reach mirrors your REST scope: an admin sees every account; a manager sees only the accounts inside the group(s) they manage.
Endpoint
wss://api.onlytradeplatform.com/ws/v1/?session_id=<session_id>
Authorization: Bearer <access_token>
The handshake needs both the session_id (query parameter) and the access
token — as an Authorization: Bearer header, or as an access_token query
parameter if your WebSocket client can't set headers.
Connect & authenticate
- Log in over REST with your admin / manager credentials (see
Broker → Authentication) and keep the
access_tokenandsession_idfrom the response. - Open the socket with the bearer token and the
session_idquery parameter. A missing or expired token fails the upgrade with HTTP401; an invalid session gets anunauthorizedframe and the socket closes. - Send subscribe frames to start receiving events.
Frame format
Every frame, both directions, is a JSON object with a type and a payload:
{ "type": "account_subscribe", "payload": { "account_id": 26100003 } }
- You send actions (subscribe to an account).
- You receive events (a balance changed, a client hit a margin call).
What you send
Subscribe per client account you want to watch (call it for each account in your book, e.g. as your CRM loads them):
{ "type": "account_subscribe", "payload": { "account_id": 26100003 } }
What you receive
| Event | When |
|---|---|
account_Summary | Balance / equity / margin / margin-level tick (note the capital S; at most one every 200 ms per account). |
account_update | Account fields changed — leverage, status, or a prop/config update you pushed. |
money_change | Deposit / withdrawal / adjustment / credit. |
balance_correction | A balance correction was applied. |
event_liqudation_status | The client reached a margin call / stop-out. |
session_client_logout | A client session was killed (login-limit, admin disconnect, or trial expiry). |
{ "type": "account_Summary", "session_id": "f6a1c2d3-…", "payload": { "ts": 1781251200000, "account_id": 26100003, "balance": 1000547.09, "credit": 0, "equity": 1010647.99, "used_margin": 9.0, "free_margin": 1010638.99, "margin_level": 11229422.11, "floating_profit": 0.90, "positions": [{ "id": 260610016, "profit": 0.90 }] } }
{ "type": "money_change", "session_id": "f6a1c2d3-…", "payload": { "account_id": 26100003, "amount": 5000.00, "balance": 1005547.09, "credit": 0, "desc": "Deposit", "origin": 0, "type": 0 } }
Error frames arrive as events too — branch on type: bad_request,
internal_server_error, not_found, forbidden, unauthorized. The
payload.message carries the reason.
Watching the whole book (self-hosters)
Internally the server fans events out over NATS. A back-office consumer can read every account's stream from one subject instead of subscribing per account:
websocket.accounts.* all accounts (admin)
websocket.accounts.{account_id}.* all events for one account
websocket.accounts.{account_id}.summary account summary ticks only
websocket.accounts.{account_id}.deals deals only
You don't need NATS when using the WebSocket directly — it's documented for broker operators running their own bus.