getProgramAccounts
https://api.triport.ioReturns all accounts owned by a given Solana program, optionally narrowed by data-size and memcmp filters.
getProgramAccounts returns every account whose owner is the supplied
programId. It is the canonical way to enumerate program state — for example,
all token accounts of a mint, all open orders on a market, or all PDAs created
by your own program.
This is a heavy method (sol_read_rpc_heavy category) and is rate-limited
far more strictly than standard read RPC: just 2 rps on the free tier, up to
80 rps on business. A single unfiltered call can scan a very large account set,
so always narrow the result with filters (a memcmp byte match and/or a
dataSize match) and request only the bytes you need with dataSlice. Treat
this method as expensive and cache its results where you can.
By default the result is a plain array of ProgramAccount objects. Set
withContext: true to wrap the array in an RpcContext envelope ({ context, value }), which is useful when you need the slot the result was evaluated at.
Parameters
JSON-RPC params is a positional array: [programId, config?].
programIdstring (base-58 Pubkey)required^[1-9A-HJ-NP-Za-km-z]{32,44}$.configobjectoptionalconfig (GetProgramAccountsConfig)objectencodingstringoptionalbase58, base64, base64+zstd, or jsonParsed.commitmentstringoptionalprocessed, confirmed, or finalized.dataSliceobjectoptional{ "offset": <integer>, "length": <integer> }. Only valid with binary encodings.filtersarrayoptionaldataSize filter or a memcmp filter (see below).minContextSlotintegeroptionalwithContextbooleanoptionaltrue, wraps the result array in an RpcContext envelope ({ context, value }). Defaults to false.filters entries (AccountFilter)objectdataSizeintegermemcmpobjectResponse
With withContext: true, the array is wrapped in an envelope:
{
"jsonrpc": "2.0",
"id": 1,
"result": {
"context": { "slot": 348392041, "apiVersion": "2.0.18" },
"value": [
{ "pubkey": "Cx...", "account": { "lamports": 2039280, "owner": "Tok...", "executable": false, "rentEpoch": 18446744073709551615, "space": 165, "data": ["...", "base64"] } }
]
}
}pubkeystring (base-58)accountobjectAccountInfo).account.lamportsintegeraccount.ownerstring (base-58)programId.account.executablebooleanaccount.rentEpochintegeru64).account.spaceintegeraccount.dataarray | object[<data>, <encoding>]. For jsonParsed: 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/filters contain an invalid value (e.g. base58 encoding on oversized data, malformed memcmp). |
-32002 | 403 | Tier insufficient | API key's tier/scope does not include sol_read_rpc_heavy. |
-32003 | 429 | Rate limit exceeded | More than your tier's sustained RPS for sol_read_rpc_heavy (2 / 5 / 20 / 80, with burst) was sent. Honour the Retry-After header. |
-32601 | 404 | Method not found | Method name misspelled or not available on this chain. |
Example rate-limit envelope:
{
"jsonrpc": "2.0",
"id": 1,
"error": {
"code": -32003,
"message": "Rate limit exceeded: 2 RPS sustained on sol_read_rpc_heavy (free tier)",
"data": {
"current_tier": "free",
"category": "sol_read_rpc_heavy",
"limit_rps": 2,
"burst_capacity": 4,
"retry_after_sec": 1
}
}
}See the shared errors reference for the full envelope and retry guidance.
Examples
JavaScript (fetch)
const res = await fetch("https://api.triport.io", {
method: "POST",
headers: {
"Authorization": `Bearer ${process.env.TRIPORT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
jsonrpc: "2.0",
id: 1,
method: "getProgramAccounts",
params: [
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
{
encoding: "base64",
commitment: "finalized",
filters: [{ dataSize: 165 }],
},
],
}),
});
const { result } = await res.json();
console.log(`${result.length} accounts owned by the program`);TypeScript SDK (@triport/sdk)
import { Triport } from "@triport/sdk";
const client = new Triport({ apiKey: process.env.TRIPORT_API_KEY! });
const accounts = await client.sol.getProgramAccounts(
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
{
encoding: "base64",
commitment: "finalized",
filters: [
{ dataSize: 165 },
{ memcmp: { offset: 0, bytes: "So11111111111111111111111111111111111111112", encoding: "base58" } },
],
},
);
for (const { pubkey, account } of accounts) {
console.log(pubkey, account.lamports);
}Python (triport-sdk)
import os
from triport import Triport
client = Triport(api_key=os.environ["TRIPORT_API_KEY"])
accounts = client.sol.get_program_accounts(
"TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA",
encoding="base64",
commitment="finalized",
filters=[
{"dataSize": 165},
{"memcmp": {"offset": 0, "bytes": "So11111111111111111111111111111111111111112", "encoding": "base58"}},
],
)
print(f"{len(accounts)} accounts owned by the program")Notes
- Always filter. An unfiltered query can scan a huge account set and is the
fastest way to exhaust your tier's RPS. Combine a
dataSizefilter (match the exact account layout size) with one or morememcmpfilters (match a discriminator or owner field) to return only what you need. - Trim the payload with
dataSlice. If you only read a few fields, request a byte window instead of full account data.dataSliceis ignored byjsonParsed. - Heavy rate limits. This method sits in
sol_read_rpc_heavy(2 / 5 / 20 / 80 rps), an order of magnitude below standard read RPC. Cache results and back off on-32003using theRetry-Afterheader. - Pagination. This method returns the full matching set in one response and
has no cursor. For large, paginated enumeration use
getProgramAccountsV2(see the method catalog) once its full schema is published. - Related methods:
getAccountInfo(a single account by key) andgetBalance(lamports only).