Blockchain Address Lookup API: Balance, Transfers and Activity for Any Address
A blockchain address lookup answers four questions about a wallet: what it holds now, what it sent and received lately, when it was first and last active, and which tokens it owns. This page answers each question with one GraphQL query on Ethereum (an EVM chain) and on Tron. The same queries work on every EVM network Bitquery supports by changing network, and the per-chain pages cover the rest. To ask the same questions in plain English, use the Bitquery MCP.
The examples use two well-known addresses:
- Ethereum:
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045(vitalik.eth). - Tron:
TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv(an OKX hot wallet).
Replace them with the address you want to look up. Every query runs on the v2 endpoint https://streaming.bitquery.io/graphql. Balances and activity times come from the Balances cube, which stores the current state per address and currency, so the lookup is fast even for addresses with years of history. dataset: combined merges the realtime and archive data, so an address that has been quiet for years is found too.
Current balance of an address
The native coin balance (ETH on Ethereum, TRX on Tron) is the Balances row with Currency: { Native: true }. AmountInUSD gives its value in USD.
Ethereum
query {
EVM(network: eth, dataset: combined) {
Balances(
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
Currency: { Native: true }
}
) {
Currency {
Name
Symbol
Native
}
Balance {
Address
Amount
AmountInUSD
}
}
}
}
Tron
query {
Tron(dataset: combined) {
Balances(
where: {
Balance: { Address: { is: "TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv" } }
Currency: { Native: true }
}
) {
Currency {
Name
Symbol
Native
}
Balance {
Address
Amount
AmountInUSD
}
}
}
}
For the balance of one token, replace Native: true with SmartContract: { is: "<token contract>" }. For the balance on a past date, see Balance on a Specific Date.
Latest transfers in and out
Two aliases on the Transfers cube return the latest outgoing (sent) and incoming (received) transfers of the address in one request, native coin and tokens together. Each row has the time, the transaction hash, the counterparty, the amount, its USD value and the currency. The queries read the last 3 days of the realtime dataset; for older transfers add dataset: combined and set the time window you need.
Ethereum
query {
EVM(network: eth) {
sent: Transfers(
limit: { count: 10 }
orderBy: { descending: Block_Time }
where: {
Transfer: { Sender: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
Block: { Time: { since_relative: { days_ago: 3 } } }
TransactionStatus: { Success: true }
}
) {
Block {
Time
}
Transaction {
Hash
}
Transfer {
Receiver
Amount
AmountInUSD
Currency {
Symbol
SmartContract
}
}
}
received: Transfers(
limit: { count: 10 }
orderBy: { descending: Block_Time }
where: {
Transfer: { Receiver: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
Block: { Time: { since_relative: { days_ago: 3 } } }
TransactionStatus: { Success: true }
}
) {
Block {
Time
}
Transaction {
Hash
}
Transfer {
Sender
Amount
AmountInUSD
Currency {
Symbol
SmartContract
}
}
}
}
}
Tron
query {
Tron {
sent: Transfers(
limit: { count: 10 }
orderBy: { descending: Block_Time }
where: {
Transfer: { Sender: { is: "TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv" } }
Block: { Time: { since_relative: { days_ago: 3 } } }
TransactionStatus: { Success: true }
}
) {
Block {
Time
}
Transaction {
Hash
}
Transfer {
Receiver
Amount
AmountInUSD
Currency {
Symbol
SmartContract
}
}
}
received: Transfers(
limit: { count: 10 }
orderBy: { descending: Block_Time }
where: {
Transfer: { Receiver: { is: "TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv" } }
Block: { Time: { since_relative: { days_ago: 3 } } }
TransactionStatus: { Success: true }
}
) {
Block {
Time
}
Transaction {
Hash
}
Transfer {
Sender
Amount
AmountInUSD
Currency {
Symbol
SmartContract
}
}
}
}
}
To follow new transfers live, turn the query into a subscription and drop limit, orderBy and the time filter. More filters (one token, minimum amount, counterparty) are on the ERC20 Token Transfers API and Tron Transfers API pages.
First and last activity
Every Balances row carries FirstChangeTime and LastChangeTime: the first and the latest time that currency's balance changed at the address. Sorting the rows by them gives the address's first activity (first_activity, usually the first deposit) and its latest activity (last_activity) in one request, with the currency that moved.
Ethereum
query {
EVM(network: eth, dataset: combined) {
first_activity: Balances(
limit: { count: 1 }
orderBy: { ascending: Balance_FirstChangeTime }
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
}
) {
Currency {
Symbol
SmartContract
}
Balance {
FirstChangeTime
}
}
last_activity: Balances(
limit: { count: 1 }
orderBy: { descending: Balance_LastChangeTime }
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
}
) {
Currency {
Symbol
SmartContract
}
Balance {
LastChangeTime
}
}
}
}
Tron
query {
Tron(dataset: combined) {
first_activity: Balances(
limit: { count: 1 }
orderBy: { ascending: Balance_FirstChangeTime }
where: {
Balance: { Address: { is: "TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv" } }
}
) {
Currency {
Symbol
SmartContract
}
Balance {
FirstChangeTime
}
}
last_activity: Balances(
limit: { count: 1 }
orderBy: { descending: Balance_LastChangeTime }
where: {
Balance: { Address: { is: "TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv" } }
}
) {
Currency {
Symbol
SmartContract
}
Balance {
LastChangeTime
}
}
}
}
Add UpdateCount to Balance to see how many times each currency's balance changed at the address.
Token holdings of an address
Without a Currency filter, Balances returns one row per token the address holds. Amount(selectWhere: { gt: "0" }) drops tokens it no longer holds, and ordering by Balance_AmountInUSD puts the largest positions first.
Ethereum
query {
EVM(network: eth, dataset: combined) {
Balances(
limit: { count: 20 }
orderBy: { descending: Balance_AmountInUSD }
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
}
) {
Currency {
Name
Symbol
SmartContract
Native
}
Balance {
Amount(selectWhere: { gt: "0" })
AmountInUSD
}
}
}
}
Tron
query {
Tron(dataset: combined) {
Balances(
limit: { count: 20 }
orderBy: { descending: Balance_AmountInUSD }
where: {
Balance: { Address: { is: "TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv" } }
}
) {
Currency {
Name
Symbol
SmartContract
Native
}
Balance {
Amount(selectWhere: { gt: "0" })
AmountInUSD
}
}
}
}
Anyone can send a token to any address, so a wallet's holdings often include airdropped spam tokens with a USD value. Check the SmartContract of a token before you trust its symbol. For NFT holdings, add Currency: { Fungible: false } (see NFTs Tracking Across Chains).
Look up one address on several EVM chains
An EVM address is the same on every EVM chain, so one request with GraphQL aliases looks it up on Ethereum, BSC, Base and Arbitrum at once. This query returns the native coin balance and the time it last changed on each chain.
query {
ethereum: EVM(network: eth, dataset: combined) {
Balances(
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
Currency: { Native: true }
}
) {
Currency {
Symbol
}
Balance {
Amount
AmountInUSD
LastChangeTime
}
}
}
bsc: EVM(network: bsc, dataset: combined) {
Balances(
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
Currency: { Native: true }
}
) {
Currency {
Symbol
}
Balance {
Amount
AmountInUSD
LastChangeTime
}
}
}
base: EVM(network: base, dataset: combined) {
Balances(
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
Currency: { Native: true }
}
) {
Currency {
Symbol
}
Balance {
Amount
AmountInUSD
LastChangeTime
}
}
}
arbitrum: EVM(network: arbitrum, dataset: combined) {
Balances(
where: {
Balance: { Address: { is: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045" } }
Currency: { Native: true }
}
) {
Currency {
Symbol
}
Balance {
Amount
AmountInUSD
LastChangeTime
}
}
}
}
Address pages for other chains
Each chain has its own page with more address queries (balance history, balance on a date, balance updates, transfers):
| Chain | Balance and holdings | Transfers |
|---|---|---|
| Ethereum | Ethereum Balance API | ERC20 Token Transfers API |
| BSC | BSC Balance API | BSC Transfers API |
| Base | Base Address Balance API | Base Transfers API |
| Solana | Solana Balances and Balance Updates API | Solana Transfers API |
| Tron | Tron Address Balance API | Tron Transfers API |
| Bitcoin | Bitcoin Address API | Bitcoin Address API |
Solana has no Balances cube: its balances come from Solana.BalanceUpdates, shown on the Solana page.
Look up an address in plain English with the MCP
The Bitquery MCP server lets an AI client such as Claude, ChatGPT or Cursor answer "who is this address and what has it done" without writing a query. Three groups of tools do the address lookup:
| Tool | What it answers | Inputs |
|---|---|---|
labels_for_addresses | Who owns a list of addresses: exchange deposit or hot wallet, mixer, scam, sanctioned entity and other labels | addresses (required; separated by commas, pipes, spaces or new lines), chain (leave empty to search every chain), label_type, limit (default 200, up to 10000) |
address_labels | Every label of one address, wallet or token contract | address (required), chain (leave empty to search every chain) |
address_risk_report | An AML risk score from 0 to 100 for a Tron, Bitcoin or Ethereum address, with the labelled entities it received from and sent to and its exposure by entity type | chain and address (required), asset, after_time, before_time, direction (both, received, sent), view (all or direct), max_hops (1 to 6, default 2), min_amount_usd (default 100), weights, format (markdown or json) |
<chain>_address_profile | Transfer counts in and out, distinct senders and receivers, and first and last activity of one address | See the table below |
labels_for_addresses returns one row per labelled address with Labels (each written as chain/label_type:label_value), Label_Types, Sources, Source_Count and Status. An address that is missing from the answer has no label; when none of the addresses has one, the answer is a single row with Status NO_LABELS_FOUND. address_risk_report adds a band to the score (none at 0, low below 25, medium 25 to 49, elevated 50 to 74, high 75 and up). Its view: all traces funds up to max_hops hops on Tron; on Bitcoin and Ethereum the report is the direct view.
The address profile tools by chain
The address profile tools share the address and format (rows or columnar) inputs and differ in the period they cover and the filters they take:
| Tools | Chains | Period | Filters | Returns |
|---|---|---|---|---|
eth_address_profile, bsc_address_profile, base_address_profile, arbitrum_address_profile, optimism_address_profile, matic_address_profile, robinhood_address_profile | Ethereum, BSC, Base, Arbitrum, Optimism, Polygon, Robinhood Chain | Whole history, or after_time / before_time | contract or currency (one token), include_internal (0 by default; 1 also counts native coin moved by contract code inside a transaction) | Sent_Transfers, Received_Transfers, Distinct_Receivers, Distinct_Senders, First_Sent, Last_Sent, First_Received, Last_Received; Sent_Amount and Received_Amount when one token is set |
arc_address_profile | Arc | Whole history, or after_time / before_time | contract, currency, asset_type (all, native, token, usdc), include_internal (1 by default) | Same as the EVM tools, plus Sent_Assets and Received_Assets |
tron_address_profile | Tron | Whole history, or after_time / before_time | contract or currency | Same as the EVM tools |
solana_address_profile | Solana | Last days days (default 90, up to 20000) | None | Window_Days, Window_From, Sent_Transfers, Received_Transfers, Distinct_Receivers, Distinct_Senders |
xrp_address_profile | XRP Ledger | Last days days (default 90, up to 20000) | None | Payments sent and received, distinct receivers and senders, destination tags, other value records, filled offers, transactions signed, fees paid in XRP, first and last activity |
xlm_address_profile | Stellar | Last days days (default 90, up to 20000) | None | Payments sent and received, distinct receivers and senders, accounts created, claimable balances, filled offers, transactions signed, fees paid in XLM, first and last activity, Created_By |
btc_address_profile, bch_address_profile, ltc_address_profile, doge_address_profile, dash_address_profile, zec_address_profile | Bitcoin, Bitcoin Cash, Litecoin, Dogecoin, Dash, Zcash (transparent addresses) | Whole history | None | Total received and sent in the chain's coin (received minus sent is the balance), distinct senders and receivers, receiving and spending counts, first and last activity |
ada_address_profile | Cardano | Whole history | currency (ADA by default; empty lists every asset), limit (default 20, up to 500) | One row per asset: received, sent and current balance, output and transaction counts, first and last activity, address type, Is_Script, Stake_Key, distinct senders and receivers |
Example prompts:
- "Look up
0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045: first and last activity on Ethereum, and who it sends to." - "Who owns these Tron addresses?
TLaGjwhvA8XQYSxFAcAXy7Dvuue9eGYitv,TU4vEruvZwLLkSfV9bNw12EJTPvNr7Pvaa" - "Give me a risk report for this Tron address."
More on these tools: Counterparties, Holders and balances, Tracing MCP and Solana MCP.
Frequently Asked Questions
What is a blockchain address lookup?
A blockchain address lookup reads the public on-chain record of one wallet or contract address: its current balance, the tokens it holds, the transfers it sent and received, and when it was first and last active. With Bitquery you get all of it from one GraphQL API, for one address or many, on many chains, without running a node.
Can you look up an address without knowing the chain?
Mostly, yes. The address format narrows it down: 0x followed by 40 hex characters is an EVM address, T followed by 33 characters is Tron, 1, 3 or bc1 is Bitcoin, and a 32 to 44 character base58 string is usually Solana. An EVM address is the same on every EVM chain, so one GraphQL request with aliases can check Ethereum, BSC, Base and Arbitrum at once, as in the multi-chain query on this page. On the MCP, labels_for_addresses and address_labels search every chain when chain is left empty.
Is the address lookup API free?
Yes, with a free trial on real-time data. The archive and combined datasets, which the balance, activity and holdings queries on this page use, are part of the paid plans. Queries are billed in points, and the points per call depend on how much data the query reads. See How Billing Works for the current plans, trial limits and points.
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.