The Wallet API is in Beta. Endpoints and response formats may change.
Overview
The Wallet Balances endpoint retrieves all token and NFT holdings for a Solana wallet — SOL, SPL tokens, Token-2022, and NFTs — with USD pricing, logos, and metadata. Results are sorted by USD value in descending order: tokens with pricing data appear first, followed by tokens without prices.
The endpoint returns up to 100 tokens per request, so pagination is manual. Use the page parameter to fetch additional pages and read pagination.hasMore to know when more results are available. Each request is a single API call and costs 100 credits.
USD prices are sourced from DAS and update hourly, covering the top 10,000 tokens by market cap. pricePerToken and usdValue are null for unsupported tokens. Prices are estimates, not real-time market rates.
When to use this
Use the Wallet Balances API when you need to:
Display portfolio holdings : show users their complete token and NFT holdings.
Calculate USD values : get portfolio valuations with hourly-updated pricing.
Build wallet UIs : power wallet dashboards and asset lists.
Track token holdings : monitor specific token balances across wallets.
Portfolio analytics : analyze holdings distribution and concentration.
Tax reporting : generate holdings snapshots for tax purposes.
Quickstart
Basic balance query
Get all token balances for a wallet with USD values:
const getWalletBalances = async ( address ) => {
const url = `https://api.helius.xyz/v1/wallet/ ${ address } /balances?api-key=YOUR_API_KEY` ;
const response = await fetch ( url );
if ( ! response . ok ) {
throw new Error ( `HTTP error! status: ${ response . status } ` );
}
const data = await response . json ();
const solBalance = data . balances [ 0 ]; // SOL is always first when showNative=true
console . log ( `SOL Balance: ${ solBalance . balance } SOL ($ ${ solBalance . usdValue } )` );
console . log ( `Page ${ data . pagination . page } Total Value: $ ${ data . totalUsdValue } ` );
console . log ( `Token Count (this page): ${ data . balances . length } ` );
// Display top holdings
data . balances . slice ( 0 , 5 ). forEach ( token => {
console . log ( ` ${ token . symbol } : ${ token . balance } ($ ${ token . usdValue || 'N/A' } )` );
});
return data ;
};
getWalletBalances ( "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" );
import requests
def get_wallet_balances ( address : str ):
url = f "https://api.helius.xyz/v1/wallet/ { address } /balances"
headers = { "X-Api-Key" : "YOUR_API_KEY" }
response = requests.get(url, headers = headers)
response.raise_for_status()
data = response.json()
sol_balance = data[ 'balances' ][ 0 ] # SOL is always first when showNative=true
print ( f "SOL Balance: { sol_balance[ 'balance' ] } SOL ($ { sol_balance[ 'usdValue' ] } )" )
print ( f "Page { data[ 'pagination' ][ 'page' ] } Total Value: $ { data[ 'totalUsdValue' ] } " )
print ( f "Token Count (this page): { len (data[ 'balances' ]) } " )
# Display top holdings
for token in data[ 'balances' ][: 5 ]:
usd_value = token.get( 'usdValue' , 'N/A' )
print ( f " { token[ 'symbol' ] } : { token[ 'balance' ] } ($ { usd_value } )" )
return data
get_wallet_balances( "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" )
curl "https://api.helius.xyz/v1/wallet/86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY/balances?api-key=YOUR_API_KEY"
Include NFTs in results
Get both tokens and NFTs in a single request with showNfts=true:
const getWalletWithNfts = async ( address ) => {
const url = `https://api.helius.xyz/v1/wallet/ ${ address } /balances?api-key=YOUR_API_KEY&showNfts=true` ;
const response = await fetch ( url );
const data = await response . json ();
console . log ( `Tokens: ${ data . balances . length } ` );
console . log ( `NFTs: ${ data . nfts ?. length || 0 } ` );
// Display NFTs
data . nfts ?. forEach ( nft => {
console . log ( `NFT: ${ nft . name || 'Unnamed' } ( ${ nft . collectionName || 'Unknown Collection' } )` );
});
return data ;
};
getWalletWithNfts ( "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" );
def get_wallet_with_nfts ( address : str ):
url = f "https://api.helius.xyz/v1/wallet/ { address } /balances"
params = {
"api-key" : "YOUR_API_KEY" ,
"showNfts" : "true"
}
response = requests.get(url, params = params)
response.raise_for_status()
data = response.json()
print ( f "Tokens: { len (data[ 'balances' ]) } " )
print ( f "NFTs: { len (data.get( 'nfts' , [])) } " )
# Display NFTs
for nft in data.get( 'nfts' , []):
name = nft.get( 'name' , 'Unnamed' )
collection = nft.get( 'collectionName' , 'Unknown Collection' )
print ( f "NFT: { name } ( { collection } )" )
return data
get_wallet_with_nfts( "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" )
Filter the results
Use query parameters to narrow what is returned:
// Only show tokens with non-zero balances
const url = `https://api.helius.xyz/v1/wallet/ ${ address } /balances?api-key=YOUR_API_KEY&showZeroBalance=false` ;
// Exclude native SOL from results
const url = `https://api.helius.xyz/v1/wallet/ ${ address } /balances?api-key=YOUR_API_KEY&showNative=false` ;
// Get only the top 50 tokens by value
const url = `https://api.helius.xyz/v1/wallet/ ${ address } /balances?api-key=YOUR_API_KEY&limit=50` ;
Query parameters
Parameter Type Default Description pageinteger 1 Page number for pagination (1-indexed) limitinteger 100 Maximum number of tokens per page (1-100) showZeroBalanceboolean false Include tokens with zero balance showNativeboolean true Include native SOL in results showNftsboolean false Include NFTs in results (max 100, first page only)
{
"balances" : [
{
"mint" : "So11111111111111111111111111111111111111111" ,
"symbol" : "SOL" ,
"name" : "Solana" ,
"balance" : 1.5 ,
"decimals" : 9 ,
"pricePerToken" : 145.32 ,
"usdValue" : 217.98 ,
"logoUri" : "https://raw.githubusercontent.com/solana-labs/token-list/main/assets/mainnet/So11111111111111111111111111111111111111112/logo.png" ,
"tokenProgram" : "spl-token"
},
{
"mint" : "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" ,
"symbol" : "USDC" ,
"name" : "USD Coin" ,
"balance" : 1000.5 ,
"decimals" : 6 ,
"pricePerToken" : 1.0 ,
"usdValue" : 1000.5 ,
"logoUri" : "https://example.com/usdc-logo.png" ,
"tokenProgram" : "spl-token"
}
],
"nfts" : [
{
"mint" : "7Xq8wXyXVqfBPPqVJjPDwG9zN5wCVxBYZ6z7vPYBzr6F" ,
"name" : "Degen Ape #1234" ,
"imageUri" : "https://example.com/nft.png" ,
"collectionName" : "Degen Ape Academy" ,
"collectionAddress" : "DegN1dXmU2uYa4n7U9qTh7YNYpK4u8L9qXx7XqYqJfGH" ,
"compressed" : false
}
],
"totalUsdValue" : 1218.48 ,
"pagination" : {
"page" : 1 ,
"limit" : 100 ,
"hasMore" : true
}
}
Field notes
balance : human-readable amount, already adjusted for decimals — 1.5 means 1.5 SOL and 1000.5 means 1000.5 USDC. No lamport conversion is needed. This endpoint does not expose a raw amountRaw field; if you need the exact integer value, derive it as Math.round(balance * 10 ** decimals).
decimals : provided for reference only.
pricePerToken / usdValue : null for tokens without DAS pricing data (see the pricing note above).
totalUsdValue : total USD value for the current response page only. For full-portfolio value, paginate through all pages and sum each balance’s usdValue.
tokenProgram : which token standard each token uses — spl-token (legacy SPL Token) or token-2022 (Token Extensions). Both are fully supported.
Use cases
Build a portfolio dashboard
Display user holdings with USD values:
const renderPortfolio = async ( address ) => {
const { balances , totalUsdValue } = await getWalletBalances ( address );
console . log ( `Current Page Value: $ ${ totalUsdValue . toLocaleString () } ` );
console . log ( ` \n Top Holdings:` );
// totalUsdValue is page-scoped; paginate before computing full portfolio value.
balances . slice ( 0 , 10 ). forEach (( token , i ) => {
if ( token . usdValue ) {
console . log ( ` ${ i + 1 } . ${ token . symbol } : ${ token . balance . toFixed ( 4 ) } ($ ${ token . usdValue . toFixed ( 2 ) } )` );
}
});
};
Calculate token concentration
Analyze portfolio diversification:
const analyzeConcentration = async ( address ) => {
const { balances , totalUsdValue } = await getWalletBalances ( address );
const tokensWithValue = balances . filter ( t => t . usdValue );
if ( tokensWithValue . length === 0 ) {
console . log ( 'No tokens with USD pricing data available' );
return null ;
}
const topToken = tokensWithValue [ 0 ];
const pageConcentration = ( topToken . usdValue / totalUsdValue ) * 100 ;
console . log ( `Largest Position on Current Page: ${ topToken . symbol } ( ${ pageConcentration . toFixed ( 1 ) } %)` );
if ( pageConcentration > 50 ) {
console . log ( `Warning: Current page is highly concentrated in ${ topToken . symbol } ` );
}
return { topToken , pageConcentration };
};
Track a specific token balance
Monitor a specific token across multiple wallets:
const getTokenBalance = async ( address , tokenMint ) => {
const { balances } = await getWalletBalances ( address );
const token = balances . find ( t => t . mint === tokenMint );
if ( ! token ) {
console . log ( `Token not found in wallet` );
return null ;
}
console . log ( ` ${ token . symbol } Balance: ${ token . balance } ` );
console . log ( `USD Value: $ ${ token . usdValue || 'N/A' } ` );
return token ;
};
// Example: Check USDC balance
getTokenBalance (
"86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY" ,
"EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // USDC mint
);
Export holdings for tax reporting
Generate a holdings snapshot:
const exportHoldingsSnapshot = async ( address ) => {
const { balances , totalUsdValue } = await getWalletBalances ( address );
const snapshot = {
date: new Date (). toISOString (),
address ,
pageValueUSD: totalUsdValue ,
holdings: balances
. filter ( t => t . usdValue )
. map ( t => ({
symbol: t . symbol ,
mint: t . mint ,
balance: t . balance ,
pricePerToken: t . pricePerToken ,
usdValue: t . usdValue
}))
};
console . log ( JSON . stringify ( snapshot , null , 2 ));
return snapshot ;
};
For wallets with more than 100 tokens, page through results with the page parameter and pagination.hasMore:
const getAllBalances = async ( address ) => {
let allBalances = [];
let page = 1 ;
let hasMore = true ;
while ( hasMore ) {
const url = `https://api.helius.xyz/v1/wallet/ ${ address } /balances?api-key=YOUR_API_KEY&page= ${ page } &limit=100` ;
const response = await fetch ( url );
const data = await response . json ();
allBalances = allBalances . concat ( data . balances );
hasMore = data . pagination . hasMore ;
page ++ ;
console . log ( `Fetched page ${ data . pagination . page } , total tokens so far: ${ allBalances . length } ` );
}
console . log ( `Total tokens: ${ allBalances . length } ` );
return allBalances ;
};
NFTs are returned on the first page only (up to 100), regardless of token pagination.
Best practices
Filter zero balances for a cleaner UI. Use showZeroBalance=false to hide tokens the wallet no longer holds.
Include NFTs only when needed. NFTs are excluded by default for performance; set showNfts=true only when displaying them.
Handle missing price data. Always check whether pricePerToken and usdValue are null before displaying. These are hourly estimates from DAS, not real-time market rates.
Cache responses. Balance data can be cached for several seconds to reduce API calls.
Paginate large wallets. Some wallets hold thousands of tokens; implement pagination to handle them efficiently.
Common errors
Error Code Description Solution 400 Invalid wallet address format Verify the address is a valid base58 Solana address 401 Missing or invalid API key Check your API key is included in the request 429 Rate limit exceeded Reduce request frequency or upgrade your plan
Next steps
Historical Balance Get a token or SOL balance at a past timestamp, datetime, or slot.
Wallet API Overview All Wallet API endpoints and shared conventions.
API Reference Request and response schemas for wallet balances.