> Solana Developer Platform docs, served as Markdown. The [docs index](https://platform-beta.solana.com/docs.md) lists every page and [llms.txt](https://platform-beta.solana.com/docs/ai/llms.txt) the key ones; [SKILL.md](https://platform-beta.solana.com/SKILL.md) has the rules for building on SDP.

# Wallet balances

Per-wallet token balances with optional USD valuation via SDP.

`GET /v1/payments/wallets/{walletId}/balances` returns a custody wallet's native **SOL** balance and every **SPL token** it holds, with raw and human-readable amounts, decimals, and a USD valuation where SDP has a price. SOL always comes first, as `token: "SOL"` with `mint: "So11111111111111111111111111111111111111112"`. Token accounts with a zero balance are left out.

## Request

`walletId` is the provider wallet ID: the `walletId` field from `GET /v1/wallets`, not the wallet's `id` (`cwlt_…`) or its address. The request needs an API key with `wallets.read`; a key limited to selected wallets reads only those.

**curl**

```bash
curl 'https://api.solana.com/v1/payments/wallets/privy_wallet_123/balances' \
  -H "Authorization: Bearer $SDP_API_KEY"
```

**TypeScript**

```typescript
const res = await fetch("https://api.solana.com/v1/payments/wallets/privy_wallet_123/balances", {
  method: "GET",
  headers: {
    Authorization: `Bearer ${process.env.SDP_API_KEY}`
  }
});
```

**Java**

```java title="GetWalletBalances.java"
HttpRequest request = HttpRequest.newBuilder()
    .uri(URI.create("https://api.solana.com/v1/payments/wallets/privy_wallet_123/balances"))
    .header("Authorization", "Bearer sf_...")
    .GET()
    .build();
```

If SDP can't read the SOL balance or any token balance, the request returns `503` instead of partial or zero balances. To read state no older than a slot you already saw, pass `minimumSlot`; the response echoes it in `data.balanceReadContext.minimumSlot`.

## Response shape

The payload sits in the standard `data` / `meta` envelope, with the balances in `data.walletBalances.balances`:

```json title="response.json"
{
  "data": {
    "walletBalances": {
      "walletId": "privy_wallet_123",
      "address": "3xYZa...2aBc",
      "balances": [
        {
          "token": "SOL",
          "mint": "So11111111111111111111111111111111111111112",
          "amount": "2500000000",
          "uiAmount": "2.5",
          "decimals": 9
        },
        {
          "token": "USDC",
          "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "amount": "1500000000",
          "uiAmount": "1500",
          "decimals": 6,
          "usdPrice": 1,
          "usdValue": 1500
        }
      ]
    }
  },
  "meta": { "requestId": "req_...", "timestamp": "2026-05-18T00:00:00.000Z" }
}
```

Per-balance fields:

| Field | Notes |
| --- | --- |
| `token` | Token symbol if known, otherwise the onchain mint. |
| `mint` | Onchain mint address. |
| `amount` | Raw amount in the smallest unit (a string, to preserve precision). |
| `uiAmount` | Human-readable decimal string: `amount / 10^decimals`. |
| `decimals` | The token's decimal count. |
| `usdPrice` | Per-token USD price; omitted when no price is available. |
| `usdValue` | Total USD value (`usdPrice * uiAmount`); omitted when no price is available. |
| `confidential` | Reserved for confidential transfer balances; absent for standard balances. |

## Use cases

- **Account dashboards:** show a custody wallet's contents to its operator.
- **Pre-transfer balance checks:** confirm a wallet holds enough of a token before you start a payout batch.
- **Treasury accounting:** take periodic snapshots into an internal ledger.

## Pricing freshness

SDP prices balances only on mainnet. In a sandbox project on devnet, `usdPrice` and `usdValue` are always absent.

`usdPrice` is a display estimate from Tokens.xyz. SDP caches each price for up to 60 seconds. Some source snapshots refresh hourly; SDP omits snapshots older than two hours or without a timestamp. The snapshot timestamp doesn't prove when its underlying price was observed.

Use an executable quote for a trade and an independently verified valuation for accounting. The onchain `amount` and `uiAmount` remain the balance values. When pricing is unavailable, `usdPrice` and `usdValue` are absent: the omission means "unknown," not "$0.00."

## Compared with onchain RPC

You can also list SPL token balances by calling `getTokenAccountsByOwner` on a Solana RPC node and decoding the token-account data. Use SDP's balances endpoint for:

- **Token resolution:** SDP resolves the mint to a symbol when it knows one; raw RPC returns mints only.
- **USD pricing:** RPC has no prices.
- **One fewer dependency:** no separate RPC integration when you already call SDP.

Go to RPC directly for:

- **State at an exact slot:** for an audit that needs the wallet as of one slot. SDP's `minimumSlot` sets only a lower bound.
- **Confidential transfer balances:** full extension support is RPC-side.
- **Latency-sensitive paths:** RPC is one hop closer to the cluster.

## Related

- [Payouts and disbursements](/docs/payments/send-payouts): check balances before running a batch.
- [Create a wallet](/docs/guides/setup-wallets): provision the wallets whose balances this endpoint reports.
