Parameters

owner
string
required

Public key of the owner (base-58 encoded)

config
object
required

Configuration object containing:

programId
string
required

Public key of the token program (base-58 encoded)

commitment
string

Commitment level (processed, confirmed, finalized)

encoding
string

Encoding for account data (base58, base64, jsonParsed)

dataSlice
object
offset
number

Offset into account data

length
number

Length of data to return

Response

result
object

Object containing:

context
object
slot
number

The slot the request was processed at

value
array

Array of token account objects containing:

pubkey
string

Public key of the token account (base-58 encoded)

account
object
lamports
number

Number of lamports in the account

owner
string

Public key of the account owner (base-58 encoded)

executable
boolean

Whether the account is executable

rentEpoch
number

Epoch at which the account will next owe rent

data
object
parsed
object
info
object
tokenAmount
object
amount
string

Raw amount of tokens as a string

decimals
number

Number of decimals configured for token’s mint

uiAmount
number

Token amount as a float, accounting for decimals

uiAmountString
string

Token amount as a string, accounting for decimals

mint
string

Public key of the token’s mint (base-58 encoded)

owner
string

Public key of the token account owner (base-58 encoded)

delegate
string

Public key of the delegate (base-58 encoded)

type
string

Type of account (account)

program
string

Program that owns the account (spl-token)

space
number

Number of bytes allocated to the account

Code Examples

Basic Request

curl https://rpc.orbitflare.com -X POST -H "Content-Type: application/json" -d '{
  "jsonrpc": "2.0",
  "id": 1,
  "method": "getTokenAccountsByOwner",
  "params": [
    "4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj",
    {
      "programId": "TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA"
    }
  ]
}'

Using web3.js

import { Connection, PublicKey } from '@solana/web3.js';

const connection = new Connection('https://rpc.orbitflare.com');

// Get token accounts by owner
const owner = new PublicKey('4vJ9JU1bJJE96FWSJKvHsmmFADCg4gpZQff4P3bkLZj');
const programId = new PublicKey('TokenkegQfeZyiNwAJbNbGKPFXCWuBvf9Ss623VQ5DA');
const accounts = await connection.getTokenAccountsByOwner(owner, { programId });
console.log('Token accounts:', accounts);

// Get token accounts by owner with analysis
async function getTokenAccountsByOwnerWithAnalysis(
  owner: PublicKey,
  config: { programId: PublicKey; commitment?: string }
) {
  const accounts = await connection.getTokenAccountsByOwner(owner, config);
  
  return {
    accounts,
    analysis: {
      totalAccounts: accounts.value.length,
      totalBalance: accounts.value.reduce((sum, acc) => {
        const amount = BigInt(acc.account.data.parsed.info.tokenAmount.amount);
        return sum + amount;
      }, BigInt(0)),
      byMint: accounts.value.reduce((acc, account) => {
        const mint = account.account.data.parsed.info.mint;
        const amount = BigInt(account.account.data.parsed.info.tokenAmount.amount);
        acc[mint] = (acc[mint] || BigInt(0)) + amount;
        return acc;
      }, {} as Record<string, bigint>),
      metadata: {
        timestamp: Date.now(),
        commitment: config.commitment
      }
    }
  };
}

Notes

  1. Returns all token accounts owned by the given public key
  2. The owner has full control over these accounts
  3. The response is immediate as it reads from the current state
  4. The accounts can change with token transfers and other operations
  5. The owner must be a valid public key

Best Practices

  1. Use appropriate commitment level based on your needs
  2. Cache results when appropriate to reduce RPC load
  3. Monitor for changes in owned accounts
  4. Consider using websocket subscription for real-time updates
  5. Handle network errors and retry when appropriate

Common Errors

CodeMessageSolution
-32601Method not foundVerify you’re connected to a Solana RPC node
-32602Invalid paramsCheck owner public key and configuration
-32007Owner not foundVerify the owner exists
-32008Invalid program IDVerify the program ID is correct

Use Cases

  1. Owner Account Analysis

    interface OwnerAccountAnalysis {
      owner: string;
      accounts: Array<{
        pubkey: string;
        mint: string;
        balance: string;
        delegate?: string;
      }>;
      metrics: {
        totalAccounts: number;
        totalBalance: string;
        byMint: Record<string, string>;
        delegatedAccounts: number;
      };
      metadata: {
        timestamp: number;
        commitment?: string;
      };
    }
    
    class OwnerAccountAnalyzer {
      async analyzeOwnerAccounts(
        owner: PublicKey,
        config: { programId: PublicKey; commitment?: string }
      ): Promise<OwnerAccountAnalysis> {
        const accounts = await connection.getTokenAccountsByOwner(owner, config);
        
        const byMint: Record<string, bigint> = {};
        let totalBalance = BigInt(0);
        let delegatedAccounts = 0;
        
        accounts.value.forEach(account => {
          const mint = account.account.data.parsed.info.mint;
          const amount = BigInt(account.account.data.parsed.info.tokenAmount.amount);
          const delegate = account.account.data.parsed.info.delegate;
          
          byMint[mint] = (byMint[mint] || BigInt(0)) + amount;
          totalBalance += amount;
          if (delegate) {
            delegatedAccounts++;
          }
        });
        
        return {
          owner: owner.toBase58(),
          accounts: accounts.value.map(account => ({
            pubkey: account.pubkey,
            mint: account.account.data.parsed.info.mint,
            balance: account.account.data.parsed.info.tokenAmount.amount,
            delegate: account.account.data.parsed.info.delegate
          })),
          metrics: {
            totalAccounts: accounts.value.length,
            totalBalance: totalBalance.toString(),
            byMint: Object.fromEntries(
              Object.entries(byMint).map(([mint, amount]) => [mint, amount.toString()])
            ),
            delegatedAccounts
          },
          metadata: {
            timestamp: Date.now(),
            commitment: config.commitment
          }
        };
      }
    }
    
  2. Owner Account Monitoring

    interface OwnerAccountChange {
      owner: string;
      changes: Array<{
        type: 'added' | 'removed' | 'modified';
        account: string;
        previousBalance?: string;
        currentBalance?: string;
        previousDelegate?: string;
        currentDelegate?: string;
      }>;
      metadata: {
        timestamp: number;
      };
    }
    
    class OwnerAccountMonitor {
      private previousAccounts: Map<string, {
        balance: string;
        delegate?: string;
      }> = new Map();
      
      async monitorOwnerAccounts(
        owner: PublicKey,
        config: { programId: PublicKey; commitment?: string }
      ): Promise<OwnerAccountChange | null> {
        const accounts = await connection.getTokenAccountsByOwner(owner, config);
        const currentAccounts = new Map(
          accounts.value.map(account => [
            account.pubkey,
            {
              balance: account.account.data.parsed.info.tokenAmount.amount,
              delegate: account.account.data.parsed.info.delegate
            }
          ])
        );
        
        const changes: Array<{
          type: 'added' | 'removed' | 'modified';
          account: string;
          previousBalance?: string;
          currentBalance?: string;
          previousDelegate?: string;
          currentDelegate?: string;
        }> = [];
        
        // Check for removed or modified accounts
        this.previousAccounts.forEach((data, account) => {
          if (!currentAccounts.has(account)) {
            changes.push({
              type: 'removed',
              account,
              previousBalance: data.balance,
              previousDelegate: data.delegate
            });
          } else {
            const current = currentAccounts.get(account)!;
            if (current.balance !== data.balance || current.delegate !== data.delegate) {
              changes.push({
                type: 'modified',
                account,
                previousBalance: data.balance,
                currentBalance: current.balance,
                previousDelegate: data.delegate,
                currentDelegate: current.delegate
              });
            }
          }
        });
        
        // Check for added accounts
        currentAccounts.forEach((data, account) => {
          if (!this.previousAccounts.has(account)) {
            changes.push({
              type: 'added',
              account,
              currentBalance: data.balance,
              currentDelegate: data.delegate
            });
          }
        });
        
        this.previousAccounts = currentAccounts;
        
        if (changes.length > 0) {
          return {
            owner: owner.toBase58(),
            changes,
            metadata: {
              timestamp: Date.now()
            }
          };
        }
        
        return null;
      }
    }
    
  3. Owner Account Planning

    interface OwnerAccountPlan {
      owner: string;
      currentAccounts: Array<{
        pubkey: string;
        mint: string;
        balance: string;
        delegate?: string;
      }>;
      recommendations: Array<{
        type: 'consolidate' | 'diversify' | 'rebalance' | 'delegate';
        accounts: string[];
        reason: string;
      }>;
      metadata: {
        timestamp: number;
      };
    }
    
    class OwnerAccountPlanner {
      private readonly minBalancePerAccount = BigInt(1000000); // 1 token
      private readonly maxAccountsPerMint = 5;
      
      async planOwnerAccounts(
        owner: PublicKey,
        config: { programId: PublicKey; commitment?: string }
      ): Promise<OwnerAccountPlan> {
        const accounts = await connection.getTokenAccountsByOwner(owner, config);
        
        const byMint = accounts.value.reduce((acc, account) => {
          const mint = account.account.data.parsed.info.mint;
          if (!acc[mint]) {
            acc[mint] = [];
          }
          acc[mint].push(account);
          return acc;
        }, {} as Record<string, typeof accounts.value>);
        
        const recommendations: Array<{
          type: 'consolidate' | 'diversify' | 'rebalance' | 'delegate';
          accounts: string[];
          reason: string;
        }> = [];
        
        Object.entries(byMint).forEach(([mint, mintAccounts]) => {
          // Check for accounts with low balances
          const lowBalanceAccounts = mintAccounts.filter(account => 
            BigInt(account.account.data.parsed.info.tokenAmount.amount) < this.minBalancePerAccount
          );
          
          if (lowBalanceAccounts.length > 0) {
            recommendations.push({
              type: 'consolidate',
              accounts: lowBalanceAccounts.map(account => account.pubkey),
              reason: `Accounts with balances below minimum threshold for mint ${mint}`
            });
          }
          
          // Check for too many accounts per mint
          if (mintAccounts.length > this.maxAccountsPerMint) {
            recommendations.push({
              type: 'consolidate',
              accounts: mintAccounts.map(account => account.pubkey),
              reason: `Too many accounts (${mintAccounts.length}) for mint ${mint}`
            });
          }
          
          // Check for accounts without delegates
          const accountsWithoutDelegates = mintAccounts.filter(
            account => !account.account.data.parsed.info.delegate
          );
          
          if (accountsWithoutDelegates.length > 0) {
            recommendations.push({
              type: 'delegate',
              accounts: accountsWithoutDelegates.map(account => account.pubkey),
              reason: `Accounts without delegates for mint ${mint}`
            });
          }
        });
        
        return {
          owner: owner.toBase58(),
          currentAccounts: accounts.value.map(account => ({
            pubkey: account.pubkey,
            mint: account.account.data.parsed.info.mint,
            balance: account.account.data.parsed.info.tokenAmount.amount,
            delegate: account.account.data.parsed.info.delegate
          })),
          recommendations,
          metadata: {
            timestamp: Date.now()
          }
        };
      }
    }