TriportRPC

getMultipleAccounts

POSThttps://api.triport.io

Returns the account information for a list of Solana public keys in a single round-trip.

Solanasol_read_rpcfree+ — 20 rps (free) / 60 rps (basic) / 200 rps (pro) / 600 rps (business), with burst

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
Public keys of the accounts to query, up to 100. Each must match ^[1-9A-HJ-NP-Za-km-z]{32,44}$.
configobjectoptional
Optional configuration object (see below).
config (GetAccountInfoConfig)object
encodingstringoptional
One of base58, base64, base64+zstd, jsonParsed. Defaults to base64. base58 is limited to account data under 129 bytes.
commitmentstringoptional
Confirmation level: processed, confirmed, or finalized.
dataSliceobjectoptional
Limits each returned account's data to a byte slice: { "offset": <integer>, "length": <integer> }. Only valid with the binary encodings.
minContextSlotintegeroptional
Minimum slot the request must be evaluated at. The request fails if the node has not yet reached this slot.

Response

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.slotinteger
Slot at which all accounts were evaluated.
context.apiVersionstring
Version of the RPC node that served the request.
valuearray
One entry per requested public key, in the same order.
value[i]object | null
Account state, or null if that account does not exist.
value[i].lamportsinteger
Balance of the account in lamports.
value[i].ownerstring (base-58)
Public key of the program that owns the account.
value[i].executableboolean
Whether the account holds a loaded program.
value[i].rentEpochinteger
Epoch at which this account will next owe rent (u64).
value[i].spaceinteger
Size of the account data in bytes.
value[i].dataarray | object
Account data. For binary encodings: [<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).

CodeHTTPMeaningWhen it happens
-32602400Invalid paramsA 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).
-32002403Tier insufficientAPI key's tier/scope does not include sol_read_rpc.
-32003429Rate limit exceededMore than your tier's sustained RPS (with burst) was sent. Honour the Retry-After header.
-32601404Method not foundMethod 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: value is parallel to pubkeys — index i of the response always corresponds to index i of the request, with null for 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 separate getAccountInfo calls.
  • Encoding & size: base58 only works for account data smaller than 129 bytes; use base64 or base64+zstd for larger accounts. dataSlice (binary encodings only) fetches just a window of each account's bytes and is ignored by jsonParsed.
  • Commitment: use confirmed or processed for lower latency when you can tolerate possible rollbacks; finalized is the safest choice for settled state.
  • Related methods: getAccountInfo (single account), getBalance (lamports only), and getProgramAccounts (all accounts owned by a program — note its much stricter sol_read_rpc_heavy rate limits of 2 / 5 / 20 / 80 rps).