getMultipleAccounts — Solana JSON-RPC
Returns the account information for a list of Solana public keys in a single round-trip.
https://triport.io/sol- Network
- Solana
- Scope
- sol_read_rpc
- Auth
- x-token: $TRIPORT_API_KEY (or Authorization: Bearer)
- Rate limit
- free+ — 20 rps (free) / 60 rps (basic) / 200 rps (pro) / 600 rps (business), with burst
Endpoint and plans: Solana RPC endpoint.
getMultipleAccounts fetches the current on-chain state of several accounts at
once, identified by their base-58 public keys. It is the batched counterpart of
getAccountInfo: instead of one request per account, you
pass up to 100 public keys and receive one AccountInfo entry per key, in
the same order you requested them.
Use it whenever you would otherwise loop over getAccountInfo — for example to
read a set of token accounts, several PDAs, or a basket of mints — to cut
latency and stay well within your rate limit. All accounts are read at the same
slot, so the returned values are mutually consistent.
The value array is positional and the same length as the pubkeys you sent.
Any account that does not exist comes back as a null entry at that position
(the surrounding array and context are still populated). The shape of each
account's data field depends on the encoding you request, exactly as for
getAccountInfo.
Parameters
Positional params array: [pubkeys, config?].
pubkeysarray of string (base-58 Pubkey)required^[1-9A-HJ-NP-Za-km-z]{32,44}$.configobjectoptionalconfig (GetAccountInfoConfig)objectencodingstringoptionalbase58, base64, base64+zstd, jsonParsed. Defaults to base64. base58 is limited to account data under 129 bytes.commitmentstringoptionalprocessed, confirmed, or finalized.dataSliceobjectoptional{ "offset": <integer>, "length": <integer> }. Only valid with the binary encodings.minContextSlotintegeroptionalResponse
The second entry is null because no account exists at that public key. The
value array is always the same length and order as the pubkeys you sent.
context.slotintegercontext.apiVersionstringvaluearrayvalue[i]object | nullnull if that account does not exist.value[i].lamportsintegervalue[i].ownerstring (base-58)value[i].executablebooleanvalue[i].rentEpochintegeru64).value[i].spaceintegervalue[i].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 | A pubkey is not valid base-58, more than 100 keys were sent, or config contains an invalid value (e.g. base58 encoding on data larger than 129 bytes). |
| — | 403 | Tier insufficient | API key's tier/scope does not include sol_read_rpc. 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 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. |
-32601 | 404 | Method not found | Method name misspelled or not available on this chain. |
Example rate-limit response — HTTP 429 with a plain body, not a JSON-RPC envelope:
{
"error": "rate_limited",
"message": "Rate limit reached: your free plan allows 20 requests/s for sol_read_rpc. 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",
"limit_rps": 20,
"burst_capacity": 40,
"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)
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: "getMultipleAccounts",
params: [
[
"So11111111111111111111111111111111111111112",
"4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",
],
{ encoding: "jsonParsed", commitment: "finalized" },
],
}),
});
const { result } = await res.json();
result.value.forEach((account, i) => {
if (account === null) console.log(`account ${i} does not exist`);
else console.log(account.lamports, account.owner);
});Notes
- 100-key limit: at most 100 public keys per call. Split larger sets across multiple requests and stay within your tier's RPS.
- Positional results:
valueis parallel topubkeys— indexiof the response always corresponds to indexiof the request, withnullfor any missing account. Don't assume non-null entries; check each. - Consistent snapshot: every account is read at the single
context.slot, so the batch is internally consistent — an advantage over issuing separategetAccountInfocalls. - Encoding & size:
base58only works for account data smaller than 129 bytes; usebase64orbase64+zstdfor larger accounts.dataSlice(binary encodings only) fetches just a window of each account's bytes and is ignored byjsonParsed. - Commitment: use
confirmedorprocessedto see changes sooner when you can tolerate possible rollbacks;finalizedis the safest choice for settled state. - Related methods:
getAccountInfo(single account),getBalance(lamports only), andgetProgramAccounts(all accounts owned by a program — note its much strictersol_read_rpc_heavyrate limits of 2 / 5 / 20 / 80 rps).