Wallet token balances
Current token balances for a wallet on Ethereum, BSC, Base and HyperEVM, read from the chain at request time, with a USD value where the token is priced.
GET https://data.vike.io/v1/onchain/wallets/{address}/balancesCurrent token balances for one wallet, read from the chain when you ask. The candidate token set
comes from our own transfer index; the amounts come from balanceOf on the node, so a balance is
what the contract says it is at that block rather than a figure derived from history.
Four chains, and the list is the answer — not a default
ethereum, bsc, base and hyperevm are the chains this route can answer for, because they are
the four the transfer index covers and the index is what supplies the candidate tokens. Without
chains all four are scanned. chains_scanned in the response names what was actually read.
Ask for a chain outside that set and it comes back named in chain_errors — not silently
scanned and empty. A wallet reported as holding nothing because nobody looked is the one answer
this endpoint must never give.
# what a wallet holds right now, keeping only token holdings worth at least 3,000 USD; the native coin is listed whatever its value
curl -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/balances?min_usd=3000"
# the simplest call: all four chains, and an omitted floor resolves to 1 USD rather than 0
curl -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/balances"
# the complete list, unpriced airdrops included: an explicit 0 is honoured, and a long-lived wallet can return thousands of rows
curl -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/balances?min_usd=0"
# one chain only
curl -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/balances?chains=bsc&min_usd=100"
# an alias works for a chain name: eth, mainnet, bnb and binance are accepted
curl -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/balances?chains=eth,bnb&min_usd=100"
# a chain this route does not scan is named in chain_errors rather than reported as an empty wallet
curl -s -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/balances?chains=base,ethereum&min_usd=3000" \
| jq '{chains_scanned, chain_errors}'
# the ten most valuable holdings: the route lists largest USD value first with unpriced ones last, and the priced native ETH, BNB or HYPE row sorts by its value like any token; total_usd sums priced holdings only, so read it as a floor
curl -s -H "X-API-Key: $VIKE_API_KEY" \
"https://data.vike.io/v1/onchain/wallets/0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045/balances?min_usd=1" \
| jq '.holdings[:10]'addresspathrequiredchainsqueryoptionalethereum, bsc, base and hyperevm; the aliases eth, mainnet, bnb and binance are accepted. Omit for all four. Any other chain is reported in chain_errors.min_usdqueryoptional1 (USD); an explicit 0 filters nothing and lists every holding. ⚠ Any floor above 0 also excludes holdings we cannot price, since an unpriced holding cannot be shown to clear it. The chain's native coin is the exception: it is always listed (when its balance is not zero), priced where a price exists, whatever the floor.A live response, captured 2026-10-24 for vitalik.eth at min_usd=100000, the whole response. No token
the wallet holds clears that floor, so the four native-coin rows, one per chain, are the entire answer:
the native coin is listed whatever the floor, and each row is priced and counted in total_usd.
{
"address": "0xd8da6bf26964af9d7eed9e03e53415d37aa96045",
"total_usd": 21375.42,
"chains_scanned": ["ethereum", "bsc", "base", "hyperevm"],
"holdings": [
{
"chain": "ethereum",
"symbol": "ETH",
"name": "ETH",
"address": null,
"balance": 5.77344569189079,
"balance_raw": "5773445691890789631",
"usd_value": 13781.27,
"usd_price": 2387.01
},
{
"chain": "base",
"symbol": "ETH",
"name": "ETH",
"address": null,
"balance": 3.1288218134727375,
"balance_raw": "3128821813472737280",
"usd_value": 7468.53,
"usd_price": 2387.01
},
{
"chain": "bsc",
"symbol": "BNB",
"name": "BNB",
"address": null,
"balance": 0.16869681254396504,
"balance_raw": "168696812543965050",
"usd_value": 125.11,
"usd_price": 741.65
},
{
"chain": "hyperevm",
"symbol": "HYPE",
"name": "HYPE",
"address": null,
"balance": 0.006529929669036304,
"balance_raw": "6529929669036304",
"usd_value": 0.51,
"usd_price": 77.431
}
]
}usd_value: null is a holding, not an error
A balance is measured; a price is looked up, and most tokens do not have one: only a small share
of the tokens traded on Ethereum carry a price feed, out of the hundreds of thousands that exist. A
holding we cannot price is still listed, with usd_value and usd_price both null, because
dropping it would under-report the wallet.
total_usd therefore sums only the priced holdings. Read it as a floor, never as net worth, and
never infer "worthless" from a null — it means unpriced here.
This is why min_usd above 0 drops unpriced holdings, and why it defaults to 1
A floor says "worth at least this much", and an unpriced holding cannot show that. Most
tokens in a long-lived wallet are unpriced airdrops — vitalik.eth carries over seven thousand
of them. A value floor that kept everything it could not price would return all of them and
filter almost nothing.
min_usd=0 is the way to ask for the complete list, and it is honoured: an omitted floor and an
explicit zero are different requests.
balance_raw is the integer the contract returned, as a string. Use it when you need exactness:
balance is that integer divided by the token's decimals and is a float, so it loses precision
on large balances.
The native coin
ETH on ethereum and base, BNB on bsc and HYPE on hyperevm are included when non-zero, with
address: null — a native coin has no contract — and the coin's ticker as both symbol and name.
The row is listed whatever min_usd says: the floor applies to tokens only. It is priced from the
latest daily price we hold for the coin, so it carries usd_value and usd_price, counts toward
total_usd and sorts by its value among the priced holdings; where no price is held, both are null.
Base and HyperEVM list every token, but name only the ones we price
On ethereum and bsc a held token carries its symbol and name from our token metadata. On base and
hyperevm there is no such registry beyond the tokens we map and price — about 170 on base and about
50 on hyperevm. For those tokens symbol, name, balance and usd_value are filled as on the other
chains. Any other token the wallet holds is listed with its contract address and balance_raw, with
symbol, name, balance and usd_value null, only when you pass min_usd=0: the default floor of
1 and any floor above 0 keep priced tokens only, so they drop these.
hyperevm means the HyperEVM chain only: assets held in HyperCore, in a spot or perp account, are not
included.
What this route cannot see
A token the wallet holds but which never appeared in our transfer index is invisible here: the
index supplies the candidate list, and balanceOf is only called for tokens on it. That fails
toward omission — a missing row, never a wrong number.
It is the narrower of the two available gaps, and deliberately chosen. Until 2026-09-04 this
route was served by a third-party API; a period when that vendor was unavailable returned
200 with an empty holdings array and total_usd: 0.0, which reads exactly like an empty
wallet. Both shapes are on the changelog.
Related
/wallets/{address}— the wallet summary/wallets/{address}/transactions— the transfer history the candidate list is drawn from- Rate limits · Authentication