Get Delegations For Delegate (WebSocket)
Retrieve a list of all delegations granted to the authenticated wallet address through the WebSocket connection. This endpoint allows a delegate wallet to discover which accounts have delegated permissions to it, enabling frontends to detect when a connected wallet is a delegate and allow switching to the delegator's account.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "delegations-for-delegate-1",
"method": "post",
"params": {
"action": "getDelegationsForDelegate",
"subAccountId": "1867542890123456789",
"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 "getDelegationsForDelegate" |
subAccountId | string | Yes | Subaccount ID included in the signed SubAccountAction payload |
owningAddress | string | No | Optional Ethereum address to query on behalf of. When provided and different from the signing wallet, the caller must have trading permission for that address |
expiresAfter | integer | No | Optional expiration timestamp in seconds |
signature | object | Yes | EIP-712 signature object |
::::info Authentication
The delegate address is determined from the wallet that signed the request. By default, this returns delegations for the signing wallet. If you provide owningAddress, the caller must have trading permission for that address.
::::
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: BigInt("1867542890123456789"),
action: "getDelegationsForDelegate",
expiresAfter: 0
};
const signature = await signer.signTypedData(domain, types, message);Response Format
Success Response
{
"id": "delegations-for-delegate-1",
"status": 200,
"result": {
"delegatedAccounts": [
{
"subAccountId": "1867542890123456789",
"ownerAddress": "0x8B3a9A6F8D1e2C4E5B7A9D0F1C3E5A7B9D1F3E5A",
"accountName": "Main Trading Account",
"accountValue": "12500.50",
"permissions": ["trading"],
"expiresAt": null
},
{
"subAccountId": "2987654321098765432",
"ownerAddress": "0x9C4b8E7F0A2D3B6C5E8A1F3D5B7C9E1A3F5D7B9E",
"accountName": "Secondary Account",
"accountValue": "4300.00",
"permissions": ["trading"],
"expiresAt": 1767225600000
}
]
}
}Empty Response
{
"id": "delegations-for-delegate-1",
"status": 200,
"result": {
"delegatedAccounts": []
}
}Error Response
{
"id": "delegations-for-delegate-1",
"status": 401,
"result": null,
"error": {
"code": 401,
"message": "Authentication failed"
}
}Response Fields
| Field | Type | Description |
|---|---|---|
delegatedAccounts | array | Array of delegated account objects |
Delegated Account Object
| Field | Type | Description |
|---|---|---|
subAccountId | string | Subaccount ID this delegation applies to |
ownerAddress | string | Ethereum wallet address of the account owner who granted the delegation |
accountName | string | Human-readable name of the delegated account |
accountValue | string | Total account value of the delegating subaccount in decimal USDT |
permissions | string[] | Array of permission levels granted. Currently supports: ["trading"] |
expiresAt | integer | null | Unix timestamp (milliseconds) when the delegation expires. null indicates no expiration |
Code Examples
Get All Delegations for Connected Wallet
{
"id": "get-my-delegations",
"method": "post",
"params": {
"action": "getDelegationsForDelegate",
"subAccountId": "1867542890123456789",
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Implementation Example
class DelegationQuery {
constructor(ws, signer) {
this.ws = ws;
this.signer = signer;
this.pendingRequests = new Map();
}
async getDelegationsForDelegate(subAccountId, expiresAfter = 0, owningAddress) {
const signature = await this.signDelegateAction(subAccountId, "getDelegationsForDelegate", expiresAfter);
const request = {
id: `delegations-for-delegate-${Date.now()}`,
method: "post",
params: {
action: "getDelegationsForDelegate",
subAccountId,
expiresAfter,
signature,
...(owningAddress ? { owningAddress } : {})
}
};
return this.sendRequest(request);
}
async signDelegateAction(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 sig = await this.signer.signTypedData(domain, types, message);
const { v, r, s } = ethers.Signature.from(sig);
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);
});
}
}
// Usage - Detect if connected wallet is a delegate
const query = new DelegationQuery(ws, signer);
const result = await query.getDelegationsForDelegate("1867542890123456789");
if (result.delegatedAccounts.length > 0) {
console.log(`This wallet is a delegate for ${result.delegatedAccounts.length} account(s):`);
result.delegatedAccounts.forEach(account => {
console.log(` Account: ${account.accountName}`);
console.log(` Owner: ${account.ownerAddress}`);
console.log(` Value: ${account.accountValue} USDT`);
console.log(` SubAccount ID: ${account.subAccountId}`);
console.log(` Permissions: ${account.permissions.join(', ')}`);
console.log(` Expires: ${account.expiresAt ? new Date(account.expiresAt).toISOString() : 'Never'}`);
console.log('---');
});
} else {
console.log('This wallet is not a delegate for any accounts');
}Use Cases
- Wallet Detection: Frontend can detect when a connected wallet is a delegate and offer account switching
- Account Switching UI: Build interfaces allowing delegates to switch between delegated accounts
- Multi-Account Management: Delegates managing multiple accounts can see all their delegations in one place
- Access Verification: Confirm which accounts a delegate has permission to trade on
- Team Dashboard: Team members can see which accounts they have access to
Implementation Notes
- Delegate-Centric Query: Unlike
getDelegatedSignerswhich queries by subaccount, this endpoint returns all accounts that have delegated permissions to the authenticated wallet - Access Control: Returns delegations for the signing wallet by default, or for
owningAddresswhen the caller hastradingpermission for that address - Real-time Data: Returns current active delegations only
- Expiration Handling: Expired delegations are automatically excluded from results
- No Pagination: All delegations are returned in a single response
- Owner Information: Includes the
ownerAddress,accountName, andaccountValueto help identify which accounts have granted delegation
Common Errors
| Error Code | Message | Description |
|---|---|---|
| 400 | Validation error | owningAddress is not a valid hex Ethereum address |
| 401 | Authentication failed | Invalid signature |
| 403 | Forbidden | Caller does not have trading permission for the specified owningAddress |
| 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 |
Next Steps
- Get Delegated Signers - Query delegations by subaccount
- Add Delegated Signer - Add new delegation
- Remove Delegated Signer - Revoke delegation
- Get Subaccount - Account details
- REST Alternative - REST API comparison