Token Holders and Wallet Balances
Two tools on the Bitquery MCP server answer balance questions for a whole chain. They exist on nine chains under the chain's prefix: tron_, eth_, bsc_, base_, arbitrum_, optimism_, matic_ (Polygon), robinhood_ and arc_.
| Tool | Use it when | Comes back as |
|---|---|---|
<chain>_token_holders | You need the addresses that hold an asset and do not have them yet | One row per holder with its current balance |
<chain>_native_balances | You already have up to 50 addresses and want each one's current native coin balance | One row per address |
Balances are in the asset's own units, never USD. Decimals gives the scale. Pass the holder addresses to labels_for_addresses to see which are exchanges, bridges or known entities.
Export the holders of an asset
Ask for the asset by contract address, or by the native coin's name. The agent pages through the list and can write each page to a file.
"Export every Tron address holding at least 1 TRX. Use tron_token_holders with limit 10000, follow Next_Cursor until it is empty, and write each page to holders.csv."
Tron
tron_token_holders takes token (a TRC-20 contract address starting with T, or TRX for the native coin), min_amount (default 1), limit (up to 10,000 per page) and cursor. Each row carries Holder, Balance, Decimals, Symbol, Status and Next_Cursor.
- TRC-20 holders come back largest balance first.
- Native TRX holders come back in address order, not ranked. The native holder set is too large to rank.
min_amountis the filter that matters: the default1returns holders of 1 TRX or more, and0returns every funded address, which is very many pages. - Pass
Next_Cursorfrom one page intocursoron the next call, keeping the sametoken,min_amountandlimit. An empty page that still has aNext_Cursormeans keep going. An emptyNext_Cursormeans the list is complete. - A holder never appears on two pages, so the pages joined together are the full list.
- A row with an empty
Holderis a status row. ReadStatus:OK,EMPTY_WINDOW,TOO_LARGE,NO_HOLDERSorBAD_CURSOR. A token with a very long balance history, such as USDT, returnsTOO_LARGE. - TRC-10 assets are not supported.
A first page for native TRX with limit: 3 looks like this:
| Holder | Balance | Symbol | Status | Next_Cursor |
|---|---|---|---|---|
| T9yD14Nj9j7xAB4dbGeiX9h8unkKLxmGkn | 541.821241 | TRX | OK | T9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW |
| T9yD14Nj9j7xAB4dbGeiX9h8unkKT76qbH | 3.915384 | TRX | OK | T9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW |
| T9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW | 88.11091 | TRX | OK | T9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW |
EVM chains
<chain>_token_holders takes a token contract address and ranks holders largest first, up to 1,000 per page. min_amount and max_amount bound the balances returned; max_amount is how you look past a burn address that holds most of the supply.
days: 0(the default) ranks every holder over the token's whole history. A very widely held token, such as a major stablecoin, has too much history for that and answers with oneTOO_LARGEstatus row instead of timing out.- Then pass
days: 30(or7). The page ranks the holders whose balance changed in that window, with exact current balances. Holders who did not move the token in the window are absent, so the page is the top of the active holders. Next_Cursoris a date. Pass it ascursorto get the next older window of the same length. No holder appears on two pages, so the top N of all pages merged is the global top N.Window_FromandWindow_Tosay which dates a page covers.- Holders with a negative recorded balance are dropped and counted in
Negative_Balances_Excluded. A balance far above the token's supply is a data artifact, not a whale: check it withtoken_supplybefore reporting it. Symbol_NonAscii = 1flags a symbol with non-ASCII letters. That is normal for CJK or emoji names, and also how a scam token imitates a major one.
Check balances of wallets you already have
"Here are 50 Tron addresses. Give me each one's current TRX balance and keep only those above 100 TRX."
Pass the addresses in one string separated by |, up to 50 per call. Addresses after the 50th distinct one are ignored, so compare Addresses_Requested with Addresses_Used and split a longer list into several calls. Each row carries Address, Native_Balance, Native_Balance_Raw (the exact integer, in sun or wei) and Balance_As_Of.
Tron
tron_native_balances sums each address's whole balance history, so a funded wallet that has not moved in years still gets a row. Balance_Inconsistent = 1 marks a rare negative sum, usually a missing or doubled delta in the log; treat that balance as suspect. A set that includes a very busy wallet may be refused on the row budget; split it.
| Address | Native_Balance | Native_Balance_Raw | Balance_As_Of |
|---|---|---|---|
| T9yD14Nj9j7xAB4dbGeiX9h8unkKLxmGkn | 541.821241 | 541821241 | 2026-08-05T13:57:24Z |
| T9yD14Nj9j7xAB4dbGeiX9h8unkP29JXHW | 88.11091 | 88110910 | 2022-09-26T10:03:45Z |
EVM chains
<chain>_native_balances reads only balances updated in the last since_days days (default 2, up to 30). A wallet that has not moved its native coin in that window returns no row. Use the same window you used to find the wallets, for example the window of eth_token_senders: an active wallet's balance is always fresh there, and a wider window costs more for no gain.
Large exports
- For a file export, pass
limit: 10000on Tron andformat: "columnar". Columnar returns the column names once and each row as a list of values, so the same data takes less room. - Run the paging loop from a script, or ask the agent to write each page to a file. A chat client may cut off a long result shown inline.
- Where a GraphQL query is the better fit, for example the top 100 holders of one token with no paging, see the Tron balance API and the Ethereum token holders API.
Ready to run this in production?
Get an API key and run these queries in minutes, or talk to us about plans and enterprise delivery.