Remove Delegated Signer
Remove a delegated signer from a subaccount, revoking their ability to perform trading actions on behalf of the subaccount. This immediately terminates the trading permission previously granted to the specified wallet address.
Endpoint
POST https://papi.synthetix.io/v1/tradeRequest
Request Format
{
"params": {
"action": "removeDelegatedSigner",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590"
},
"nonce": 1735689600000,
"expiresAfter": 1735689900000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}Request Parameters
| Parameter | Type | Required | Description |
|---|---|---|---|
params | object | Yes | Action object containing removal details |
params.action | string | Yes | Must be "removeDelegatedSigner" |
params.subAccountId | string | Yes | The subaccount ID to remove the delegated signer from |
params.delegateAddress | string | Yes | Ethereum wallet address of the delegated signer to remove (42-character hex format) |
expiresAfter | integer | No | Optional request expiration timestamp (milliseconds) |
| Parameter | Type | Required | Description |
|---|---|---|---|
nonce | uint64 | Yes* | Positive integer nonce (must be incrementing and unique per request) |
signature | object | Yes | EIP-712 signature object |
expiresAfter | uint64 | No | Unix milliseconds expiration timestamp (5x rate limit on stale cancels) |
:::info Common Parameters
These are top-level request parameters. The subAccountId parameter is specified within the params object (see each endpoint's parameter table).
:::
:::info SubAccountAction Endpoints
Endpoints using SubAccountAction signing (getPositions, getOpenOrders, getOrdersHistory, getTrades, getFundingPayments, getSubAccount, getSubAccounts, getDelegatedSigners, getBalanceUpdates) do not require the nonce parameter. Only signature and optional expiresAfter are needed.
:::
EIP-712 Signature Structure
The request is signed using EIP-712 with the following type definition:
EIP-712 Type Definitions for Delegation
AddDelegatedSigner
const AddDelegatedSignerTypes = {
AddDelegatedSigner: [
{ name: "delegateAddress", type: "address" },
{ name: "subAccountId", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" },
{ name: "expiresAt", type: "uint256" },
{ name: "permissions", type: "string[]" }
]
}GetDelegatedSigners
Uses the standard SubAccountAction type (same as other read operations like getTrades, getPositions):
const SubAccountActionTypes = {
SubAccountAction: [
{ name: "subAccountId", type: "uint256" },
{ name: "action", type: "string" },
{ name: "expiresAfter", type: "uint256" }
]
}
// Message example:
const message = {
subAccountId: "1867542890123456789",
action: "getDelegatedSigners",
expiresAfter: 0 // Optional, use 0 if not expiring
}RemoveDelegatedSigner
const RemoveDelegatedSignerTypes = {
RemoveDelegatedSigner: [
{ name: "delegateAddress", type: "address" },
{ name: "subAccountId", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
}RemoveAllDelegatedSigners
const RemoveAllDelegatedSignersTypes = {
RemoveAllDelegatedSigners: [
{ name: "subAccountId", type: "uint256" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
}Example Typed Data for AddDelegatedSigner
{
"types": {
"EIP712Domain": [
{ "name": "name", "type": "string" },
{ "name": "version", "type": "string" },
{ "name": "chainId", "type": "uint256" },
{ "name": "verifyingContract", "type": "address" }
],
"AddDelegatedSigner": [
{ "name": "delegateAddress", "type": "address" },
{ "name": "subAccountId", "type": "uint256" },
{ "name": "nonce", "type": "uint256" },
{ "name": "expiresAfter", "type": "uint256" },
{ "name": "expiresAt", "type": "uint256" },
{ "name": "permissions", "type": "string[]" }
]
},
"primaryType": "AddDelegatedSigner",
"domain": {
"name": "Synthetix",
"version": "1",
"chainId": 1,
"verifyingContract": "0x0000000000000000000000000000000000000000"
},
"message": {
"delegateAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"subAccountId": "1867542890123456789",
"nonce": 1735689600000,
"expiresAfter": 1735689900000,
"expiresAt": 0,
"permissions": ["trading"]
}
}Important Notes:
- Field order matters for EIP-712 - Fields must be in the exact order shown above for signature verification
delegateAddressis the wallet address being granted delegation permissionsexpiresAfteris the request expiration timestamp (when the request itself expires)expiresAtis when the delegation permission expires (use0for no expiration)- The
noncefield must be a positive integer, incrementing per subaccount - All delegation operations must be signed by the master account owner
Response
Success Response
{
"status": "ok",
"response": {
"subAccountId": "1867542890123456789",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590"
},
"request_id": "5ccf215d37e3ae6d"
}Cascade Removal Response
{
"status": "ok",
"response": {
"subAccountId": "1867542890123456789",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"cascadeRemovedSigners": [
"0x1111111111111111111111111111111111111111",
"0x2222222222222222222222222222222222222222"
]
},
"request_id": "5ccf215d37e3ae6d"
}Response Fields
| Field | Type | Description |
|---|---|---|
subAccountId | string | The subaccount ID the signer was removed from |
walletAddress | string | The removed delegated signer's wallet address |
cascadeRemovedSigners | string[] | omitted | Wallet addresses of sub-delegates automatically removed because they were created by the removed signer. Omitted when empty |
Error Response
{
"status": "error",
"error": {
"message": "Delegated signer not found",
"code": "NOT_FOUND"
},
"request_id": "5ccf215d37e3ae6d"
}Common Error Cases
{
"status": "error",
"error": {
"message": "Only master account can remove delegated signers",
"code": "UNAUTHORIZED"
},
"request_id": "5ccf215d37e3ae6d"
}{
"status": "error",
"error": {
"message": "Subaccount not found",
"code": "NOT_FOUND"
},
"request_id": "5ccf215d37e3ae6d"
}Code Examples
Remove Trading Bot Access
{
"params": {
"action": "removeDelegatedSigner",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590"
},
"nonce": 1735689600000,
"expiresAfter": 1735689900000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}Revoke Team Member Access
{
"params": {
"action": "removeDelegatedSigner",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x9C4b8E7F0A2D3B6C5E8A1F3D5B7C9E1A3F5D7B9E"
},
"nonce": 1735689600001,
"expiresAfter": 1735689900000,
"signature": {
"v": 28,
"r": "0x1234567890abcdef1234567890abcdef1234567890abcdef1234567890abcdef",
"s": "0xabcdef1234567890abcdef1234567890abcdef1234567890abcdef1234567890"
}
}Implementation Notes
- Immediate Effect: Removal takes effect immediately upon successful execution
- Access Requirements: Only master account owners can remove delegated signers
- No Self-Removal: Delegated signers cannot remove themselves (must be done by master account)
- Idempotent: Attempting to remove a non-existent delegation returns an error
- Active Sessions: Any active sessions or connections for the removed signer should be terminated
- Pending Operations: Any pending operations initiated by the removed signer remain valid
- Audit Trail: All removal actions are logged for security and compliance
Security Considerations
- Master Account Only: System validates that only the master account can remove delegated signers
- Address Validation: Wallet addresses must be valid Ethereum addresses
- Signature Required: All removal operations require valid EIP-712 signatures
- Cascade Removal: If the removed signer created sub-delegates, the backend returns those automatically revoked addresses in
cascadeRemovedSigners. The field is omitted when no cascade occurs. - Recovery: Removed signers can be re-added if needed through the
addDelegatedSignerendpoint
Effect on Active Operations
| Operation Type | Effect of Removal |
|---|---|
| Open Orders | Remain active (can be cancelled by master account) |
| Pending Withdrawals | Continue processing |
| Active Sessions | Should be terminated |
| API Keys | Should be invalidated |
| Subscriptions | Should be cancelled |
Use Cases
- Security Response: Immediately revoke access when a delegated signer is compromised
- Team Changes: Remove access when team members leave or change roles
- Bot Decommission: Remove trading bot access when no longer needed
- Access Rotation: Regular removal and re-addition of signers for security
- Emergency Lockdown: Quick removal of all delegated signers in security events
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 |