Streaming
One WebSocket, JSON-RPC 2.0, updates as they happen.
GET /v1/ws
Upgrade to a WebSocket at wss://api.orderfill.trade/v1/ws, with
Authorization: Bearer <token>. Browsers cannot set that header, so ?token= also
works; use a short-lived session token there, never an API key, because query strings
end up in logs.
The first message tells you where you stand:
{ "jsonrpc": "2.0", "method": "connection.ready",
"params": { "orgId": "…", "role": "owner", "canTrade": true, "methods": ["orders.place", "…"] } }
A bad token gets connection.rejected, then the socket closes.
Calling methods
Every method mirrors a REST call and behaves the same way.
{ "jsonrpc": "2.0", "id": 1, "method": "orders.place",
"params": { "accountId": "…", "symbol": "XAUUSD", "side": "buy", "volume": 0.1,
"idempotencyKey": "order-42" } }
| Method | REST twin |
|---|---|
accounts.list | GET /accounts |
account.summary, account.capabilities | GET …/summary, GET …/capabilities |
positions.list, orders.list, executions.list | the matching GETs |
market.quote, market.candles | GET …/quotes/:symbol, GET …/candles/:symbol |
symbols.list, symbols.resolve, symbols.override | the symbol calls |
orders.place, orders.check, orders.cancel | POST …/orders, POST …/orders/check, DELETE …/orders/:ticket |
positions.modify, positions.close, positions.closeAll | PATCH/DELETE …/positions/:ticket, DELETE …/positions |
subscribe, unsubscribe | streams, below |
ping |
idempotencyKey shares its store with the REST header. If the socket drops mid-order
and you retry over HTTP with the same key, you get the first result.
Subscribing
{ "jsonrpc": "2.0", "id": 2, "method": "subscribe",
"params": { "accountId": "…", "stream": "positions" } }
| Stream | params | Items |
|---|---|---|
positions | every open position, on each change | |
orders | every working order, on each change | |
executions | new fills | |
account | balance, equity and margin | |
ticks | symbol (required), intervalMs | quotes for that symbol |
{ "jsonrpc": "2.0", "id": 3, "method": "subscribe",
"params": { "accountId": "…", "stream": "ticks", "params": { "symbol": "XAUUSD" } } }
Updates arrive as notifications:
{ "jsonrpc": "2.0", "method": "stream.data",
"params": { "subscription": "…", "stream": "positions", "items": [ "…" ] } }
Streams push on change, so silence means nothing changed. Subscribing twice is harmless, and closing the socket ends every subscription it held.
Prefer streams to polling. Placing an order is as fast as your broker whatever else is happening. Reads are not: a tight polling loop slows down as the host gets busy and spends your rate limit on answers that have not changed.
Errors
{ "jsonrpc": "2.0", "id": 1,
"error": { "code": -32602, "message": "NZDCAD is not available on this account",
"data": { "error": "bad_request", "status": 400, "details": { "hint": "…" } } } }
data.error is the same code the REST API uses. A bad frame does not close the
connection.