Private Streams
Real-time streams of your own orders and fills. Two subjects:
| Subject | Purpose |
|---|---|
v1.f.ex1.private.subAccountId.<id>.order | Order state changes — New, PartiallyFilled, Filled, Cancelled. |
v1.f.ex1.private.subAccountId.<id>.trade | Execution (fill) events — one per match. |
<id> is your sub-account ID. You'll receive it as sub_account_id on every payload, and it's also visible in the response of Place Order (via the order context).
Authentication
Private subjects can only be subscribed to with a valid signature. The flow:
- Call
GET /dma/api/v1/socket/signatureas a normal authenticated HFT request. - The response contains
{api_key, expires, signature}— these are credentials specifically for the HFT WebSocket auth message, separate from your CoinSwitch REST API key. - Use those three values to authenticate the NATS WebSocket connection.
Get a signature
| Method | GET |
| Path | /dma/api/v1/socket/signature |
Query parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
expires_in_seconds | integer | No | Lifetime of the returned signature, in seconds. Default 300. The returned expires field is now + expires_in_seconds, expressed as a Unix-ms timestamp. |
Request
- Python
- Java
- Go
- Node.js
from reference_client import sign_request, BASE_URL
import requests
headers, path = sign_request("GET", "/dma/api/v1/socket/signature")
r = requests.get(BASE_URL + path, headers=headers)
creds = r.json()
# {"api_key": "...", "expires": 1756461000000, "signature": "..."}
HttpResponse<String> resp = client.send(
"GET", "/dma/api/v1/socket/signature", null, null);
System.out.println(resp.body());
headers, p, err := SignRequest("GET", "/dma/api/v1/socket/signature", nil)
if err != nil { panic(err) }
req, _ := http.NewRequest("GET", BaseURL+p, nil)
for k, v := range headers { req.Header.Set(k, v) }
resp, err := http.DefaultClient.Do(req)
if err != nil { panic(err) }
defer resp.Body.Close()
out, _ := io.ReadAll(resp.Body)
fmt.Println(string(out))
const {signRequest, BASE_URL} = require('./reference-client');
const {headers, path} = signRequest('GET', '/dma/api/v1/socket/signature');
const r = await fetch(BASE_URL + path, {
method: 'GET',
headers,
});
console.log(await r.json());
Response
{
"api_key": "<api key for the websocket auth message>",
"expires": 1756461000000,
"signature": "<signature hex>"
}
| Field | Type | Description |
|---|---|---|
api_key | string | The API key to use on the WebSocket auth payload. |
expires | integer | Expiry timestamp (Unix ms). After this, the signature is rejected. |
signature | string | The signature to use on the WebSocket auth payload. Computed on our side; you don't compute this yourself — just pass it through. |
Don't compute this signature client-side. Always call /dma/api/v1/socket/signature to obtain it.
Authenticate the WebSocket
Once connected to the NATS WebSocket, send the auth message below before subscribing to any private subject:
{
"op": "auth",
"args": ["<api_key>", <expires>, "<signature>"]
}
Use the values from the /dma/api/v1/socket/signature response. Subscribe to your private subjects only after the auth message is acknowledged.
If expires is in the past (or close to it), the auth is rejected — request a fresh signature with a longer expires_in_seconds if needed.
Order Updates
Subject: v1.f.ex1.private.subAccountId.<id>.order
{
"t": 1756478182146,
"e": "COINSWITCHX",
"event_type": "order.linear",
"E": 1756478182146,
"T": 0,
"user_id": "491363048",
"sub_account_id": "491363048",
"o": {
"category": "linear",
"symbol": "SOLUSDT",
"orderId": "68a4579e-c396-4427-b055-7a8bcafbd48d",
"orderLinkId": "7b708608-7e1d-456b-aa78-43a9892c2fda",
"side": "Buy",
"positionIdx": 0,
"orderStatus": "Filled",
"cancelType": "UNKNOWN",
"rejectReason": "EC_NoError",
"timeInForce": "IOC",
"price": "220.25",
"qty": "0.2",
"avgPrice": "209.76",
"leavesQty": "0",
"leavesValue": "0",
"cumExecQty": "0.2",
"cumExecValue": "41.952",
"cumExecFee": "0.0146832",
"orderType": "Market",
"lastPriceOnCreated": "209.75",
"closeOnTrigger": false,
"reduceOnly": false,
"createType": "CreateByUser",
"updatedTime": "1756478182110"
}
}
You'll receive one of these every time the order's orderStatus changes (placed → filled, cancelled, rejected, etc.). The o object mirrors the shape of result.list[] on Get Orders (Realtime).
Trade Updates
Subject: v1.f.ex1.private.subAccountId.<id>.trade
{
"t": 1756478116649,
"e": "COINSWITCHX",
"event_type": "execution.linear",
"E": 1756478116649,
"T": 1756478116611,
"user_id": "491363048",
"sub_account_id": "491363048",
"o": [
{
"category": "linear",
"symbol": "BTCUSDT",
"orderId": "316ea49e-59b3-42c5-9d71-edaf2504b0f8",
"orderLinkId": "cf8cc52d-b749-4d97-aeb9-f44c90b94092",
"side": "Sell",
"orderPrice": "107396.1",
"orderQty": "0.002",
"leavesQty": "0",
"createType": "CreateByUser",
"orderType": "Market",
"execFee": "0.07593348",
"execId": "a1076552-0c0f-5a56-a064-5a653f9172c6",
"execPrice": "108476.4",
"execQty": "0.002",
"execType": "Trade",
"execValue": "216.9528",
"execTime": "1756478116611",
"isMaker": false,
"feeRate": "0.00035",
"closedSize": "0.002",
"seq": 448368491576
}
]
}
o is an array — a single matching event can produce multiple executions (e.g. a market order eating through several resting orders). Each entry mirrors result.list[] on Execution List.
Each execution has a unique execId — use it as the primary key when you store fills locally, so retries or duplicate messages don't insert the same fill twice.