Historical account state is in Beta. Parameters, pricing, response formats, and data coverage may change.
What is historical account state?
Standard Solana RPC methods likegetAccountInfo and getTokenAccountsByOwner return an account’s current state only. Validators keep just the latest version of each account, so every write replaces the one before it. Transaction history doesn’t fill the gap: getTransaction and getBlock return instructions, logs, and balance changes, not the account data a program wrote.
Helius’s historical account methods return accounts as they were at a past slot, or immediately after a specific transaction within that slot. Because you can read state between two transactions in the same slot, you can see exactly what one transaction changed, even when an account is written many times in a single slot. Use them to:
- Check a wallet’s token balances at a point in time, for audits, accounting, or tax reporting
- Debug a transaction by reading the accounts it touched right before and right after it executed
- Read a protocol’s accounts, such as pools, vaults, or oracles, at a past slot without replaying the ledger yourself
Which method should I use?
Both take the same three parameters: an address, a query object that selects the position in history, and a configuration object.
Availability and pricing
- Plans: Business plans and above.
- Cost: 0 credits per call during beta (pricing subject to change).
- Rate limits:
getHistoricalAccountInfoallows 100 requests per second, with a maximum burst of 100.getHistoricalTokenAccountsByOwnerallows 10 requests per second, with a maximum burst of 10. These limits are separate from your plan’s RPC rate limit, and requests over them return HTTP429. See rate limits. - Network: Mainnet only. Call them on the standard mainnet endpoint,
https://mainnet.helius-rpc.com, or the Gatekeeper endpoint,https://beta.helius-rpc.com. Devnet returns error-32601.
Data coverage
History is available from slot 444,959,999 (September 7, 2026) onward. That’s the last slot of epoch 1029, so it holds the state at the start of epoch 1030. Requests for earlier slots return error-32018 (“Account history not available”).
Choose a position in history
The second parameter is a query object with two optional fields,slot and transactionIndex:
transactionIndex requires slot.
Non-transaction writes, such as epoch rewards, are applied at the end of the slot. A query with transactionIndex never includes them, even for the last transaction in the slot. To include them, query the slot with no transactionIndex.
Read state before and after a transaction
To inspect what a transaction changed, read the account twice:- After the transaction: query its own
slotandtransactionIndex. - Before the transaction: query the same
slotwithtransactionIndexminus 1. If the transaction is the first in its slot (index 0), query the previous slot with notransactionIndex.
getTransactionsForAddress returns slot and transactionIndex for every transaction, so you can find a transaction’s position there and pass it straight to these methods.
Understand lastUpdatedAt
Every returned account includeslastUpdatedAt, the position of the write that produced the state you received:
slotandtransactionIndexpoint to the last write at or before the position you queried. In the example above, a query for slot 445,000,000 returned state last written by the transaction at index 700 in slot 444,999,837.transactionIndex: nullmeans the write happened outside a transaction, such as epoch rewards.slot: 444959999withtransactionIndex: nullmeans the account hasn’t changed since history coverage began. It doesn’t mean the account was written in that slot.
What a null value means
value is null when the account didn’t exist at the position you queried. Either it hadn’t been created yet, or it had been closed.
- A
nullresponse has nolastUpdatedAt, so it doesn’t tell you when the account was created or closed. To find those transactions, usegetTransactionsForAddress. - An address that never existed also returns
null, not an error. - A slot before history coverage returns error
-32018for every address, whether or not the account existed.
Walk back through account history
UselastUpdatedAt as a cursor to list every state an account has had, newest first. After each read, query the position just before the write you received:
Stop when
value is null, which means the write you just stepped past created the account. Also stop when lastUpdatedAt.slot reaches 444,959,999, the start of history coverage.
- Accounts that are closed now return
nullat the latest slot. Pass astartposition from when the account still existed. - Non-transaction writes step to the previous slot. If the same account was also written by a transaction earlier in that slot, the walk skips that state.
- To walk forward in time, list the account’s transactions oldest first with
getTransactionsForAddressandsortOrder: "asc". Then read the state at each transaction’sslotandtransactionIndex.
Response context
context.slot in every response is the latest slot Helius had indexed when it served the request. It isn’t the slot you queried. Use the slot in your request, or lastUpdatedAt, to reason about the data you received.
Paginate consistently
getHistoricalTokenAccountsByOwner returns results one page at a time. Each response includes value.accounts and value.paginationKey.
- Pass
paginationKeyback in the configuration object to fetch the next page. - Stop only when
paginationKeyisnull. A page can be short, or empty, and still have more results behind it. - Pin
slotacross every page. If you omitslot, each page reads the latest indexed slot, and your pages can come from different points in time. - Set
limitbetween 1 and 5,000. It defaults to 5,000.
Encodings and parsed data
- Supported encodings are
base64(the default),base64+zstd, andjsonParsed.base58andbinaryaren’t supported. jsonParsedtoken accounts use the mint’s decimals as of the queried position, so amounts are correct even if the mint has since changed. If the mint can’t be read at that position, the account falls back to base64.dataSliceworks the same way as ingetAccountInfo.
Commitment
commitment accepts finalized (the default) and confirmed. processed isn’t supported. A slot newer than the requested commitment allows returns error -32004.
Errors
Frequently asked questions
How do I get a Solana account’s state at a specific slot?
CallgetHistoricalAccountInfo with the address and { "slot": S }. It returns the account as it was at the end of slot S, in the same format as getAccountInfo.
Can I read an account between two transactions in the same slot?
Yes. AddtransactionIndex to the query to get the account’s state immediately after that transaction executed. See Read state before and after a transaction.
How far back can I query?
History starts at slot 444,959,999, on September 7, 2026. Earlier slots return error-32018.
Which plans include historical account methods?
Business plans and above. Calls cost 0 credits during the beta period; prices are subject to change. The methods are available on mainnet only.What are the rate limits?
getHistoricalAccountInfo allows 100 requests per second, and getHistoricalTokenAccountsByOwner allows 10 requests per second. Both limits are separate from your plan’s RPC rate limit. See Availability and pricing.
How do I get every past state of an account?
Step backward from one write to the previous one usinglastUpdatedAt. See Walk back through account history.
Do I need a new SDK?
No. These are JSON-RPC methods, so any HTTP client works. Standard Solana client libraries don’t include them, so send the request directly, as in the examples above.Next steps
getHistoricalAccountInfo
Read a single account at a past slot or transaction
getHistoricalTokenAccountsByOwner
List a wallet’s token accounts at a past slot
getTransactionsForAddress
Find the slot and transactionIndex of the transactions you want to inspect
Historical data overview
Transaction history, transfers, and other archival methods