Get Balance Updates (WebSocket)
Retrieve historical deposit, withdrawal, and transfer transactions for a subaccount through the WebSocket connection. This endpoint returns balance changes from on-chain deposits, withdrawals, and internal transfers, excluding funding payments.
Endpoint
ws.send() wss://api.synthetix.io/v1/ws/tradeRequest
Request Format
{
"id": "balance-updates-1",
"method": "post",
"params": {
"action": "getBalanceUpdates",
"subAccountId": "1867542890123456789",
"actionFilter": "DEPOSIT",
"limit": 50,
"offset": 0,
"startTime": 1704067200000,
"endTime": 1704153600000,
"expiresAfter": 1704153600,
"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 "getBalanceUpdates" |
subAccountId | string | Yes | Subaccount identifier |
actionFilter | string | No | Filter by action type: "DEPOSIT", "WITHDRAWAL", "TRANSFER", or comma-separated (e.g. "DEPOSIT,WITHDRAWAL"). Defaults to all types |
limit | integer | No | Maximum number of results to return (default: 50, max: 1000) |
offset | integer | No | Pagination offset (default: 0, max: 10000) |
startTime | integer | No | Start of time range as Unix timestamp in milliseconds. Defaults to 7 days before endTime (or 7 days ago if neither is set) |
endTime | integer | No | End of time range as Unix timestamp in milliseconds. Defaults to 7 days after startTime (or now if neither is set). Maximum range is 365 days |
expiresAfter | integer | No | Optional expiration timestamp in seconds |
signature | object | Yes | EIP-712 signature using SubAccountAction type |
- This endpoint uses
SubAccountActionEIP-712 type (no nonce required) - Returns deposit, withdrawal, and internal transfer transactions (excludes funding payments)
- For funding payment history, use Get Funding Payments
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: "1867542890123456789",
action: "getBalanceUpdates",
expiresAfter: 0,
};
const signature = await signer._signTypedData(domain, types, message);Response Format
Success Response
{
"id": "balance-updates-1",
"status": 200,
"result": {
"status": "success",
"response": {
"balanceUpdates": [
{
"id": "12345",
"subAccountId": "1867542890123456789",
"action": "DEPOSIT",
"status": "success",
"amount": "1000.00",
"fee": "0.00",
"grossAmount": "1000.00",
"collateral": "USDT",
"timestamp": 1704067200000
}
]
}
}
}Empty Result
{
"id": "balance-updates-1",
"status": 200,
"result": {
"status": "success",
"response": {
"balanceUpdates": []
}
}
}Error Response
{
"id": "balance-updates-1",
"status": 400,
"result": null,
"error": {
"code": 400,
"message": "limit cannot exceed 1000"
}
}Response Fields
Balance Update Object
| Field | Type | Description |
|---|---|---|
id | string | Unique transaction ID (string for JS BigInt compatibility) |
subAccountId | string | Subaccount ID associated with the transaction (string for JS BigInt compatibility) |
action | string | Action type: "DEPOSIT", "WITHDRAWAL", or "TRANSFER" |
status | string | Transaction status: "pending", "success", or "failed" |
amount | string | Net amount changed (positive for deposits, negative for withdrawals) |
fee | string | Fee charged for the transaction |
grossAmount | string | Total amount including fee (amount + fee) |
collateral | string | Collateral symbol (e.g., "USDT", "WETH") |
timestamp | integer | Unix timestamp in milliseconds when the transaction was created |
destinationAddress | string | Destination address for withdrawals (optional, only for withdrawals) |
txHash | string | On-chain transaction hash (optional) |
fromSubAccountId | string | Source subaccount ID for internal transfers (optional) |
toSubAccountId | string | Target subaccount ID for internal transfers (optional) |
Code Examples
Get All Balance Updates
{
"id": "all-updates",
"method": "post",
"params": {
"action": "getBalanceUpdates",
"subAccountId": "1867542890123456789",
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Get Deposits Only
{
"id": "deposits-only",
"method": "post",
"params": {
"action": "getBalanceUpdates",
"subAccountId": "1867542890123456789",
"actionFilter": "DEPOSIT",
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Get Withdrawals Only
{
"id": "withdrawals-only",
"method": "post",
"params": {
"action": "getBalanceUpdates",
"subAccountId": "1867542890123456789",
"actionFilter": "WITHDRAWAL",
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Paginated Request
{
"id": "paginated",
"method": "post",
"params": {
"action": "getBalanceUpdates",
"subAccountId": "1867542890123456789",
"limit": 100,
"offset": 100,
"expiresAfter": 0,
"signature": { "v": 28, "r": "0x...", "s": "0x..." }
}
}Implementation Example
class BalanceUpdatesQuery {
constructor(ws, signer) {
this.ws = ws;
this.signer = signer;
this.pendingRequests = new Map();
}
async getBalanceUpdates(options = {}) {
const {
subAccountId,
actionFilter = null,
limit = 50,
offset = 0,
expiresAfter = 0,
} = options;
const signature = await this.signSubAccountAction(
subAccountId,
"getBalanceUpdates",
expiresAfter,
);
const request = {
id: `balance-updates-${Date.now()}`,
method: "post",
params: {
action: "getBalanceUpdates",
subAccountId,
limit,
offset,
expiresAfter,
signature,
},
};
if (actionFilter) {
request.params.actionFilter = actionFilter;
}
return this.sendRequest(request);
}
async signSubAccountAction(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
const query = new BalanceUpdatesQuery(ws, signer);
// Get all deposits
const deposits = await query.getBalanceUpdates({
subAccountId: "1867542890123456789",
actionFilter: "DEPOSIT",
});
console.log(`Found ${deposits.response.balanceUpdates.length} deposits`);Implementation Notes
- Returns deposit, withdrawal, and internal transfer transactions (excludes funding payments)
- Results are ordered by timestamp (most recent first)
- Default limit is 50 results per request, maximum is 1000
- Pagination offset maximum is 10,000
- Use pagination with
limitandoffsetfor large result sets - When
startTimeandendTimeare both omitted, the default time window is the last 7 days - When only one time bound is supplied, the other is automatically extended by 7 days (end time is capped at now)
- Maximum allowed time range is 365 days; requests spanning a longer period are rejected
- Authentication requires signature by account owner or authorized delegate
Common Errors
| Error Code | Message | Description |
|---|---|---|
| 400 | subAccountId is required | No subaccount ID was provided |
| 400 | limit cannot exceed 1000 | Limit parameter exceeds maximum |
| 400 | limit must be non-negative | Negative limit value provided |
| 400 | offset must be non-negative | Negative offset value provided |
| 400 | offset cannot exceed 10000 | Offset exceeds maximum of 10000 |
| 400 | invalid action filter, available filters: DEPOSIT, WITHDRAWAL, TRANSFER | Invalid action filter value |
| 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 Subaccount - View current account balances
- Get Funding Payments - Funding payment history
- Withdraw Collateral - Initiate withdrawals
- REST Alternative - REST API comparison
