vike

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}/balances

Current 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.

cURL
# 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]'
addresspathrequired
Wallet address, 0x-prefixed, exactly 42 characters
chainsqueryoptional
Comma-separated. ethereum, 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_usdqueryoptional
Hide holdings worth less than this. Omitted resolves to 1 (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.

Example response
{
  "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.

Example response
{  "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    }  ]}