Get Subaccount (WebSocket)
Retrieve complete account information for the authenticated subaccount through the WebSocket connection, including collateral balances, open positions, margin summary, market preferences, and fee rate information.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "subaccount-1",
"method": "post",
"params": {
"action": "getSubAccount",
"subAccountId": "1867542890123456789",
"expiresAfter": 1704067500,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}
}Parameters
Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
id | string | Yes | Client-generated unique request identifier |
method | string | Yes | Must be "post" |
params | object | Yes | Contains all parameters for the request |
Params Object
| Parameter | Type | Required | Description |
|---|---|---|---|
action | string | Yes | Must be "getSubAccount" |
subAccountId | string | Yes | Subaccount identifier |
expiresAfter | integer | No | Optional expiration timestamp in seconds |
signature | object | Yes | EIP-712 signature using SubAccountAction type |
- This endpoint uses
SubAccountActionEIP-712 type (no nonce required, onlyexpiresAfteris optional) - Returns data for the specified subaccount
Response Format
Success Response
{
"id": "subaccount-1",
"status": 200,
"result": {
"subAccountId": "1867542890123456789",
"masterAccountId": null,
"subAccountName": "Trading Account 1",
"collaterals": [
{
"symbol": "USDT",
"quantity": "10000.00000000",
"withdrawable": "5000.00000000",
"pendingWithdraw": "0.00000000",
"adjustedCollateralValue": "10000.00000000",
"collateralValue": "10000.00000000"
},
{
"symbol": "ETH",
"quantity": "2.50000000",
"withdrawable": "1.00000000",
"pendingWithdraw": "0.00000000",
"adjustedCollateralValue": "4375.00000000",
"collateralValue": "5000.00000000"
}
],
"crossMarginSummary": {
"accountValue": "15750.50",
"availableMargin": "8250.00",
"totalUnrealizedPnl": "125.50",
"maintenanceMargin": "3150.25",
"initialMargin": "6300.50",
"withdrawable": "9450.00",
"adjustedAccountValue": "15750.50"
},
"positions": [
{
"symbol": "BTC-USDT",
"side": "long",
"entryPrice": "43500.00",
"quantity": "0.25",
"pnl": "50.00",
"upnl": "125.50",
"usedMargin": "2175.00",
"maintenanceMargin": "1087.50",
"liquidationPrice": "41000.00"
}
],
"marketPreferences": {
"leverages": {
"BTC-USDT": 20,
"ETH-USDT": 10
}
},
"feeRates": {
"makerFeeRate": "0.0002",
"takerFeeRate": "0.0005",
"tierName": "VIP 0"
},
"accountLimits": {
"maxSubAccounts": 10
}
}
}Response Fields
| Field | Type | Description |
|---|---|---|
subAccountId | string | Unique subaccount identifier |
masterAccountId | string | null | Parent account ID if this is a delegated subaccount, null otherwise |
subAccountName | string | Human-readable subaccount name |
collaterals | array | Array of collateral balances held in this subaccount |
crossMarginSummary | object | Comprehensive margin and balance information |
positions | array | Array of open positions for this subaccount |
marketPreferences | object | Market-specific settings (leverage per market) |
feeRates | object | Fee rates applicable to this subaccount |
accountLimits | object | Account limits for this subaccount |
Collateral Object
| Field | Type | Description |
|---|---|---|
symbol | string | Collateral token symbol (e.g., "USDT") |
quantity | string | Amount of collateral held |
withdrawable | string | Amount available for withdrawal |
pendingWithdraw | string | Amount pending withdrawal |
adjustedCollateralValue | string | Collateral value after applying haircut discount (USD equivalent) |
collateralValue | string | Full collateral value before haircut (USD equivalent) |
Cross Margin Summary Object
| Field | Type | Description |
|---|---|---|
accountValue | string | Total account value including PnL |
availableMargin | string | USDT amount available for new positions |
totalUnrealizedPnl | string | Sum of all unrealized PnL |
maintenanceMargin | string | Minimum margin required for all positions |
initialMargin | string | Initial margin required for all positions |
withdrawable | string | USDT amount available for withdrawal |
adjustedAccountValue | string | Adjusted account value for margin calculations |
Position Fields
| Field | Type | Description |
|---|---|---|
symbol | string | Market symbol |
side | string | Position side: "long" or "short" |
entryPrice | string | Volume-weighted average entry price |
quantity | string | Position size (always positive) |
pnl | string | Realized profit/loss |
upnl | string | Unrealized profit/loss |
usedMargin | string | Margin allocated to this position |
maintenanceMargin | string | Minimum margin required to maintain position |
liquidationPrice | string | Price at which position will be liquidated |
Market Preferences
| Field | Type | Description |
|---|---|---|
leverages | object | Map of market symbols to leverage values (e.g., {"BTC-USDT": 20}) |
Fee Rates
| Field | Type | Description |
|---|---|---|
makerFeeRate | string | Maker fee rate (e.g., "0.0002" = 0.02%) |
takerFeeRate | string | Taker fee rate (e.g., "0.0005" = 0.05%) |
tierName | string | Fee tier name (e.g., "VIP 0", "VIP 1") |
Account Limits
| Field | Type | Description |
|---|---|---|
maxSubAccounts | integer | Maximum number of subaccounts allowed for the master account |
Error Response
{
"id": "subaccount-1",
"status": 400,
"result": null,
"error": {
"code": 400,
"message": "subaccountId is required"
}
}Implementation Example
class SubaccountQuery {
constructor(ws, signer) {
this.ws = ws;
this.signer = signer;
this.pendingRequests = new Map();
}
async getSubAccount(subAccountId, expiresAfter = 0) {
// Sign using SubAccountAction type (no nonce required)
const signature = await this.signSubAccountAction(subAccountId, "getSubAccount", expiresAfter);
const request = {
id: `subaccount-${Date.now()}`,
method: "post",
params: {
action: "getSubAccount",
subAccountId,
expiresAfter,
signature
}
};
return this.sendRequest(request);
}
async signSubAccountAction(subAccountId, action, expiresAfter = 0) {
const domain = {
name: "Synthetix",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000"
};
const types = {
SubAccountAction: [
{ name: "subAccountId", type: "uint256" },
{ name: "action", type: "string" },
{ name: "expiresAfter", type: "uint256" }
]
};
const message = {
subAccountId: BigInt(subAccountId),
action,
expiresAfter: BigInt(expiresAfter)
};
const signature = await this.signer._signTypedData(domain, types, message);
const { v, r, s } = ethers.utils.splitSignature(signature);
return { v, r, s };
}
sendRequest(request) {
return new Promise((resolve, reject) => {
this.pendingRequests.set(request.id, { resolve, reject });
this.ws.send(JSON.stringify(request));
setTimeout(() => {
if (this.pendingRequests.has(request.id)) {
this.pendingRequests.delete(request.id);
reject(new Error('Request timeout'));
}
}, 10000);
});
}
handleResponse(response) {
const pending = this.pendingRequests.get(response.id);
if (pending) {
this.pendingRequests.delete(response.id);
if (response.error) {
pending.reject(new Error(response.error.message));
} else {
pending.resolve(response.result);
}
}
}
}
// Usage
const query = new SubaccountQuery(ws, signer);
const subaccount = await query.getSubAccount("1867542890123456789");
console.log('Account Value:', subaccount.crossMarginSummary.accountValue);
console.log('Positions:', subaccount.positions.length);Implementation Notes
- This endpoint uses
SubAccountActionEIP-712 type (no nonce required) - Returns data for the specified subaccount
| Error Code | Description | Retryable |
|---|---|---|
UNAUTHORIZED | EIP-712 signature validation failed | No |
VALIDATION_ERROR | Request validation failed | No |
MISSING_REQUIRED_FIELD | Required field is missing | No |
INVALID_FORMAT | Field format is invalid | No |
INVALID_VALUE | Invalid parameter value | No |
RATE_LIMIT_EXCEEDED | Too many requests in time window | Yes |
INSUFFICIENT_MARGIN | Not enough margin for trade | No |
ORDER_NOT_FOUND | Order does not exist | No |
OPERATION_TIMEOUT | Operation timed out | Yes |
Next Steps
- Get Positions - Detailed position information
- Get Order History - Order history and status
- SubAccount Updates - Real-time account updates
- Get Subaccount IDs - List all subaccount IDs for a wallet