Member balances by asset (eight buckets)
x-on-behalf-of required
One row per asset with eight independent buckets. These are not different views of one total, but eight nonoverlapping balances. The member's total for the asset is their sum.
available: available. The only directly spendable bucket. Every order-creation endpoint debits it.pending: incoming. Deposits detected but not yet confirmed. Always 0 undermerchant_hosted, because the merchant determines receipt; funds are already confirmed when the merchant callsPOST /v1/deposits.frozen: frozen. Funds frozen by operations/risk controls per member and asset. Only our administration system can unfreeze them; merchants have no unlock endpoint.isolated: isolated. Funds segregated during disputes, legal assistance, or anti-money-laundering investigations. Separate fromfrozenbecause the handling process differs; do not merge their display.locked: business holds. When an asynchronous, potentially failing order such as a remittance is created, funds move here from available. At the final outcome they are either settled or returned to available.card: funds on cards. Money already sent to the issuing upstream, physically outside our platform. Only card-issuing endpoints may move it. Do not include it in how much the user can still spend from the wallet.earn: wealth products. Principal invested in flexible or fixed-term products.withdrawing: withdrawals in progress. Funds moved from available byPOST /v1/withdrawals. The only exits areconfirm, which clears the hold, orfail, which returns funds to available. Operations cannot modify it, and merchants have no third path.
⚠ Returns assets for which this member already has account rows, not the asset catalog. A member who has never received funds gets an empty array, not a list of 0 balances. To show every selectable asset, also fetch GET /v1/assets and outer-join the two lists.
⚠ The response envelope was standardized to { data, next_cursor, has_more } on 2026-08-13. This endpoint is not paginated and will not be: next_cursor is always null and has_more always false, explicitly indicating a complete list rather than missing fields. Your generic paginator therefore needs no special branch here.
balances is still returned and references the same array as data, but is a transitional compatibility field retained for integrations predating the change. New integrations must read data; existing balances readers should migrate. Its removal will be announced in the changelog, with no second compatibility fallback afterward.
Prerequisites
- The member belongs to this Key's merchant; otherwise always returns member_not_found, identical to a nonexistent member.
Request Headers
| Field | Type | Required | Description |
|---|---|---|---|
x-on-behalf-of |
string | Required | Whose balance to query. Accepts both the merchant's own external_member_id
and our mem_<uuid> returned in member responses. |
Response
{
"data": [
{
"asset": "USDT",
"available": "1250.000000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "300.000000",
"card": "0.000000",
"earn": "5000.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
},
{
"asset": "USD",
"available": "48.750000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "0.000000",
"card": "120.000000",
"earn": "0.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
}
],
"next_cursor": null,
"has_more": false,
"balances": [
{
"asset": "USDT",
"available": "1250.000000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "300.000000",
"card": "0.000000",
"earn": "5000.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
},
{
"asset": "USD",
"available": "48.750000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "0.000000",
"card": "120.000000",
"earn": "0.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
}
]
}member_context_required: missing x-on-behalf-of.member_not_found: nonexistent member, belonging to another merchant, or suspended.
All three return the same response; do not use it to determine whether a member exists.curl -X GET 'https://api.zinfra.vip/v1/balances' \
-H 'x-auth-token: Bearer $TOKEN' \
-H 'x-on-behalf-of: $MEMBER_ID'const res = await fetch("https://api.zinfra.vip/v1/balances", {
method: "GET",
headers: {
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
},
});
// Keep monetary amounts as strings, never numbers.
const data = await res.json();import requests
res = requests.get(
"https://api.zinfra.vip/v1/balances",
headers={
"x-auth-token": "Bearer $TOKEN",
"x-on-behalf-of": "$MEMBER_ID",
},
)
# Use Decimal(str(...)) for amounts, not float.
data = res.json()req, _ := http.NewRequest("GET", "https://api.zinfra.vip/v1/balances",
nil)
req.Header.Set("x-auth-token", "Bearer $TOKEN")
req.Header.Set("x-on-behalf-of", "$MEMBER_ID")
res, err := http.DefaultClient.Do(req)
// Decode amount fields as string, not float64.HttpRequest req = HttpRequest.newBuilder()
.uri(URI.create("https://api.zinfra.vip/v1/balances"))
.header("x-auth-token", "Bearer $TOKEN")
.header("x-on-behalf-of", "$MEMBER_ID")
.method("GET", HttpRequest.BodyPublishers.noBody())
.build();
// Use String / BigDecimal for amounts, not double.$ch = curl_init('https://api.zinfra.vip/v1/balances');
curl_setopt_array($ch, [
CURLOPT_CUSTOMREQUEST => 'GET',
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HTTPHEADER => [
'x-auth-token: Bearer $TOKEN',
'x-on-behalf-of: $MEMBER_ID',
],
]);
$res = curl_exec($ch);
// Use bcmath / strings for amounts, not floatval.
{
"data": [
{
"asset": "USDT",
"available": "1250.000000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "300.000000",
"card": "0.000000",
"earn": "5000.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
},
{
"asset": "USD",
"available": "48.750000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "0.000000",
"card": "120.000000",
"earn": "0.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
}
],
"next_cursor": null,
"has_more": false,
"balances": [
{
"asset": "USDT",
"available": "1250.000000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "300.000000",
"card": "0.000000",
"earn": "5000.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
},
{
"asset": "USD",
"available": "48.750000",
"pending": "0.000000",
"frozen": "0.000000",
"isolated": "0.000000",
"locked": "0.000000",
"card": "120.000000",
"earn": "0.000000",
"withdrawing": "0.000000",
"ledger_scale": 6,
"display_scale": 2
}
]
}