Create Subaccount
Create a new trading subaccount under the authenticated wallet address. Subaccounts allow for isolated trading strategies, separate margin management, and organized position tracking within a single master account.
Endpoint
POST https://papi.synthetix.io/v1/tradeRequest
Request Format
{
"params": {
"action": "createSubaccount",
"subAccountId": "1867542890123456789",
"name": "Trading Bot Strategy"
},
"nonce": 1735689600000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
},
"expiresAfter": 1735689900
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
params | object | Yes | Parameters object containing method details |
params.action | string | Yes | Must be "createSubaccount" |
params.subAccountId | string | Yes | Existing owned subaccount ID used to prove wallet ownership |
params.name | string | No | Optional display name for the new subaccount (max 50 chars) |
nonce | integer (uint64) | Yes | Positive integer, incrementing nonce |
signature | object | Yes | EIP-712 signature for wallet authentication |
expiresAfter | integer | No | Optional expiration timestamp in seconds |
Authentication
This endpoint requires the wallet owner to sign a CreateSubaccount payload that includes an existing owned subaccount ID as proof of wallet ownership. In the request body, send that ownership-proof ID as params.subAccountId; in the EIP-712 payload it is signed as masterSubAccountId.
Naming Guidelines
- Optional Parameter: Name can be omitted for system-generated naming
- Descriptive Names: Use clear, meaningful names for easy identification when provided
- Character Limit: Maximum 50 characters when specified
- Default Behavior: If no name provided, system may generate a default identifier
- Strategy-Based: Consider naming based on trading strategy or purpose
Examples:
- "Main Trading"
- "DCA Strategy"
- "Arbitrage Bot"
- "Risk Management"
""(empty string) - System handles default naming
Response
Success Response (New Account)
When a subaccount is first created, subAccountId, subAccountName, and accountLimits are populated. All other fields return zero/null values:
{
"status": "ok",
"response": {
"subAccountId": "1867542890123456790",
"masterAccountId": null,
"subAccountName": "Trading Bot Strategy",
"collaterals": null,
"crossMarginSummary": {
"accountValue": "",
"availableMargin": "",
"totalUnrealizedPnl": "",
"maintenanceMargin": "",
"initialMargin": "",
"withdrawable": "",
"adjustedAccountValue": "",
"debt": ""
},
"positions": null,
"marketPreferences": {
"leverages": null
},
"feeRates": {
"makerFeeRate": "",
"takerFeeRate": "",
"tierName": ""
},
"accountLimits": {
"maxBorrowCapacity": "100000",
"maxOrdersPerMarket": 50,
"maxSubAccounts": 10,
"maxTotalOrders": 200
}
},
"request_id": "5ccf215d37e3ae6d"
}Response Structure
Response Fields
| Field | Type | Description |
|---|---|---|
subAccountId | string | System-generated unique identifier for the new subaccount (populated) |
masterAccountId | string | null | Master account ID (returns null) |
subAccountName | string | Display name provided in request (or empty if not specified) (populated) |
collaterals | array | null | Collateral balances (returns null for new accounts) |
collaterals[].adjustedCollateralValue | string | Adjusted collateral value after applying haircuts |
collaterals[].calculatedAt | integer | Unix millisecond timestamp of the collateral price calculation (0 for USDT) |
collaterals[].collateralValue | string | Raw collateral value |
collaterals[].pendingWithdraw | string | Amount pending withdrawal |
collaterals[].price | string | Collateral price used for valuation |
collaterals[].quantity | string | Total collateral quantity held |
collaterals[].symbol | string | Collateral asset symbol |
collaterals[].withdrawable | string | Amount available to withdraw |
crossMarginSummary | object | Cross-margin account summary (returns empty strings for new accounts) |
crossMarginSummary.debt | string | USDT debt after positive unrealized PnL offset |
positions | array | null | Open positions (returns null for new accounts) |
marketPreferences | object | Market-specific preferences like leverage (returns empty for new accounts) |
feeRates | object | Fee rate information (returns empty strings for new accounts) |
accountLimits | object | Account limit information |
accountLimits.maxBorrowCapacity | string | Maximum borrow capacity in USDT |
accountLimits.maxOrdersPerMarket | integer | Maximum open orders allowed per market |
accountLimits.maxSubAccounts | integer | Maximum number of subaccounts allowed for the wallet |
accountLimits.maxTotalOrders | integer | Maximum total open orders across all markets |
Initial State
- Populated Fields:
subAccountId,subAccountName, andaccountLimitsare populated upon creation - Zero/Null Values: Other fields are returned with zero or null values since the account has no positions or collaterals yet
- Active Status: Subaccount is immediately available for trading
- Full Functionality: All trading features are enabled upon creation
- Additional Details: Use Get Subaccount after deposits/trades to retrieve populated account information including positions and collaterals
Error Response
{
"status": "error",
"error": {
"message": "Failed to create subaccount",
"code": "INTERNAL_ERROR"
},
"request_id": "5ccf215d37e3ae6d"
}Common Error Cases
{
"status": "error",
"error": {
"message": "Subaccount limit reached",
"code": "VALIDATION_ERROR"
},
"request_id": "5ccf215d37e3ae6d"
}{
"status": "error",
"error": {
"message": "Invalid subaccount name",
"code": "VALIDATION_ERROR"
},
"request_id": "5ccf215d37e3ae6d"
}Code Examples
Create Basic Subaccount
{
"params": {
"action": "createSubaccount",
"subAccountId": "1867542890123456789",
"name": "Main Trading"
},
"nonce": 1735689600000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
},
"expiresAfter": 1735689900
}Create Strategy-Specific Subaccount
{
"params": {
"action": "createSubaccount",
"subAccountId": "1867542890123456789",
"name": "Grid Trading Bot"
},
"nonce": 1735689600001,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
},
"expiresAfter": 1735689901
}Implementation Notes
- Wallet owner signature required, plus an existing owned subaccount ID supplied as
params.subAccountIdfor ownership proof - Subaccount name parameter is optional and accepts empty string for system-generated naming
- Name length must not exceed 50 characters when provided
- Account creation limits may apply per platform configuration
- New subaccounts are immediately available for trading operations
- Each subaccount inherits master wallet security and authorization settings
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.
Nonce Management
The nonce system prevents replay attacks and ensures order uniqueness:
- Use any positive integer as nonce
- Each nonce must be greater than the previous one (incrementing)
Date.now()is a convenient option, not a requirement- If nonce conflicts occur, increment by 1 and retry
:::note SubAccountAction Exception
SubAccountAction endpoints (getPositions, getOpenOrders, getOrdersHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates) do not require a nonce. Only the signature and optional expiresAfter parameters are needed.
:::
Error Handling
| 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 |
