The Wallet API is in Beta. Endpoints and response formats may change.
Overview
The Historical Balance endpoint answers: what was this wallet’s balance of a specific token (or native SOL) at a specific point in the past? While the Balances endpoint reports current holdings,balance-at reports holdings as of any timestamp, datetime, or slot.
It finds the single most recent transaction at or before the requested point in time that involved the wallet and the token, then reads the wallet’s post-transaction balance from that transaction. A transaction’s post-balance is the balance that held from that transaction until the next one, so “balance as of time T” is the post-balance of the last relevant transaction with a block time (or slot) at or before T. For the typical wallet, this is an exact value, not an estimate.
- Tokens (SPL / Token-2022): read from the transaction’s post token balances, summed over the wallet’s token accounts for that mint.
- Native SOL: read from the transaction’s lamport post-balances. Address native SOL with the pseudo-mint
So11111111111111111111111111111111111111111.
When to use this
Use the Historical Balance API for:- PnL calculation: determine holdings at the start and end of a period.
- Cost basis and tax lots: reconstruct balances at acquisition or disposal events.
- Dispute resolution: prove what a wallet held at a specific moment.
- Snapshot verification: check a wallet’s balance at an airdrop or governance snapshot.
- Accounting and audits: reconstruct wallet state at period boundaries.
Quickstart
Token balance at a timestamp
Get a wallet’s USDC balance at a Unix timestamp:- JavaScript
- Python
- cURL
Token balance at a datetime
Pass a human-readable datetime instead of a timestamp. Remember to URL-encode the space as%20:
Native SOL balance at a slot
For native SOL, use the pseudo-mintSo11111111111111111111111111111111111111111. Slot-based queries are exact and deterministic:
Query parameters
| Param | Required | Type | Description |
|---|---|---|---|
mint | Yes | string | Token mint address. For native SOL, use So11111111111111111111111111111111111111111. |
time | One-of | int | Unix timestamp in seconds. Balance as of this time. |
datetime | One-of | string | Datetime string, e.g. 2025-01-10 19:20:00. UTC by default. |
slot | One-of | int | Slot number. Balance as of this slot. Exact and deterministic. |
time, datetime, or slot must be provided. Providing zero or more than one returns a 400 error.
Datetime formats
Accepted formats:- Date only:
2025-01-10→ UTC midnight - Date + time:
2025-01-10 19:20:00or2025-01-10T19:20:00(seconds optional) → UTC - With explicit timezone:
2025-01-10T19:20:00Z,2025-01-10T19:20:00+02:00,2025-01-10T19:20:00-05:00→ honored as given
01/10/2025, 2025-13-10, 2025-02-30) return a 400 error.
Response format
Field notes
wallet: echo of the queried wallet address.mint: echo of the queried mint (the SOL pseudo-mint when native).isNative:truewhen the result is native SOL.balance: human-readable amount as a decimal string — a string, not a number, so large balances don’t lose precision. Trailing zeros are trimmed ("1.5", not"1.500000").balanceRaw: exact amount in the smallest unit (lamports for SOL), as a string.decimals: token decimals (9 for SOL).requested: echo of the query. Whendatetimeis used,timeis also populated with the resolved epoch seconds, making the UTC interpretation visible.asOf: the transaction the balance was read from (slot,blockTime,signature).
asOf: null means zero, not an error. When the wallet had no matching transaction at or before the requested point in time, the endpoint returns 200 with balance: "0" and asOf: null — the wallet simply had not held the token by then.
Use cases
Balance change over a period
Compare holdings at two points in time:Snapshot eligibility check
Verify a wallet held a token at a snapshot slot:Best practices
- Use
slotfor deterministic results.timeanddatetimeresolve via validator-reported block times, which can drift by a few seconds. When exact reproducibility matters (snapshots, audits), query byslot. - Parse balances as strings.
balanceandbalanceRaware strings to preserve precision. UseBigInt(balanceRaw)(or your language’s arbitrary-precision integers) for arithmetic — don’t cast to a float. - Treat
asOf: nullas zero. AnullasOfis a successful response meaning the wallet had no activity for that token by the requested point. Don’t handle it as an error. - Cache historical results. A balance at a past point in time never changes. Cache results permanently to avoid repeated API calls.
Common errors
| Error Code | Description | Solution |
|---|---|---|
| 400 | Missing mint, invalid mint, zero or multiple of time/datetime/slot, or unparseable datetime | Provide a valid mint and exactly one point-in-time parameter |
| 401 | Missing or invalid API key | Check your API key is included in the request |
| 404 | Invalid wallet address in the path | Verify the address is a valid base58 Solana address |
| 429 | Rate limit exceeded | Reduce request frequency or upgrade your plan |
| 502 | Upstream RPC error or timeout | Retry with exponential backoff |
Limitations
- Multi-token-account wallets may undercount. The balance is read from the single most recent matching transaction. The common case — one associated token account per mint — is exact. A wallet holding the same mint across multiple token accounts, where the latest transaction touched only some of them, can be undercounted.
- Native SOL precision for very large balances. For SOL balances beyond ~9,007,199 SOL (2⁵³ lamports), precision may be lost upstream. Token amounts are not affected.
time/datetimeprecision depends on validator-reported block times, which can drift a few seconds. Useslotfor exact, deterministic results.- Single token per request. There is no multi-mint or “all balances at time T” batch form.
Next steps
Wallet Balances
Get a wallet’s current token and NFT holdings with USD values.
Wallet API Overview
All Wallet API endpoints and shared conventions.
API Reference
Request and response schemas for historical balance.