Skip to content

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/trade

Request

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

ParameterTypeRequiredDescription
idstringYesClient-generated unique request identifier
methodstringYesMust be "post"
paramsobjectYesContains all parameters for the request

Params Object

ParameterTypeRequiredDescription
actionstringYesMust be "getDelegationsForDelegate"
subAccountIdstringYesSubaccount ID included in the signed SubAccountAction payload
owningAddressstringNoOptional Ethereum address to query on behalf of. When provided and different from the signing wallet, the caller must have trading permission for that address
expiresAfterintegerNoOptional expiration timestamp in seconds
signatureobjectYesEIP-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

FieldTypeDescription
delegatedAccountsarrayArray of delegated account objects

Delegated Account Object

FieldTypeDescription
subAccountIdstringSubaccount ID this delegation applies to
ownerAddressstringEthereum wallet address of the account owner who granted the delegation
accountNamestringHuman-readable name of the delegated account
accountValuestringTotal account value of the delegating subaccount in decimal USDT
permissionsstring[]Array of permission levels granted. Currently supports: ["trading"]
expiresAtinteger | nullUnix 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 getDelegatedSigners which 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 owningAddress when the caller has trading permission 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, and accountValue to help identify which accounts have granted delegation

Common Errors

Error CodeMessageDescription
400Validation errorowningAddress is not a valid hex Ethereum address
401Authentication failedInvalid signature
403ForbiddenCaller does not have trading permission for the specified owningAddress
Error CodeDescriptionRetryable
UNAUTHORIZEDEIP-712 signature validation failedNo
VALIDATION_ERRORRequest validation failedNo
MISSING_REQUIRED_FIELDRequired field is missingNo
INVALID_FORMATField format is invalidNo
INVALID_VALUEInvalid parameter valueNo
RATE_LIMIT_EXCEEDEDToo many requests in time windowYes
INSUFFICIENT_MARGINNot enough margin for tradeNo
ORDER_NOT_FOUNDOrder does not existNo
OPERATION_TIMEOUTOperation timed outYes

Next Steps