getProgramAccountsV2 — Solana JSON-RPC
Paginated variant of getProgramAccounts: lists the accounts owned by a program page by page, using limit and a paginationKey cursor.
https://triport.io/sol- Network
- Solana
- Scope
- sol_read_rpc_heavy
- Auth
- x-token: $TRIPORT_API_KEY (or Authorization: Bearer)
- Rate limit
- free+ — 2 rps (free) / 5 rps (basic) / 20 rps (pro) / 80 rps (business), with burst
Endpoint and plans: Solana RPC endpoint.
getProgramAccountsV2 is the paginated form of
getProgramAccounts: it returns the accounts owned
by a given program Pubkey, with the same filtering and encoding controls, but
one page at a time. Pass limit to size the page; each response carries a
paginationKey that you send back to get the next page. That makes it the
method to use when a program owns more accounts than fit comfortably in one
response.
Like its predecessor, this is one of the two heavy Solana read methods
(sol_read_rpc_heavy). Scanning all accounts owned by a program is expensive
for the node, so it is throttled far more aggressively than ordinary reads —
just 2 rps on the Free trial, rising to 80 rps on business. Budget your
calls accordingly, cache results where you can, and always narrow the scan with
filters (a dataSize and/or memcmp filter) rather than fetching every
account a program owns.
Parameters
Positional params array: [programId, config?]. The config object takes
the getProgramAccounts options and adds two V2 fields, limit and
paginationKey.
programIdstring (base-58 Pubkey)required^[1-9A-HJ-NP-Za-km-z]{32,44}$.configobjectoptionalconfig (GetProgramAccountsConfig)objectencodingstringoptionalbase58, base64, base64+zstd, jsonParsed. Controls how each account's data is returned.commitmentstringoptionalprocessed, confirmed, or finalized.dataSliceobjectoptional{ "offset": <integer>, "length": <integer> }. Only valid with binary encodings.filtersarrayoptionalminContextSlotintegeroptionalwithContextbooleanoptionaltrue, wraps the page in an RpcContext envelope: { context, value: { accounts, paginationKey, count } }.limitintegeroptionalpaginationKeystringoptionalpaginationKey; omit it for the first page (V2).filters entries (AccountFilter)objectdataSizeintegermemcmpobjectoffset, equals the provided bytes ({ "offset": <integer>, "bytes": <string>, "encoding": <string> }).Response
The result is one page: an accounts array, the cursor for the next page and
the number of accounts in this page. With withContext: true the same object
is returned under result.value, next to result.context.
accountsarrayProgramAccount (address plus AccountInfo).paginationKeystring | nullconfig.paginationKey. null on the last page.countintegeraccounts[].pubkeystring (base-58)accounts[].account.lamportsintegeraccounts[].account.ownerstring (base-58)programId.accounts[].account.executablebooleanaccounts[].account.rentEpochintegeru64).accounts[].account.spaceintegeraccounts[].account.dataarray | object[<data>, <encoding>]; jsonParsed returns a decoded object (or the binary tuple if no parser matched).Errors
Errors use the standard JSON-RPC envelope (error.code, error.message,
error.data).
| Code | HTTP | Meaning | When it happens |
|---|---|---|---|
-32602 | 400 | Invalid params | programId is not valid base-58, or config contains an invalid value. |
| — | 403 | Tier insufficient | API key's tier/scope does not include sol_read_rpc_heavy. Rejected before the RPC layer: plain HTTP body {"error":"tier_insufficient", …} with an X-Required-Tier header — there is no JSON-RPC error object. |
| — | 429 | Rate limit exceeded | More than your tier's sustained heavy-read RPS (with burst) was sent. Plain HTTP body {"error":"rate_limited", …} with limit_rps, burst_capacity and retry_after_sec; honour Retry-After and X-RateLimit-Reset. |
| — | 403 | Unknown method | Method name misspelled. Rejected before the RPC layer with a plain HTTP body {"error":"method_unknown", …}. |
Example rate-limit response — HTTP 429 with a plain body, not a JSON-RPC envelope (note the much lower heavy-tier limit):
{
"error": "rate_limited",
"message": "Rate limit reached: your free plan allows 2 requests/s for sol_read_rpc_heavy. Retry in 1s (see the Retry-After header) or upgrade for a higher limit at https://triport.io/app/pricing",
"current_tier": "free",
"category": "sol_read_rpc_heavy",
"limit_rps": 2,
"burst_capacity": 4,
"retry_after_sec": 1,
"upgrade_url": "https://triport.io/app/pricing",
"docs_url": "https://triport.io/errors/http-429-rate-limit"
}See the shared errors reference for the full envelope and retry guidance.
Examples
JavaScript (fetch)
// Walk every page of a filtered scan. Stay under your heavy-read RPS.
async function page(paginationKey) {
const res = await fetch("https://triport.io/sol", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TRIPORT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getProgramAccountsV2",
params: [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
{
encoding: "base64",
limit: 1000,
filters: [
{ dataSize: 165 },
{ memcmp: { offset: 0, bytes: "So11111111111111111111111111111111111111112" } },
],
...(paginationKey ? { paginationKey } : {}),
},
],
}),
});
const { result } = await res.json();
return result;
}
let key;
do {
const { accounts, paginationKey, count } = await page(key);
console.log(`${count} accounts`, accounts[0]?.pubkey);
key = paginationKey; // null on the last page
} while (key);Notes
- Beta: published schema not final. The endpoint serves V2 today and the
fields above are what it returns; the OpenRPC schema still types the result
as an open object until spec
api.2.2+. Re-check this page when that spec ships.getProgramAccountsis the stable, unpaginated contract. - Paging. Keep sending the returned
paginationKeyuntil it comes backnull— that page is the last one. Each page is a separate heavy read and counts against your RPS budget. - Heavy rate limits.
getProgramAccountsV2shares thesol_read_rpc_heavybudget withgetProgramAccounts— only 2 / 5 / 20 / 80 rps by tier. These are an order of magnitude lower than standard reads (20 / 60 / 200 / 600 rps); see rate limits and tiers. - Always filter. Use
dataSizeandmemcmpfilters to restrict the scan server-side. Unfiltered scans over large programs are slow and burn through your limited heavy-read budget quickly. - Related methods:
getProgramAccounts(the stable v1),getAccountInfo(single account), andgetMultipleAccounts(batch of known addresses).