Get Subaccounts
Retrieve all subaccounts under the same master account as the requested subAccountId, plus any subaccounts owned by other wallets that have granted account-level delegation to the caller's wallet. Callable by account owners, subaccount-level delegated signers, and account-level managers authorized for the requested subaccount. Each subaccount includes collateral balances, cross margin summary, positions, market preferences, fee rates, and delegated signers. See Smart Contract Accounts (Safe) for the Gnosis Safe owner + manager workflow.
Endpoint
POST https://papi.synthetix.io/v1/tradeRequest
Request Format
{
"params": {
"action": "getSubAccounts",
"subAccountId": "1867542890123456789"
},
"expiresAfter": 1735689900,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}Request Parameters
| Field | Type | Required | Description |
|---|---|---|---|
params | object | Yes | Request parameters wrapper |
params.action | string | Yes | Must be "getSubAccounts" |
params.subAccountId | string | Yes | A subaccount the caller can authenticate for (owner, subaccount delegate, or account-level manager). Any ID in the same master account group resolves to the full sibling list. Must match the subAccountId in the EIP-712 SubAccountAction signature. |
Top-level Parameters
getSubAccounts uses SubAccountAction signing. These fields sit alongside params at the top level of the request body:
| Parameter | Type | Required | Description |
|---|---|---|---|
signature | object | Yes | EIP-712 signature object (v, r, s) |
expiresAfter | uint64 | No | Unix timestamp in seconds (same unit as EIP-712 expiresAfter). Use 0 for no expiration. |
nonce is not used on this endpoint.
Optional request header X-Request-ID: when provided, the response echoes it as both requestId and request_id. When omitted, those fields are not included in the response body.
Response
Success Response
The example below includes requestId / request_id because the client sent X-Request-ID.
{
"status": "ok",
"response": {
"subAccounts": [
{
"subAccountId": "1867542890123456789",
"masterAccountId": "1867542890123456788",
"subAccountName": "Trading Account 1",
"collaterals": [
{
"symbol": "USDC",
"quantity": "1000.00000000",
"withdrawable": "1000.00000000",
"pendingWithdraw": "0.00000000",
"adjustedCollateralValue": "1000.00",
"collateralValue": "1000.00",
"haircutRate": "0",
"haircutAdjustment": "0.00",
"price": "1.0000",
"calculatedAt": 0
}
],
"crossMarginSummary": {
"accountValue": "6750.50",
"availableMargin": "2415.00",
"totalUnrealizedPnl": "75.00",
"maintenanceMargin": "1207.50",
"initialMargin": "2415.00",
"withdrawable": "4335.50",
"adjustedAccountValue": "6750.50",
"debt": "0.00"
},
"positions": [],
"marketPreferences": {
"leverages": {
"BTC-USDT": 20
}
},
"feeRates": {
"makerFeeRate": "0.0002",
"takerFeeRate": "0.0005",
"tierName": "Regular User"
},
"accountLimits": {
"maxBorrowCapacity": "10000.00",
"maxOrdersPerMarket": 10,
"maxSubAccounts": 10,
"maxTotalOrders": 100
},
"delegatedSigners": [
{
"subAccountId": "1867542890123456789",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"permissions": ["session"],
"expiresAt": null
}
]
}
],
"managedAccounts": {
"0xABcDeF1234567890AbCdEf1234567890AbCdEf12": [
{
"subAccountId": "1867542890123456800",
"masterAccountId": "1867542890123456799",
"subAccountName": "Managed Trading Account",
"collaterals": [],
"crossMarginSummary": {
"accountValue": "2500.00",
"availableMargin": "2500.00",
"totalUnrealizedPnl": "0.00",
"maintenanceMargin": "0.00",
"initialMargin": "0.00",
"withdrawable": "2500.00",
"adjustedAccountValue": "2500.00",
"debt": "0.00"
},
"positions": [],
"marketPreferences": { "leverages": {} },
"feeRates": {
"makerFeeRate": "0.0002",
"takerFeeRate": "0.0005",
"tierName": "Regular User"
},
"accountLimits": {
"maxBorrowCapacity": "10000.00",
"maxOrdersPerMarket": 10,
"maxSubAccounts": 10,
"maxTotalOrders": 100
},
"delegatedSigners": []
}
]
}
},
"requestId": "5ccf215d37e3ae6d",
"request_id": "5ccf215d37e3ae6d",
"timestamp": 1735689900000
}Response Fields
| Field | Type | Description |
|---|---|---|
status | string | "ok" on success |
response | object | Wrapper containing subAccounts and managedAccounts |
response.subAccounts | SubAccountWithDelegates[] | All subaccounts under the same master account as params.subAccountId (the owner's master tree, regardless of caller role) |
response.managedAccounts | Record<WalletAddress, SubAccountWithDelegates[]> | Map of owner wallet address to subaccounts the caller manages via account-level delegation. Keys are checksummed hex wallet addresses. Always present; {} when empty. See Smart Contract Accounts (Safe). |
requestId | string | Optional. Echo of the X-Request-ID request header (also emitted as legacy request_id). Omitted when the header is not sent. |
timestamp | integer | Server timestamp in milliseconds |
SubAccountWithDelegates Object
Each entry in subAccounts and in each managedAccounts value array is a SubAccountWithDelegates object. It includes all standard subaccount fields (flattened) plus a delegatedSigners array:
| Field | Type | Description |
|---|---|---|
subAccountId | string | Unique subaccount identifier |
masterAccountId | string | null | ID of the master account (null if this is a master account) |
subAccountName | string | Human-readable subaccount name |
collaterals | array | Collateral assets held in this subaccount (see Collateral Object) |
crossMarginSummary | object | Account value, margins, and P&L (see Cross Margin Summary Object) |
positions | array | Open positions for this subaccount. For field definitions when non-empty, see Get Positions. |
marketPreferences | object | Market-specific preferences |
marketPreferences.leverages | object | Per-market leverage settings (key: symbol, value: leverage multiplier) |
feeRates | object | Fee rate information for this subaccount |
feeRates.makerFeeRate | string | Maker fee rate as decimal (e.g. "0.0002") |
feeRates.takerFeeRate | string | Taker fee rate as decimal (e.g. "0.0005") |
feeRates.tierName | string | Fee tier name (e.g. "Regular User", "Top Tier") |
accountLimits | object | Account limits for this subaccount |
accountLimits.maxBorrowCapacity | string | Maximum borrow capacity in USD |
accountLimits.maxOrdersPerMarket | integer | Maximum open orders per market |
accountLimits.maxSubAccounts | integer | Maximum subaccounts allowed for the master account |
accountLimits.maxTotalOrders | integer | Maximum total open orders across all markets |
Additional Field
| Field | Type | Description |
|---|---|---|
delegatedSigners | DelegatedSigner[] | Subaccount-level delegated signers for this subaccount (see below) |
Each delegatedSigners entry includes:
| Field | Type | Description |
|---|---|---|
subAccountId | string | Subaccount ID this delegation applies to |
walletAddress | string | Delegated signer's wallet address |
permissions | string[] | Permission levels granted. Canonical values are session and delegate; legacy records may return trading (equivalent to session). |
expiresAt | integer | null | Expiration timestamp in milliseconds, or null if no expiration |
addedBy is not returned on this endpoint. For the full delegation record including addedBy, use Get Delegated Signers.
managedAccounts Map
The managedAccounts field is a JSON object (map) where:
- Keys are owner wallet addresses (
string, EIP-55 checksummed) of accounts that granted account-level delegation to the caller - Values are arrays of
SubAccountWithDelegatesobjects owned by that wallet
An empty object ({}) is returned when no managed accounts exist.
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) |
haircutRate | string | Haircut rate applied to this collateral (e.g., "0.1" = 10% discount) |
haircutAdjustment | string | Absolute haircut adjustment amount in USD |
price | string | Collateral token price in USD at time of calculation |
calculatedAt | integer | Unix timestamp (milliseconds) when price was last calculated; 0 for USDT |
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 |
debt | string | Outstanding debt in the account |
Error Response
Shown with X-Request-ID sent (same echo rules as success).
{
"status": "error",
"error": {
"message": "subaccountId is required",
"code": "VALIDATION_ERROR"
},
"requestId": "5ccf215d37e3ae6d",
"request_id": "5ccf215d37e3ae6d",
"timestamp": 1735689900000
}| 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 |
| Error | HTTP | Code | Description |
|---|---|---|---|
subaccountId is required | 400 | VALIDATION_ERROR | params.subAccountId missing or not resolved from auth context |
Invalid subaccountId: must be a valid number | 400 | VALIDATION_ERROR | params.subAccountId is not a non-negative integer string |
authentication failed: … wallet … is not authorized to act on this subaccount | 401 | UNAUTHORIZED | Signer lacks owner, delegate, or manager access to the requested subAccountId, or the subAccountId does not exist (auth runs before list lookup) |
Failed to list subaccounts | 500 | INTERNAL_ERROR | Subaccount service error after auth succeeds |
Subaccount Information
- Account Access: Caller must be the subaccount owner, a subaccount-level delegated signer, or an account-level manager authorized for the requested
subAccountId - Pure managers: Use getSubAccountIds with
includeDelegations: trueto discovermanagedSubAccountIds, then sign this call with one of those IDs - subAccounts: Always lists all subaccounts under the same master account as
params.subAccountId(the owner's master tree, not filtered by caller wallet). A non-existentsubAccountIdreturns401/UNAUTHORIZEDat auth, not an empty list subAccountsvsmanagedAccounts: For a single Safe, these overlap;managedAccountsadditionally lists every owner workspace when the caller manages multiple accounts- Managed Accounts:
managedAccountsis populated when the authenticated wallet has account-level delegation granted by other wallet owners; it is an empty map ({}) when no such delegations exist - Delegation Visibility: Includes
delegatedSignersfor each subaccount, unlikegetSubAccount - Complementary Data: Use with
getPositionsfor detailed position information andgetPerformanceHistoryfor performance analytics
Code Examples
EIP-712 Signature
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: "1867542890123456789",
action: "getSubAccounts",
expiresAfter: 0 // Optional, use 0 for no expiration
};
const signature = await signer._signTypedData(domain, types, message);Comparison with getSubAccount
| Feature | getSubAccount | getSubAccounts |
|---|---|---|
| Returns | Single subaccount | Master-tree siblings (subAccounts) under the same master as authenticated subAccountId, plus managed accounts map (managedAccounts) |
| Response shape | Single object | Wrapper with subAccounts + managedAccounts |
| Delegated Signers | Not included | Included for each subaccount |
| Managed Accounts | Not included | Included in managedAccounts map |
| Use Case | Specific account lookup | Full account overview with delegation info |
Related Endpoints
- Smart Contract Accounts (Safe) - Gnosis Safe owner + manager flow
- Get Subaccount - Get a single subaccount
- Get Delegated Signers - Get delegated signers for a single subaccount
- Get Delegations For Delegate - Get accounts that have delegated to your wallet
- Get Positions - Get positions for a subaccount
- Get Balance Updates - Track balance changes
:::info Rate Limits The Synthetix API enforces rate limits to ensure fair usage and system stability:
- Order Placement: 100 orders per second per subaccount
- WebSocket Connections: 100 connections per IP address
- WebSocket Subscriptions: 1000 subscriptions per IP address
See Rate Limits for detailed information and best practices. :::
Signing
All trading methods are signed using EIP-712. Each successful trading request will contain:
- A piece of structured data that includes the sender address
- A signature of the hash of that structured data, signed by the sender
For detailed information on EIP-712 signing, see EIP-712 Signing.