OKX DEX Balance API
4 endpoints for supported chains, wallet total value, all token balances, and specific token balances.
Auth: HMAC-SHA256 signature, 4 headers required (
,
,
,
)
Authentication & Credentials
API Key Application:
OKX Developer Portal
Read credentials from environment variables:
- → API key
- → Secret key (system-generated)
- → Passphrase (developer-supplied)
Never output the above credentials to logs, response content, or any user-visible interface.
typescript
import crypto from 'crypto';
const BASE = 'https://web3.okx.com';
// Signature rule:
// GET → body = "", requestPath includes query string (e.g., "/api/v6/dex/balance/all-token-balances-by-address?address=0x...&chains=1,56")
// POST → body = JSON string of request body, requestPath is path only (e.g., "/api/v6/dex/balance/token-balances-by-address")
async function okxFetch(method: 'GET' | 'POST', path: string, body?: object) {
const timestamp = new Date().toISOString();
const bodyStr = body ? JSON.stringify(body) : '';
const sign = crypto
.createHmac('sha256', process.env.OKX_SECRET_KEY!)
.update(timestamp + method + path + bodyStr)
.digest('base64');
const headers: Record<string, string> = {
'OK-ACCESS-KEY': process.env.OKX_API_KEY!,
'OK-ACCESS-SIGN': sign,
'OK-ACCESS-PASSPHRASE': process.env.OKX_PASSPHRASE!,
'OK-ACCESS-TIMESTAMP': timestamp,
'Content-Type': 'application/json',
};
const res = await fetch(`${BASE}${path}`, {
method,
headers,
...(body && { body: bodyStr }),
});
if (res.status === 429) throw { code: 'RATE_LIMITED', msg: 'Rate limited — retry with backoff', retryable: true };
if (res.status >= 500) throw { code: `HTTP_${res.status}`, msg: 'Server error', retryable: true };
const json = await res.json();
if (json.code !== '0') throw { code: json.code, msg: json.msg || 'API error', retryable: false };
return json.data;
}
Response envelope:
{ "code": "0", "data": [...], "msg": "" }
.
=
means success.
Developer Quickstart
typescript
// Get all token balances (GET)
const balances = await okxFetch('GET', '/api/v6/dex/balance/all-token-balances-by-address?' + new URLSearchParams({
address: '0xYourWallet', chains: '1,56,137',
}));
// → balances[].tokenAssets[]: { symbol, balance (UI units), tokenPrice, rawBalance }
// Check specific tokens (POST)
const specific = await okxFetch('POST', '/api/v6/dex/balance/token-balances-by-address', {
address: '0xYourWallet',
tokenContractAddresses: [
{ chainIndex: '1', tokenContractAddress: '' }, // native ETH
{ chainIndex: '1', tokenContractAddress: '0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48' }, // USDC
],
});
Common Chain IDs
| Chain | chainIndex | Chain | chainIndex |
|---|
| Ethereum | | Arbitrum | |
| BSC | | Base | |
| Polygon | | Solana | |
Address format note: The same
parameter is only valid across chains of the same type. EVM addresses (
) work on Ethereum/BSC/Polygon/Arbitrum/Base etc. Solana addresses (Base58) and Bitcoin addresses (UTXO) have different formats. Do NOT mix — e.g., passing an EVM address with
will return empty data for the Solana portion.
Endpoint Index
Cross-Skill Workflows
This skill is often used before swap (to verify sufficient balance) or as portfolio entry point. Below are typical end-to-end flows showing how data flows between skills.
Workflow A: Pre-Swap Balance Check
User: "Swap 1 SOL for BONK"
1. okx-dex-token /market/token/search?search=BONK → get tokenContractAddress
2. okx-wallet-portfolio /balance/all-token-balances-by-address → verify SOL balance >= 1
↓ balance field (UI units) → convert to minimal units for swap
3. okx-dex-swap /aggregator/quote → get quote
4. okx-dex-swap /aggregator/swap-instruction → execute (Solana)
Data handoff:
- from token search → feeds into swap /
- from balance API is UI units; swap API needs minimal units → multiply by
- If balance < required amount → inform user, do NOT proceed to swap
Workflow B: Portfolio Overview + Analysis
User: "Show my portfolio"
1. okx-wallet-portfolio /balance/total-value-by-address → total USD value
2. okx-wallet-portfolio /balance/all-token-balances-by-address → per-token breakdown
↓ top holdings by USD value
3. okx-dex-token /market/price-info → enrich with 24h change, market cap, liquidity
4. okx-dex-market /market/candles (optional) → price charts for tokens of interest
Workflow C: Sell Underperforming Tokens
1. okx-wallet-portfolio /balance/all-token-balances-by-address → list all holdings
↓ tokenContractAddress + chainIndex for each
2. okx-dex-token /market/price-info → get priceChange24H per token
3. Filter by negative change → user confirms which to sell
4. okx-dex-swap /aggregator/quote → /aggregator/swap → execute sell
Key conversion:
(UI units) ×
=
(minimal units) for swap API.
Operation Flow
Step 1: Identify Intent
- Check total assets ->
GET /balance/total-value-by-address
- View all token holdings ->
GET /balance/all-token-balances-by-address
- Check specific token balance ->
POST /balance/token-balances-by-address
- Unsure which chains are supported ->
GET /balance/supported/chain
first
Step 2: Collect Parameters
- Missing wallet address -> ask user
- Missing target chains -> ask user, or suggest common set ()
- Need to filter risky tokens -> set (only works on ETH/BSC/SOL/BASE)
Step 3: Call and Display
- Total value: display USD amount
- Token balances: show token name, amount (UI units), USD value
- Sort by USD value descending
Step 4: Suggest Next Steps
After displaying results, suggest 2-3 relevant follow-up actions based on the endpoint just called:
| Just called | Suggest |
|---|
/balance/total-value-by-address
| 1. View token-level breakdown → /balance/all-token-balances-by-address
(this skill) 2. Check price trend for top holdings → |
/balance/all-token-balances-by-address
| 1. View detailed analytics (market cap, 24h change) for a token → 2. Swap a token → 3. View price chart for a token → |
/balance/token-balances-by-address
| 1. View full portfolio across all tokens → /balance/all-token-balances-by-address
(this skill) 2. Swap this token → |
Present conversationally, e.g.: "Would you like to see the price chart for your top holding, or swap any of these tokens?" — never expose skill names or endpoint paths to the user.
API Reference
1. GET /balance/supported/chain
No request parameters.
Response:
| Field | Type | Description |
|---|
| String | Chain name (e.g., "Ethereum") |
| String | Chain logo URL |
| String | Chain short name (e.g., "ETH") |
| String | Chain unique identifier (e.g., "1") |
json
{ "code": "0", "data": [{ "name": "Ethereum", "logoUrl": "...", "shortName": "ETH", "chainIndex": "1" }], "msg": "" }
2. GET /balance/total-value-by-address
type warning: This endpoint uses
(
/
), but endpoints #3 and #4 use
(
/
). This is an OKX API inconsistency — pay attention to the type per endpoint.
| Param | Type | Required | Description |
|---|
| String | Yes | Wallet address |
| String | Yes | Chain IDs, comma-separated, max 50. e.g., |
| String | No | =all (default), =tokens only, =DeFi only |
| Boolean | No | =filter risky tokens (default), =include. Only ETH/BSC/SOL/BASE |
Response:
| Field | Type | Description |
|---|
| String | Total asset value in USD |
json
{ "code": "0", "data": [{ "totalValue": "1172.895057177065864522" }], "msg": "success" }
3. GET /balance/all-token-balances-by-address
| Param | Type | Required | Description |
|---|
| String | Yes | Wallet address |
| String | Yes | Chain IDs, comma-separated, max 50 |
| String | No | =filter out (default), =do not filter. Only ETH/BSC/SOL/BASE |
Response key fields:
—
,
,
,
(UI units),
(base units),
(USD),
. Full fields: see
docs.
json
{
"code": "0",
"data": [{
"tokenAssets": [{
"chainIndex": "1", "tokenContractAddress": "0x2260fac5e5542a773aa44fbcfedf7c193bc2c599",
"symbol": "WBTC", "balance": "0.5", "rawBalance": "50000000",
"tokenPrice": "65000.00", "isRiskToken": false,
"address": "0xEd0C6079229E2d407672a117c22b62064f4a4312"
}]
}],
"msg": "success"
}
4. POST /balance/token-balances-by-address
| Param | Type | Required | Description |
|---|
| String | Yes | Wallet address |
| Array | Yes | Max 20 items |
tokenContractAddresses[].chainIndex
| String | Yes | Chain ID (e.g., ) |
tokenContractAddresses[].tokenContractAddress
| String | Yes | Token address ( for native token) |
| String | No | =filter out (default), =do not filter |
Response: Same schema as endpoint #3.
json
{
"code": "0",
"data": [{
"tokenAssets": [{
"chainIndex": "1", "tokenContractAddress": "",
"symbol": "eth", "balance": "1.5", "tokenPrice": "3640.43",
"isRiskToken": false, "rawBalance": "1500000000000000000", "address": "0x..."
}]
}],
"msg": "success"
}
Input / Output Examples
User says: "Check my wallet 0xABC... total assets on Ethereum and BSC"
GET /api/v6/dex/balance/total-value-by-address?address=0xabc...&chains=1,56
-> Display: Total assets $12,345.67
User says: "Show all tokens in my wallet"
GET /api/v6/dex/balance/all-token-balances-by-address?address=0xabc...&chains=1,56
-> Display:
ETH: 1.5 ($4,500.00)
USDC: 2,000 ($2,000.00)
BNB: 3.2 ($1,920.00)
...
User says: "Only check USDC and USDT balances"
POST /api/v6/dex/balance/token-balances-by-address
Body: {
"address": "0xabc...",
"tokenContractAddresses": [
{ "chainIndex": "1", "tokenContractAddress": "0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48" },
{ "chainIndex": "1", "tokenContractAddress": "0xdac17f958d2ee523a2206206994597c13d831ec7" }
]
}
-> Display: USDC: 2,000 ($2,000.00), USDT: 1,500 ($1,500.00)
Edge Cases
- Zero balance: valid state — display , not an error
- Unsupported chain: call first to confirm
- chains exceeds 50: split into batches, max 50 per request
- not working: only supported on ETH/BSC/SOL/BASE
- DeFi positions: use to query DeFi holdings separately
- 429 rate limit: exponential backoff with jitter. See Rate Limit & Fee Docs for tier-specific RPS limits (Trial: 1 RPS, Start-up: 2-50 RPS, Enterprise: custom).
- Cross-skill pipeline rate limit: when chaining calls across multiple skills (e.g., token search → balance → swap), add 300-500ms delay between requests to avoid triggering rate limit (error code ).
- Network error: retry once
- Request timeout: all API calls must set a 10-second timeout limit
Amount Display Rules
- Token amounts in UI units (), never base units ()
- USD values with 2 decimal places
- Large amounts in shorthand ()
- Sort by USD value descending
Global Notes
- supports up to 50 chain IDs (comma-separated strings)
- : =all =tokens only =DeFi only
- only works on ETH()/BSC()/SOL()/BASE()
/token-balances-by-address
is the only POST endpoint in this family
- Total value is returned as a USD string — handle type conversion
- For token prices / K-lines -> use
- For token search / metadata -> use
- For swap execution -> use