Solana getTokenAccountsByOwner & RugCheck getTokenReportSummary Developer Guide

Learn how to fetch every token account a Solana wallet owns with getTokenAccountsByOwner, decode mints and balances with byte slicing, and check a token's safety score with the RugCheck getTokenReportSummary API — one program, two APIs.

Reference documentation: getTokenAccountsByOwner

Before We Begin

Before reading this guide, you should be familiar with fetching single and multiple accounts on Solana, as well as optimizing RPC calls with byte slicing. Our developer guides for getAccountInfo and getMultipleAccounts will help you learn these skills, if you need.

This guide is a little special: it uses two APIs together, and therefore two API keys — a FluxRPC API key for the getTokenAccountsByOwner RPC call, and a RugCheck API key for the getTokenReportSummary endpoint. Our free keys are sufficient for both. You can create each one by logging in to FluxRPC and visiting the respective API Keys page (FluxRPC / RugCheck) — the banner at the top of this guide will tell you if you are missing one.

There is no need to copy-paste them: just navigate back to this page while logged in, and we will automatically use the keys from your account in every example below.

In this guide, we will accomplish the following:

  1. Learn about Token Accounts
  2. Learn how to fetch token accounts, by owner
  3. Fetch a RugCheck report summary for a token you own

About Token Accounts

On Solana, all accounts are owned by a program that determines how to interpret the data in an account, and the rules for changing it. For example, when you transfer SOL from one account to another, the System program determines what bytes represent the SOL stored in your account, and whether to permit the change to both accounts.

Token accounts are owned by one of the two token programs, either SPL Token, or Token-2022 (also called Token Extensions). Each of these programs has a different public key:

These two types of token have different features. However, they have some features in common:

  1. They are controlled by a wallet, which is confusingly also called the "owner". In this guide we'll refer to this explicitly as the "owning wallet" to avoid mixing it up with the program that literally owns the account.
  2. They contain a "mint" that identifies what tokens the wallet contains.
  3. They contain an amount, the number of tokens in the wallet.
  4. Each token account can contain only one type of token, but a single wallet can own many token accounts.

The two token programs have many features, especially Token-2022. These are beyond the scope of this guide — for our purposes we only need to know about the four properties above.

Now, think about what happens when you open your preferred Solana wallet. You enter a passphrase, see your SOL balance, and within a short delay a list of the tokens you own appears. How does it know which tokens you own, if they are all stored in separate accounts?

How to Fetch Token Accounts

We will discuss three methods, of which one is practical, and the other two are interesting and form a bit of a story about why the last method is required.

First, the public key of token accounts is not random. It is computed by the Associated Token Account program (ATokenGPvbdGVxr1b2hvZbsiqW5xWH25efTNsLJA8knL), using the owning wallet's public key, the token mint, the token program, and the associated token program itself.

These four inputs act as a seed to a function that computes a new public key. Whenever you enter the same four inputs, you will get the same output. This means that for a given owning wallet and token, you'll always end up with the same token account public key. So, you could fetch your tokens by computing the public key for every token you own, and then executing a getMultipleAccounts RPC call.

However, this has the major disadvantage of requiring that you know the mints of all the tokens that you own. Also, the work of deriving the token account public keys is unnecessarily complicated. So what do we do? Let's look at the data stored in an SPL token account, which you may remember from our getMultipleAccounts guide:

Since all token accounts are owned by one of the two token programs, you could in principle make a getProgramAccounts request against the Token program, and use a memcmp filter to select only accounts where bytes 32-63 match a specific public key, the owning wallet. This way, you could get all the tokens a wallet owns, without knowing what the mints are in advance. However, this is impractical for a different set of reasons:

  1. The SPL Token program owns a very large set of accounts — a few hundred gigabytes! Your request will be very slow.
  2. Most RPCs block getProgramAccounts requests to the Token program, because of how large it is.
  3. Since every wallet application out there needs to do this, a lot of people would be making this very resource-intensive RPC call.

So instead, the Solana standard RPC methods specify an RPC call that abstracts away all that complexity, called getTokenAccountsByOwner. You provide it the owning wallet and token program, and it will return all the token accounts owned by that wallet. Beneath the hood, every RPC provider will handle this differently than a getProgramAccounts call — that would be too slow to be practical, so it will be some data structure optimized to answer this query quickly.

Some accounts can own a lot of tokens, for example the following owns more than 1000! We'll use this one in our examples today, just to use something with a little more meat than a wallet that owns only a handful of tokens.

curl "https://eu.fluxrpc.com?key=<Your-API-Key>" -s -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenAccountsByOwner",
    "params": [
      "MfDuWeqSHEqTFVYZ7LoexgAK9dxk7cy4DFJWjWMGVWa",
      { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
      { "encoding": "base64" }
    ]
  }'

Having the accounts is great, but how do we take that mess of accounts and output a list of token mints and balances? Again, our first step is byte slicing. We know that we only need bytes 0-71:

curl "https://eu.fluxrpc.com?key=<Your-API-Key>" -s -X POST \
  -H "Content-Type: application/json" \
  -d '{
    "jsonrpc": "2.0",
    "id": 1,
    "method": "getTokenAccountsByOwner",
    "params": [
      "MfDuWeqSHEqTFVYZ7LoexgAK9dxk7cy4DFJWjWMGVWa",
      { "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA" },
      {
        "encoding": "base64",
        "dataSlice": { "offset": 0, "length": 72 }
      }
    ]
  }'

That will save us a significant amount of bandwidth (and therefore money). Sadly, we can only specify one dataSlice parameter. So we have to take bytes 0-71, even though 32 of them will always be the same (the owning wallet). We could make two RPC calls with different dataSlice parameters, but that would be even more inefficient in this case — although this would sometimes be a reasonable approach for accounts storing a very large amount of data.

Fetching Balances and a RugCheck Report

Now that our RPC call is good enough, let's build a program around it that fetches all the token accounts for that wallet (over 1000!). Then we'll print out the mint & balance for a few of them (not all of them, that would be a pain to read through), and also fetch the RugCheck report and score for whichever token comes in first. Note that the order will not always be the same! So if you run this program more than once, you'll likely get RugCheck reports for different tokens.

import requests
import json
import base64
import base58

RPC_APIKey = "<Your-API-Key>"
rugCheck_APIKey = "{{RUGCHECK_API_KEY}}"
RPCRegion = "eu"
AccountPubKey = "MfDuWeqSHEqTFVYZ7LoexgAK9dxk7cy4DFJWjWMGVWa" # Add your wallet here, if you want!

def fetchTokenAccounts(pubKey, program):
    headers = {'content-type': 'application/json'}
    url = "https://" + RPCRegion + ".fluxrpc.com?key=" + RPC_APIKey

    data = {
        "jsonrpc": "2.0",
        "id": 1,
        "method": "getTokenAccountsByOwner",
        "params": [
            pubKey,
            {
                "programId": program
            },
            {
                "encoding": "base64",
                "dataSlice": {"offset": 0, "length": 72}
            }
        ]
    }
    response = requests.post(url, data=json.dumps(data), headers=headers)
    return response

def fetchRugCheckReport(tokenMint):
    headers = {'content-type': 'application/json', 'X-API-KEY': rugCheck_APIKey}
    url = "https://api.rugcheck.xyz/v1/tokens/" + str(tokenMint) + "/report/summary"
    response = requests.get(url, headers=headers)
    return response

# Fetch all SPL token accounts for the wallet & append to tokenMints list
# This is requesting a lot of data, and could take a moment to complete.
response = fetchTokenAccounts(AccountPubKey, "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA")
if response.status_code != 200:
    raise Exception("RPC returned HTTP error code " + str(response.status_code))
responseJSON = json.loads(response.text)
tokenAccounts = (responseJSON["result"]["value"])
all_mints = []
all_amounts = []
for i in tokenAccounts:
    dataBytes = base64.b64decode(i["account"]["data"][0])
    all_mints.append(str(base58.b58encode(dataBytes[:32]), 'utf-8'))
    all_amounts.append(str(int.from_bytes(dataBytes[-8:], byteorder='little')))

# This outputs a lot of mints, lets limit it to printing out 5, although we have all of them!
for count, i in enumerate(all_mints[:5]):
    print("Mint: " + i + " Balance: " + all_amounts[count])

report = fetchRugCheckReport(all_mints[0]) # Fetch the rugcheck report summary for one token we found
if report.status_code != 200:
    raise Exception("RugCheck returned HTTP error code " + str(report.status_code))

reportJSON = json.loads(report.text)
print() # Empty line so it's easier to read
# Lets print this just so you can see what the report looks like
print("Token Report for mint: " + all_mints[0])
print(reportJSON)
print() # Empty line so it's easier to read
# Let's extract the token score too
print("The token score for token mint: " + all_mints[0] + " is: " + str(reportJSON["score_normalised"]))

Note that we also extract the token score, as score_normalised. We consider many different factors when scoring a token, and the normalized score (0-100, lower is better) gives a better indication of the result than the raw score.

In summary, we've used only on-chain methods to fetch & store the token account balances for a large liquidity bot. For normal user wallets, this would run much faster! Changing the example above to use your public key, this method would be sufficient to build yourself a simple UI showing your different token balances. If you add transaction sending, you've got yourself a simple wallet application!

Bonus Tricks: Bulk Reports and Rate Limits

If you want to fetch the RugCheck reports for ALL the tokens in a wallet, we offer two methods — bulkTokenReports and bulkTokenSummary — to handle that. These are much more efficient than fetching the reports one at a time, and are available to all paid RugCheck plans. Our bulkTokenSummary guide walks through exactly that.

For testing purposes, you can totally iterate through an array of mints and fetch the reports one-at-a-time, but you'll have to stay under the rate limit. We provide an easy way to do that — the response headers for all RugCheck API calls contain the remaining calls you can make, like so:

{
  "Server": "nginx/1.22.1",
  "Date": "Thu, 30 Jul 2026 11:56:06 GMT",
  "Content-Type": "application/json; charset=utf-8",
  "Transfer-Encoding": "chunked",
  "Connection": "keep-alive",
  "Vary": "Accept-Encoding",
  "X-Rate-Limit-Limit": "3",
  "X-Rate-Limit-Remaining": "2",
  "Content-Encoding": "gzip"
}

In this example, I've made one call on a free plan that's limited to three requests per second. The field X-Rate-Limit-Limit shows me my total rate limit, and X-Rate-Limit-Remaining shows me how many requests I have left. After one second, my rate limit will refresh to 3. If my remaining requests is 0, I would have to wait a little before making a new one, or RugCheck will return an HTTP 429 error.

Next Steps

If you haven't yet, read the getProgramAccounts guide — it covers the memcmp filters and byte-offset techniques that getTokenAccountsByOwner abstracts away, and they matter as soon as you need accounts from any other program.

← All developer guides