getMultipleAccounts
https://api.triport.ioReturns the account information for a list of Solana public keys in a single round-trip.
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). |
-32002 | 403 | Tier insufficient | API key's tier/scope does not include sol_read_rpc. |
-32003 | 429 | Rate limit exceeded | More than your tier's sustained RPS (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: 20 RPS sustained on sol_read_rpc (free tier)",
"data": {
"current_tier": "free",
"category": "sol_read_rpc",
"limit_rps": 20,
"burst_capacity": 40,
"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: "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);
});TypeScript SDK (@triport/sdk)
import { Triport } from "@triport/sdk";
const client = new Triport({ apiKey: process.env.TRIPORT_API_KEY! });
const { context, value } = await client.sol.getMultipleAccounts(
[
"So11111111111111111111111111111111111111112",
"4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",
],
{ encoding: "jsonParsed", commitment: "finalized" },
);
value.forEach((account, i) => {
if (account === null) console.log(`account ${i} not found at slot ${context.slot}`);
else console.log(account.lamports, account.owner);
});Python (triport-sdk)
import os
from triport import Triport
client = Triport(api_key=os.environ["TRIPORT_API_KEY"])
resp = client.sol.get_multiple_accounts(
[
"So11111111111111111111111111111111111111112",
"4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",
],
encoding="jsonParsed",
commitment="finalized",
)
for i, account in enumerate(resp.value):
if account is None:
print(f"account {i} not found at slot {resp.context.slot}")
else:
print(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
confirmedorprocessedfor lower latency 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).