Skip to content

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/trade

Request

Request Format

{
  "id": "subaccount-1",
  "method": "post",
  "params": {
    "action": "getSubAccount",
    "subAccountId": "1867542890123456789",
    "expiresAfter": 1704067500,
    "signature": {
      "v": 28,
      "r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
      "s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
    }
  }
}

Parameters

Request Parameters

ParameterTypeRequiredDescription
idstringYesClient-generated unique request identifier
methodstringYesMust be "post"
paramsobjectYesContains all parameters for the request

Params Object

ParameterTypeRequiredDescription
actionstringYesMust be "getSubAccount"
subAccountIdstringYesSubaccount identifier
expiresAfterintegerNoOptional expiration timestamp in seconds
signatureobjectYesEIP-712 signature using SubAccountAction type
Important Notes:
  • This endpoint uses SubAccountAction EIP-712 type (no nonce required, only expiresAfter is 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

FieldTypeDescription
subAccountIdstringUnique subaccount identifier
masterAccountIdstring | nullParent account ID if this is a delegated subaccount, null otherwise
subAccountNamestringHuman-readable subaccount name
collateralsarrayArray of collateral balances held in this subaccount
crossMarginSummaryobjectComprehensive margin and balance information
positionsarrayArray of open positions for this subaccount
marketPreferencesobjectMarket-specific settings (leverage per market)
feeRatesobjectFee rates applicable to this subaccount
accountLimitsobjectAccount limits for this subaccount

Collateral Object

FieldTypeDescription
symbolstringCollateral token symbol (e.g., "USDT")
quantitystringAmount of collateral held
withdrawablestringAmount available for withdrawal
pendingWithdrawstringAmount pending withdrawal
adjustedCollateralValuestringCollateral value after applying haircut discount (USD equivalent)
collateralValuestringFull collateral value before haircut (USD equivalent)

Cross Margin Summary Object

FieldTypeDescription
accountValuestringTotal account value including PnL
availableMarginstringUSDT amount available for new positions
totalUnrealizedPnlstringSum of all unrealized PnL
maintenanceMarginstringMinimum margin required for all positions
initialMarginstringInitial margin required for all positions
withdrawablestringUSDT amount available for withdrawal
adjustedAccountValuestringAdjusted account value for margin calculations

Position Fields

FieldTypeDescription
symbolstringMarket symbol
sidestringPosition side: "long" or "short"
entryPricestringVolume-weighted average entry price
quantitystringPosition size (always positive)
pnlstringRealized profit/loss
upnlstringUnrealized profit/loss
usedMarginstringMargin allocated to this position
maintenanceMarginstringMinimum margin required to maintain position
liquidationPricestringPrice at which position will be liquidated

Market Preferences

FieldTypeDescription
leveragesobjectMap of market symbols to leverage values (e.g., {"BTC-USDT": 20})

Fee Rates

FieldTypeDescription
makerFeeRatestringMaker fee rate (e.g., "0.0002" = 0.02%)
takerFeeRatestringTaker fee rate (e.g., "0.0005" = 0.05%)
tierNamestringFee tier name (e.g., "VIP 0", "VIP 1")

Account Limits

FieldTypeDescription
maxSubAccountsintegerMaximum 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 SubAccountAction EIP-712 type (no nonce required)
  • Returns data for the specified subaccount
Error CodeDescriptionRetryable
UNAUTHORIZEDEIP-712 signature validation failedNo
VALIDATION_ERRORRequest validation failedNo
MISSING_REQUIRED_FIELDRequired field is missingNo
INVALID_FORMATField format is invalidNo
INVALID_VALUEInvalid parameter valueNo
RATE_LIMIT_EXCEEDEDToo many requests in time windowYes
INSUFFICIENT_MARGINNot enough margin for tradeNo
ORDER_NOT_FOUNDOrder does not existNo
OPERATION_TIMEOUTOperation timed outYes

Next Steps