Get Account Balances
POST https://trade-uk.sandbox.zodiamarkets.com/api/3/account
Retrieve account balances across all account groups (sub-accounts). Returns balances for each currency held within each account group, along with balance buckets.
Balances are read from the Account_Groups array, which breaks them down by account group.
Account Balance Objects
Section titled “Account Balance Objects”data.Account_Groups[].Accounts is a map keyed by currency code. The generated field reference lists it as a single object, so the shape of each value is documented here.
Account Balance Object
Section titled “Account Balance Object”Each currency within an account group contains the following balance fields:
| Field | Type | Description |
|---|---|---|
| Balance | Object | Total balance including unsettled amounts |
| Available_Balance | Object | Balance available for withdrawal |
| Brokerage_Available_Balance | Object | Balance available for trading |
| Unsettled_Sell_Balance | Object | Pending sell trade amounts awaiting settlement |
| Unsettled_Buy_Balance | Object | Pending buy trade amounts awaiting settlement |
| ccy | String | Currency code |
| Owner_Uuid | String | UUID of the account owner |
| Uuid | String | Unique identifier for this account |
Balance Detail Object
Section titled “Balance Detail Object”Each balance field (Balance, Available_Balance, etc.) contains:
| Field | Type | Description |
|---|---|---|
| displayShort | String | Abbreviated formatted balance (e.g., "2.34 BTC") |
| valueInt | String | Integer representation of the balance (smallest unit) |
| currency | String | Currency code |
| display | String | Full precision formatted balance (e.g., "2.33581881 BTC") |
| value | String | Decimal string value of the balance |
Understanding Balance Types
Section titled “Understanding Balance Types”| Balance Type | Description |
|---|---|
| Balance | Total balance across all states. Includes unsettled amounts. |
| Available_Balance | Funds available for immediate withdrawal. |
| Brokerage_Available_Balance | Funds available for placing new trades. |
| Unsettled_Sell_Balance | Amount pending from sell trades not yet settled. |
| Unsettled_Buy_Balance | Amount pending from buy trades not yet settled. |
Note:
Balance= settled funds +Unsettled_Buy_Balance-Unsettled_Sell_Balance. Negative balances on unsettled balances indicate unsettled obligations (i.e. trade is unsettled)
Account Groups (Sub-Accounts)
Section titled “Account Groups (Sub-Accounts)”Balances are organised by account group (optional). Each account group represents either the primary account or a sub-account. All users will always have a ‘Default’ account group and can optionally request additional sub-accounts to split their balances.
| Field Value | Meaning |
|---|---|
| Natural: true | Primary (default) account group |
| Natural: false | Sub-account |
Code Examples
Section titled “Code Examples”Python
Section titled “Python”import base64import jsonimport hmacimport hashlibimport timeimport requests
# Configurationapi_key = "your_api_key"api_secret = "your_api_secret"base_url = "https://trade-uk.sandbox.zodiamarkets.com"
# Request body — every signed request must carry a nonce or toncetonce = str(int(time.time() * 1000000))body = { "tonce": tonce, "filterZeroBalanceAccounts": True}body_json = json.dumps(body)
# Generate signaturepath = "api/3/account"message = f"{path}\0{body_json}"signature = base64.b64encode( hmac.new( base64.b64decode(api_secret), message.encode(), hashlib.sha512 ).digest()).decode()
# Make requestheaders = { "Rest-Key": api_key, "Rest-Sign": signature, "Content-Type": "application/json"}
response = requests.post( f"{base_url}/{path}", headers=headers, data=body_json)
# Process responseif response.status_code == 200: data = response.json() for group in data['data']['Account_Groups']: print(f"\nAccount Group: {group['AccountGroup_Name']} ({'Primary' if group['Natural'] else 'Sub-account'})") print(f" UUID: {group['AccountGroup_Uuid']}") for ccy, account in group['Accounts'].items(): print(f" {ccy}:") print(f" Balance: {account['Balance']['display']}") print(f" Available for Trading: {account['Brokerage_Available_Balance']['display']}") print(f" Unsettled Buy: {account['Unsettled_Buy_Balance']['display']}") print(f" Unsettled Sell: {account['Unsettled_Sell_Balance']['display']}")else: print(f"Error: {response.status_code}") print(response.text)JavaScript (Node.js)
Section titled “JavaScript (Node.js)”const crypto = require('crypto');const axios = require('axios');
// Configurationconst apiKey = 'your_api_key';const apiSecret = 'your_api_secret';const baseUrl = 'https://trade-uk.sandbox.zodiamarkets.com';
// Request body — every signed request must carry a nonce or tonceconst tonce = Date.now() * 1000;const body = { tonce, filterZeroBalanceAccounts: true};const bodyJson = JSON.stringify(body);
// Generate signatureconst path = 'api/3/account';const message = `${path}\0${bodyJson}`;const signature = crypto .createHmac('sha512', Buffer.from(apiSecret, 'base64')) .update(message) .digest('base64');
// Make requestconst headers = { 'Rest-Key': apiKey, 'Rest-Sign': signature, 'Content-Type': 'application/json'};
axios.post(`${baseUrl}/${path}`, body, { headers }) .then(response => { response.data.data.Account_Groups.forEach(group => { const type = group.Natural ? 'Primary' : 'Sub-account'; console.log(`\nAccount Group: ${group.AccountGroup_Name} (${type})`); console.log(` UUID: ${group.AccountGroup_Uuid}`); Object.entries(group.Accounts).forEach(([ccy, account]) => { console.log(` ${ccy}:`); console.log(` Balance: ${account.Balance.display}`); console.log(` Available for Trading: ${account.Brokerage_Available_Balance.display}`); }); }); }) .catch(error => { console.error('Error:', error.response?.status); console.error(error.response?.data); });curl -X POST https://trade-uk.sandbox.zodiamarkets.com/api/3/account \ -H "Rest-Key: your_api_key" \ -H "Rest-Sign: your_hmac_signature" \ -H "Content-Type: application/json" \ -d '{ "tonce": 1770888183656000, "filterZeroBalanceAccounts": true }'Common Use Cases
Section titled “Common Use Cases”Get Balances for a Specific Account Group
Section titled “Get Balances for a Specific Account Group”response = make_api_request('POST', 'api/3/account', { 'filterZeroBalanceAccounts': true, 'accountGroupUuid': '2073252c-81ed-41be-bf4d-d51b8f2246b8'})
for group in response['data']['Account_Groups']: for ccy, account in group['Accounts'].items(): print(f"{ccy}: {account['Balance']['display']}")Check Available Trading Balance
Section titled “Check Available Trading Balance”response = make_api_request('POST', 'api/3/account', { 'filterZeroBalanceAccounts': true})
for group in response['data']['Account_Groups']: print(f"\n{group['AccountGroup_Name']}:") for ccy, account in group['Accounts'].items(): brokerage = float(account['Brokerage_Available_Balance']['value']) if brokerage > 0: print(f" {ccy}: {account['Brokerage_Available_Balance']['display']} available for trading")Find All Sub-Accounts with Balances
Section titled “Find All Sub-Accounts with Balances”response = make_api_request('POST', 'api/3/account', { 'filterZeroBalanceAccounts': true})
sub_accounts = [ group for group in response['data']['Account_Groups'] if not group['Natural']]
for group in sub_accounts: print(f"\nSub-account: {group['AccountGroup_Name']}") print(f" UUID: {group['AccountGroup_Uuid']}") for ccy, account in group['Accounts'].items(): print(f" {ccy}: {account['Balance']['display']}")Get Total Balance Across All Account Groups
Section titled “Get Total Balance Across All Account Groups”from collections import defaultdict
response = make_api_request('POST', 'api/3/account', { 'filterZeroBalanceAccounts': true})
totals = defaultdict(float)for group in response['data']['Account_Groups']: for ccy, account in group['Accounts'].items(): totals[ccy] += float(account['Balance']['value'])
for ccy, total in sorted(totals.items()): print(f"{ccy}: {total}")Domain: Accounts
Request
Section titled “Request”POST https://trade-uk.sandbox.zodiamarkets.com/api/3/accountHeaders
Section titled “Headers”| Header | Required | Description |
|---|---|---|
Rest-Key |
yes | API key for authentication |
Rest-Sign |
yes | Calculated API Signature |
| Field | Type | Required | Description |
|---|---|---|---|
tonce |
integer (int64) | yes | The current Unix time in microseconds. |
nonce |
integer (int64) | Alternative to tonce. Every request must carry either nonce or tonce, and the value must parse as a whole number; a request with neither is rejected with INVALID_NONCE_OR_TONCE. |
|
filterZeroBalanceAccounts |
boolean | When true, omits accounts whose balance is not greater than zero. This narrows Account_Groups only; Wallets and Secondary_Wallets ignore it entirely. When false or omitted, a zero-balance account is still returned if its currency is supported for your site. Strongly recommended. — Default: false |
|
accountGroupUuid |
string | Restricts Account_Groups to the single account group with this UUID. Like filterZeroBalanceAccounts, it narrows Account_Groups only; Wallets and Secondary_Wallets ignore it entirely. |
|
userUuid |
string | Master API keys only: UUID of the user to act on behalf of. Ignored unless the calling key belongs to the owner of a master-API-enabled site. |
Responses
Section titled “Responses”200 OK
Section titled “200 OK”| Field | Type | Required | Description |
|---|---|---|---|
data |
object | Account data container | |
data.Created |
string | Account creation date | |
data.Language |
string | Account language locale | |
data.Last_Login |
string | Date of the most recent login for this user | |
data.Login |
string | API user login email | |
data.Rights |
array of string | List of permissions on the API user: trade, withdraw, get_info |
|
data.Wallets |
object | Legacy per-currency balances for the caller’s own natural account group. Deprecated - use Account_Groups. Always present in the response, but an empty object when the caller owns no natural account group, which is always the case for subordinate users. Keyed by currency only. | |
data.Secondary_Wallets |
object | Legacy per-currency balances for account groups other than the caller’s own natural one. Deprecated - use Account_Groups. Always present in the response, but an empty object when the caller belongs to no other account group. Keyed by currency only, so an entry is lost when the same currency is held in more than one of those groups. | |
data.Account_Groups |
array of object | Array of account group objects containing balances | |
data.Account_Groups[].AccountGroup_Uuid |
string | Unique identifier for the account group | |
data.Account_Groups[].AccountGroup_Name |
string | Account group name (e.g., “Default”, sub-account names) | |
data.Account_Groups[].Owner_Uuid |
string | UUID of the account owner | |
data.Account_Groups[].Owner_Name |
string | Owner (Parent) email address | |
data.Account_Groups[].Owner_Shortcode |
string | Client shortcode identifier | |
data.Account_Groups[].Natural |
boolean | true for the primary (default) account group, false for sub-accounts |
|
data.Account_Groups[].Accounts |
object | Map of currency codes to account balance objects — see “Account Balance Object” below for the shape of each value | |
userUuid |
string | Unique identifier for the API user | |
timestamp |
string | Unix timestamp of the response (milliseconds) | |
resultCode |
string | Result status (OK on success) |
|
description |
string | Failure reason. Present only on the error path; absent on success. |
400 Bad Request
Section titled “400 Bad Request”Malformed body, or a missing/stale nonce/tonce. Note that resultCode is hard-coded to INVALID_PARAMETERS on every failure of this endpoint regardless of cause — only the HTTP status distinguishes them, and description carries the reason text.
| Field | Type | Required | Description |
|---|---|---|---|
timestamp |
string | Unix timestamp of the response (milliseconds). | |
resultCode |
string | Always INVALID_PARAMETERS on this endpoint, whatever the real cause. |
|
description |
string | Reason text for the failure. |
401 Unauthorized
Section titled “401 Unauthorized”The key authenticated but is not authorised for this call.
| Field | Type | Required | Description |
|---|---|---|---|
timestamp |
string | Unix timestamp of the response (milliseconds). | |
resultCode |
string | Always INVALID_PARAMETERS on this endpoint, whatever the real cause. |
|
description |
string | Reason text for the failure. |
403 Forbidden
Section titled “403 Forbidden”The key could not be authenticated: unknown, deactivated, locked, expired, or wrong site.
| Field | Type | Required | Description |
|---|---|---|---|
timestamp |
string | Unix timestamp of the response (milliseconds). | |
resultCode |
string | Always INVALID_PARAMETERS on this endpoint, whatever the real cause. |
|
description |
string | Reason text for the failure. |
429 Too Many Requests
Section titled “429 Too Many Requests”The user has exceeded the request rate limit.
| Field | Type | Required | Description |
|---|---|---|---|
timestamp |
string | Unix timestamp of the response (milliseconds). | |
resultCode |
string | Always INVALID_PARAMETERS on this endpoint, whatever the real cause. |
|
description |
string | Reason text for the failure. |
500 Internal Server Error
Section titled “500 Internal Server Error”The request could not be validated.
| Field | Type | Required | Description |
|---|---|---|---|
timestamp |
string | Unix timestamp of the response (milliseconds). | |
resultCode |
string | Always INVALID_PARAMETERS on this endpoint, whatever the real cause. |
|
description |
string | Reason text for the failure. |
