Wallet balances
Per-wallet token balances with optional USD valuation via SDP.
GET /v1/payments/wallets/{walletId}/balances returns the wallet's native SOL balance plus every SPL token balance held by a custody wallet — raw amount, human-readable amount, decimals, and optional USD valuation when a price source is configured. SOL is always prepended as the first entry and is represented with token: "SOL" and mint: "So11111111111111111111111111111111111111112".
Request
curl https://api.solana.com/v1/payments/wallets/wal_abc123/balances \
-H "Authorization: Bearer sk_test_..."const response = await fetch(
"https://api.solana.com/v1/payments/wallets/wal_abc123/balances",
{ headers: { Authorization: "Bearer sk_test_..." } }
);
const { data } = await response.json();
// data.walletBalances.balances: TokenBalance[]HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.solana.com/v1/payments/wallets/wal_abc123/balances"))
.header("Authorization", "Bearer sk_test_...")
.GET()
.build();Response shape
The payload is wrapped in the standard data / meta envelope, with the balances under a walletBalances key:
{
"data": {
"walletBalances": {
"walletId": "wal_abc123",
"address": "3xYZa...2aBc",
"balances": [
{
"token": "SOL",
"mint": "So11111111111111111111111111111111111111112",
"amount": "2500000000",
"uiAmount": "2.5",
"decimals": 9
},
{
"token": "USDC",
"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": "1500000000",
"uiAmount": "1500.00",
"decimals": 6,
"usdPrice": 1.0,
"usdValue": 1500.0
}
]
}
},
"meta": { "requestId": "req_...", "timestamp": "2026-05-18T00:00:00.000Z" }
}Per-balance fields:
| Field | Notes |
|---|---|
token | Token symbol if known, otherwise the on-chain mint. |
mint | On-chain mint address. |
amount | Raw amount in the smallest unit (string to preserve precision). |
uiAmount | Human-readable decimal string — amount / 10^decimals. |
decimals | Token's decimal count. |
usdPrice | Per-token USD price; omitted when no pricing data is available. |
usdValue | Total USD value (= usdPrice * uiAmount); omitted when pricing is unavailable. |
confidential | Reserved for confidential transfer balances; absent for standard balances. |
Use cases
- Account dashboards — display the contents of a custody wallet to its operator.
- Pre-transfer balance checks — validate that a wallet has enough of a specific token before kicking off a payout batch.
- Treasury accounting — periodic snapshots into an internal ledger.
Pricing freshness
When USD valuation is populated, the price comes from SDP's configured price source and reflects the most recent quote available. The cadence and source depend on deployment configuration — do not rely on usdValue for downstream balance-sheet decisions without confirming the price source's freshness with your operations team. When in doubt, treat amount / uiAmount as authoritative and convert with your own price feed.
If no price source is configured, the usdPrice and usdValue fields are simply absent rather than zero — falling back to "I don't know" rather than "$0.00" so downstream consumers can decide how to handle the gap.
Comparison to on-chain RPC
You can also enumerate SPL token balances by calling getTokenAccountsByOwner against a Solana RPC and decoding the returned token-account data. Reasons to use SDP's balances endpoint instead:
- Token resolution — SDP resolves the mint to a symbol when it knows one; raw RPC returns mints only.
- USD pricing — RPC has no concept of price.
- No RPC dependency in your stack — one fewer external integration when you are already calling SDP.
Reasons to skip SDP and go to RPC directly:
- Cluster-of-truth — you want the wallet's state at a specific slot for an audit.
- Confidential transfer balances — full extension support is RPC-side.
- Latency-sensitive paths — RPC is one hop closer to the cluster.
Related
- Wallet policies — set transfer caps based on balance bounds.
- Payouts and disbursements — balance-check before running a batch.
- Set Up Wallets — provision the wallets whose balances this endpoint reports.