TriportRPC

getTokenAccountsByOwner

POSThttps://api.triport.io

Returns all SPL Token accounts owned by a given wallet, filtered by a single mint or token program.

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

getTokenAccountsByOwner returns every SPL Token account held by a wallet (owner), narrowed by a required filter. You filter by exactly one of mint (return only the owner's account(s) for that specific token) or programId (return all of the owner's accounts owned by that token program, e.g. the SPL Token program). You must supply one and only one of the two — not both, and not neither.

Use it to discover a wallet's token holdings: which mints it holds, the address of each token account, and — with jsonParsed encoding — the decoded balance for each. Each entry in the result pairs the token account's pubkey with its full on-chain account state, all read at a single slot so the snapshot is internally consistent.

This is the standard Solana JSON-RPC method and works on any wallet. It is distinct from the Digital Asset Standard getTokenAccounts, which is a sol_das method (basic+ tier) with cursor pagination and a different result shape; getTokenAccountsByOwner here is sol_read_rpc and available from the free tier.

Parameters

Positional params array: [owner, filter, config?].

ownerstring (base-58 Pubkey)required
Wallet public key to query. Must match ^[1-9A-HJ-NP-Za-km-z]{32,44}$.
filterobjectrequired
Exactly one of mint or programId (see below).
configobjectoptional
Optional configuration object (see below).
filter (TokenAccountsFilter)object
mintstring (base-58 Pubkey)
Restrict results to token accounts for this single mint.
programIdstring (base-58 Pubkey)
Restrict results to token accounts owned by this token program (e.g. TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA for SPL Token).
config (GetTokenAccountsConfig)object
encodingstringoptional
One of base58, base64, base64+zstd, jsonParsed. jsonParsed decodes token balances into a readable object; 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

With a binary encoding (e.g. base64), each account.data is instead a [<data>, <encoding>] tuple rather than the decoded parsed object shown above.

context.slotinteger
Slot at which all accounts were evaluated.
context.apiVersionstring
Version of the RPC node that served the request.
valuearray
One entry per matching token account; empty if the owner holds none.
value[i].pubkeystring (base-58)
Address of the token account.
value[i].accountobject
Full AccountInfo for the token account.
value[i].account.lamportsinteger
Balance of the account in lamports.
value[i].account.ownerstring (base-58)
Owning program (the token program), not the wallet.
value[i].account.executableboolean
Whether the account holds a loaded program (always false for token accounts).
value[i].account.rentEpochinteger
Epoch at which this account will next owe rent (u64).
value[i].account.spaceinteger
Size of the account data in bytes.
value[i].account.dataobject | array
Account data. For jsonParsed: a decoded object with program/parsed. For binary encodings: a [<data>, <encoding>] tuple.

Errors

Errors use the standard JSON-RPC envelope (error.code, error.message, error.data).

CodeHTTPMeaningWhen it happens
-32602400Invalid paramsowner is not valid base-58, filter is missing or specifies both/neither of mint/programId, 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: "getTokenAccountsByOwner",
    params: [
      "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",
      { mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" },
      { encoding: "jsonParsed", commitment: "finalized" },
    ],
  }),
});


const { result } = await res.json();
result.value.forEach(({ pubkey, account }) => {
  const { tokenAmount } = account.data.parsed.info;
  console.log(pubkey, tokenAmount.uiAmountString);
});

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.getTokenAccountsByOwner(
  "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",
  { mint: "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" },
  { encoding: "jsonParsed", commitment: "finalized" },
);


console.log(`found ${value.length} accounts at slot ${context.slot}`);
for (const { pubkey, account } of value) {
  console.log(pubkey, account.data.parsed.info.tokenAmount.uiAmountString);
}

Python (triport-sdk)

import os
from triport import Triport


client = Triport(api_key=os.environ["TRIPORT_API_KEY"])


resp = client.sol.get_token_accounts_by_owner(
    "4fYNw3dojWmQ4dXtSGE9epjRGy9pFSx62YypT7avPYvA",
    filter={"mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"},
    encoding="jsonParsed",
    commitment="finalized",
)


for entry in resp.value:
    info = entry.account.data["parsed"]["info"]
    print(entry.pubkey, info["tokenAmount"]["uiAmountString"])

Notes

  • Exactly one filter: the filter object must contain mint or programId, never both and never neither. Use mint to look up a wallet's account for one specific token; use programId (e.g. TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA) to enumerate all of the wallet's token accounts under that program.
  • Token-2022: to find Token-2022 accounts, filter by that program's programId rather than the legacy SPL Token program — the two live under different owning programs.
  • Encoding: jsonParsed is the most convenient choice — it decodes mint, owner, and tokenAmount for each account. Use base64/base64+zstd when you need the raw account bytes; base58 only works for data under 129 bytes, and dataSlice (binary encodings only) 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.
  • Empty result: a wallet with no matching token accounts returns an empty value array (with a populated context), not an error.
  • Related methods: getTokenAccountsByDelegate (same shape, keyed by approved delegate instead of owner), getTokenAccounts (DAS variant, sol_das / basic+ tier, cursor-paginated), getMultipleAccounts, and getProgramAccounts (note its much stricter sol_read_rpc_heavy rate limits of 2 / 5 / 20 / 80 rps).