Remove Delegated Signer (WebSocket)
Remove a delegated signer from a subaccount through the WebSocket connection, 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
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "delegate-remove-1",
"method": "post",
"params": {
"action": "removeDelegatedSigner",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"nonce": 1735689600000,
"expiresAfter": 1735689900,
"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 "removeDelegatedSigner" |
subAccountId | string | Yes | Subaccount identifier |
delegateAddress | string | Yes | Ethereum wallet address of the delegated signer to remove (42-character hex format) |
nonce | integer | Yes | Incrementing nonce (Unix ms timestamp as number) |
expiresAfter | integer | No | Optional request expiration timestamp in seconds |
signature | object | Yes | EIP-712 signature |
Important: Only the master account owner can remove delegated signers.
EIP-712 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" }
]
}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 monotonically increasing per subaccount - All delegation operations must be signed by the master account owner
Response Format
Success Response
{
"id": "delegate-remove-1",
"status": 200,
"result": {
"subAccountId": "1867542890123456789",
"walletAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
subAccountId | string | The subaccount ID the signer was removed from |
walletAddress | string | The removed delegated signer's wallet address |
Error Response
{
"id": "delegate-remove-1",
"status": 404,
"result": null,
"error": {
"code": 404,
"message": "Delegated signer not found"
}
}Implementation Example
import { ethers } from 'ethers';
async function removeDelegatedSigner(ws, signer, subAccountId, delegateAddress) {
const nonce = Date.now();
const expiresAfter = Math.floor(Date.now() / 1000) + 300; // 5 minutes
const domain = {
name: "Synthetix",
version: "1",
chainId: 1,
verifyingContract: "0x0000000000000000000000000000000000000000"
};
const types = {
RemoveDelegatedSigner: [
{ name: "subAccountId", type: "uint256" },
{ name: "delegateAddress", type: "address" },
{ name: "nonce", type: "uint256" },
{ name: "expiresAfter", type: "uint256" }
]
};
const message = {
subAccountId: BigInt(subAccountId),
delegateAddress,
nonce: BigInt(nonce),
expiresAfter: BigInt(expiresAfter)
};
const sig = await signer.signTypedData(domain, types, message);
const signature = ethers.Signature.from(sig);
ws.send(JSON.stringify({
id: `delegate-remove-${Date.now()}`,
method: "post",
params: {
action: "removeDelegatedSigner",
subAccountId,
delegateAddress,
nonce,
expiresAfter,
signature: { v: signature.v, r: signature.r, s: signature.s }
}
}));
}
// Usage: Remove a trading bot's delegation
await removeDelegatedSigner(
ws,
signer,
"1867542890123456789",
"0x742d35Cc6634C0532925a3b844Bc9e7595f89590"
);Code Examples
Remove Trading Bot Access
{
"id": "remove-bot",
"method": "post",
"params": {
"action": "removeDelegatedSigner",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x742d35Cc6634C0532925a3b844Bc9e7595f89590",
"nonce": 1735689600000,
"expiresAfter": 1735689900,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Revoke Team Member Access
{
"id": "remove-team-member",
"method": "post",
"params": {
"action": "removeDelegatedSigner",
"subAccountId": "1867542890123456789",
"delegateAddress": "0x9C4b8E7F0A2D3B6C5E8A1F3D5B7C9E1A3F5D7B9E",
"nonce": 1735689600001,
"expiresAfter": 1735689900,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}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
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
Common Errors
| Error Code | Message | Description |
|---|---|---|
| 404 | Delegated signer not found | Address is not delegated for this subaccount |
| 401 | Only master account can remove delegated signers | Must be signed by master account owner |
| 404 | Subaccount not found | Invalid subaccount ID |
| Error | Description |
|---|---|
| Invalid signature | EIP-712 signature validation failed |
| Invalid market symbol | Market symbol not recognized |
| Nonce already used | Nonce must be greater than previous value |
| Rate limit exceeded | Too many requests in time window |
| Request expired | expiresAfter timestamp has passed |
Next Steps
- Add Delegated Signer - Add new delegation
- Get Delegated Signers - List all delegated signers
- Get Subaccount - Account details
- REST Alternative - REST API comparison