Get Subaccounts (WebSocket)
Retrieve all subaccounts for the authenticated wallet through the WebSocket connection, including comprehensive details for each subaccount such as collateral balances, cross margin summary, positions, market preferences, fee rates, and delegated signers. This is a more comprehensive alternative to getSubAccount that returns multiple subaccounts with delegation information included.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "subaccounts-1",
"method": "post",
"params": {
"action": "getSubAccounts",
"subAccountId": "1867542890123456789",
"expiresAfter": 1704067500000,
"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 "getSubAccounts" |
subAccountId | string | Yes | The ID of a subaccount owned by the authenticated wallet |
expiresAfter | integer | No | Optional expiration timestamp (milliseconds) |
signature | object | Yes | EIP-712 signature using SubAccountAction type |
- This endpoint uses
SubAccountActionEIP-712 type (no nonce required, onlyexpiresAfteris optional) - Returns all subaccounts associated with the authenticated wallet
Response Format
Success Response
{
"id": "subaccounts-1",
"status": 200,
"result": {
"subAccounts": [
{
"subAccountId": "1867542890123456789",
"masterAccountId": "1867542890123456788",
"subAccountName": "Trading Account 1",
"collaterals": [
{
"symbol": "USDC",
"quantity": "1000.00000000",
"withdrawable": "1000.00000000",
"pendingWithdraw": "0.00000000"
},
{
"symbol": "ETH",
"quantity": "0.5000",
"withdrawable": "0.5000",
"pendingWithdraw": "0.0000"
}
],
"crossMarginSummary": {
"accountValue": "6750.50",
"availableMargin": "2415.00",
"totalUnrealizedPnl": "75.00",
"maintenanceMargin": "1207.50",
"initialMargin": "2415.00",
"withdrawable": "4335.50"
"adjustedAccountValue": "6750.50"
},
"positions": [],
"marketPreferences": {
"leverages": {
"BTC-USDT": 20,
"ETH-USDT": 10
}
},
"feeRates": {
"makerFeeRate": "0.0002",
"takerFeeRate": "0.0005",
"tierName": "Regular User"
},
"delegatedSigners": [
{
"subAccountId": "1867542890123456789",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"permissions": ["trading"],
"expiresAt": null
}
]
},
{
"subAccountId": "1867542890123456790",
"masterAccountId": "1867542890123456788",
"subAccountName": "Trading Account 2",
"collaterals": [
{
"symbol": "USDC",
"quantity": "5000.00000000",
"withdrawable": "5000.00000000",
"pendingWithdraw": "0.00000000"
}
],
"crossMarginSummary": {
"accountValue": "5000.00",
"availableMargin": "5000.00",
"totalUnrealizedPnl": "0.00",
"maintenanceMargin": "0.00",
"initialMargin": "0.00",
"withdrawable": "5000.00"
"adjustedAccountValue": "5000.00"
},
"positions": [],
"marketPreferences": {
"leverages": {}
},
"feeRates": {
"makerFeeRate": "0.0002",
"takerFeeRate": "0.0005",
"tierName": "Regular User"
},
"delegatedSigners": []
}
]
}
}Response Fields
| Field | Type | Description |
|---|---|---|
subAccounts | array | Array of subaccount objects |
Each subaccount in the subAccounts array includes:
| Field | Type | Description |
|---|---|---|
subAccountId | string | Unique subaccount identifier |
masterAccountId | string | null | Parent account ID if this is a 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 |
delegatedSigners | array | Array of delegated signer objects 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 |
Delegate Object
Delegate Object
The delegate object represents a delegated signer in API responses. Note that the response uses walletAddress while EIP-712 signing uses delegateAddress.
| Field | Type | Description |
|---|---|---|
subAccountId | string | Subaccount ID this delegation applies to |
walletAddress | string | Ethereum wallet address of the delegated signer (42-character hex format) |
permissions | string[] | Array of permission levels granted. Currently supports: ["trading"] |
expiresAt | integer | null | Unix timestamp (milliseconds) when the delegation expires. null indicates no expiration |
addedBy | string | omitted | Wallet address that created this delegation. Omitted for pre-migration records where the creator was not recorded |
Example Delegate Object
{
"subAccountId": "1867542890123456789",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"permissions": ["trading"],
"expiresAt": null,
"addedBy": "0x1111111111111111111111111111111111111111"
}Example with Expiration
{
"subAccountId": "1867542890123456789",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"permissions": ["trading"],
"expiresAt": 1767225600000
}Error Response
{
"id": "subaccounts-1",
"status": 400,
"result": null,
"error": {
"code": 400,
"message": "subaccountId is required"
}
}Implementation Example
class SubaccountsQuery {
constructor(ws, signer) {
this.ws = ws;
this.signer = signer;
this.pendingRequests = new Map();
}
async getSubAccounts(subAccountId) {
const expiresAfter = Date.now() + 300000; // 5 minutes in milliseconds
// Sign using SubAccountAction type (no nonce required)
const signature = await this.signSubAccountAction(subAccountId, "getSubAccounts", expiresAfter);
const request = {
id: `subaccounts-${Date.now()}`,
method: "post",
params: {
action: "getSubAccounts",
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 sig = await this.signer.signTypedData(domain, types, message);
const { v, r, s } = ethers.Signature.from(sig);
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 SubaccountsQuery(ws, signer);
const subaccounts = await query.getSubAccounts("1867542890123456789");
subaccounts.subAccounts.forEach(account => {
console.log(`Account: ${account.subAccountName}`);
console.log(`Value: ${account.crossMarginSummary.accountValue}`);
console.log(`Delegates: ${account.delegatedSigners.length}`);
});Code Examples
Get All Subaccounts
{
"id": "get-subaccounts",
"method": "post",
"params": {
"action": "getSubAccounts",
"subAccountId": "1867542890123456789",
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Implementation Notes
- This endpoint uses
SubAccountActionEIP-712 type (no nonce required) - Returns all subaccounts associated with the authenticated wallet
- Includes delegated signers for each subaccount, unlike
getSubAccount
| 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 Subaccount - Get a single subaccount
- Get Delegated Signers - Get delegated signers for a single subaccount
- Get Positions - Detailed position information
- SubAccount Updates - Real-time account updates
- REST Alternative - REST API comparison