Skip to main content
The Wallet API is in Beta. Endpoints and response formats may change.

Overview

The Transaction History endpoint retrieves the complete transaction history for a Solana wallet using the Enhanced Transactions API. It returns human-readable, parsed transactions with balance changes for each transaction, in reverse chronological order (newest first). The endpoint returns up to 100 transactions per request, so pagination is manual. Use the before parameter with pagination.nextCursor to fetch the next page, and read pagination.hasMore to know when more results are available. Each request is a single API call and costs 100 credits. The tokenAccounts parameter controls whether transactions involving token accounts owned by the wallet are included:
  • balanceChanged (recommended): includes transactions that changed token account balances, filtering spam.
  • none: only direct wallet interactions.
  • all: all token account transactions, including spam.
The tokenAccounts filter relies on the owner field in token balance metadata, which was not available before slot 111,491,819 (~December 2022). Transactions involving token accounts active before this slot may be missing. See the getTransactionsForAddress tutorial for a workaround.

When to use this

Use the Transaction History API when you need to:
  • Display a transaction feed: show users their complete transaction history.
  • Calculate PnL: track gains and losses across all transactions.
  • Tax and accounting: generate complete transaction reports for tax filing.
  • Portfolio analytics: analyze trading patterns and activity.
  • Audit trails: maintain complete records of wallet activity.
  • Balance reconstruction: rebuild current balances from historical data.

Quickstart

Basic history query

Get the most recent transactions with balance changes:
const getTransactionHistory = async (address) => {
  const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY`;

  const response = await fetch(url);
  if (!response.ok) {
    throw new Error(`HTTP error! status: ${response.status}`);
  }

  const data = await response.json();

  console.log(`Found ${data.data.length} transactions`);

  // Display recent transactions
  data.data.forEach(tx => {
    const date = new Date(tx.timestamp * 1000).toLocaleString();
    const status = tx.error ? 'Failed' : 'Success';

    console.log(`\n${status} - ${date}`);
    console.log(`Signature: ${tx.signature.slice(0, 20)}...`);
    console.log(`Fee: ${tx.fee} SOL`);

    // Show balance changes
    tx.balanceChanges.forEach(change => {
      const sign = change.amount > 0 ? '+' : '';
      console.log(`  ${sign}${change.amount} ${change.mint === 'SOL' ? 'SOL' : change.mint.slice(0, 8)}...`);
    });
  });

  return data;
};

getTransactionHistory("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");

Pagination for complete history

Fetch all transactions using pagination with the before parameter:
const getAllTransactionHistory = async (address) => {
  let allTransactions = [];
  let before = null;

  do {
    const url = before
      ? `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&before=${before}`
      : `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY`;

    const response = await fetch(url);
    const data = await response.json();

    allTransactions = allTransactions.concat(data.data);
    before = data.pagination.hasMore ? data.pagination.nextCursor : null;

    console.log(`Fetched ${allTransactions.length} transactions so far...`);

  } while (before);

  console.log(`\nTotal transactions: ${allTransactions.length}`);
  return allTransactions;
};

getAllTransactionHistory("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY");

Query parameters

ParameterTypeDefaultDescription
limitinteger100Maximum number of transactions per request (1-100)
beforestring-Fetch transactions before this signature (use pagination.nextCursor from previous response)
afterstring-Fetch transactions after this signature (for ascending order pagination)
typestring-Filter by transaction type (e.g., SWAP, TRANSFER, NFT_SALE, TOKEN_MINT)
tokenAccountsstringbalanceChangedFilter transactions involving token accounts: none, balanceChanged (recommended), or all

Available transaction types

The type parameter supports filtering by these transaction types: SWAP, TRANSFER, NFT_SALE, NFT_BID, NFT_LISTING, NFT_MINT, NFT_CANCEL_LISTING, TOKEN_MINT, BURN, COMPRESSED_NFT_MINT, COMPRESSED_NFT_TRANSFER, COMPRESSED_NFT_BURN, CREATE_STORE, WHITELIST_CREATOR, ADD_TO_WHITELIST, REMOVE_FROM_WHITELIST, AUCTION_MANAGER_CLAIM_BID, EMPTY_PAYMENT_ACCOUNT, UPDATE_PRIMARY_SALE_METADATA, ADD_TOKEN_TO_VAULT, ACTIVATE_VAULT, INIT_VAULT, INIT_BANK, INIT_STAKE, MERGE_STAKE, SPLIT_STAKE, CREATE_AUCTION_MANAGER, START_AUCTION, CREATE_AUCTION_MANAGER_V2, UPDATE_EXTERNAL_PRICE_ACCOUNT, EXECUTE_TRANSACTION

Filter examples

// Get only SWAP transactions
const url = `https://api.helius.xyz/v1/wallet/${address}/history?api-key=YOUR_API_KEY&type=SWAP`;

Response format

{
  "data": [
    {
      "signature": "5wHu1qwD7Jsj3xqWjdSEJmYr3Q5f5RjXqjqQJ7jqEj7jqEj7jqEj7jqEj7jqEj7jqE",
      "timestamp": 1704067200,
      "slot": 250000000,
      "fee": 0.000005,
      "feePayer": "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
      "error": null,
      "balanceChanges": [
        {
          "mint": "So11111111111111111111111111111111111111111",
          "amount": -0.05,
          "decimals": 9
        },
        {
          "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
          "amount": 50.0,
          "decimals": 6
        }
      ]
    }
  ],
  "pagination": {
    "hasMore": true,
    "nextCursor": "5wHu1qwD7Jsj3xqWjdSEJmYr3Q5f5RjXqjqQJ7jqEj7jqEj7jqEj7jqEj7jqEj7jqE"
  }
}

Field notes

  • timestamp: Unix seconds. May be null for very recent transactions that haven’t been fully processed yet.
  • error: null for successful transactions; an error value for failed ones. Failed transactions still incur fees.
  • balanceChanges: how the wallet’s holdings changed in the transaction — a positive amount is tokens received, a negative amount is tokens sent or spent.
  • mint (within balanceChanges): token mint address, or "SOL" for native SOL.
  • amount (within balanceChanges): human-readable, already divided by decimals-0.05 means −0.05 SOL, not −0.05 lamports. This endpoint does not include a raw amountRaw field.

Example balance changes

// Swap: Sold 0.05 SOL, received 5 USDC
{
  "balanceChanges": [
    { "mint": "SOL", "amount": -0.05, "decimals": 9 },
    { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": 5.0, "decimals": 6 }
  ]
}

// Simple transfer: Sent 10 USDC
{
  "balanceChanges": [
    { "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "amount": -10.0, "decimals": 6 }
  ]
}

Use cases

Calculate total trading volume

Sum all transfers to get trading volume:
const calculateTradingVolume = async (address, tokenMint) => {
  const transactions = await getAllTransactionHistory(address);

  let totalVolume = 0;

  transactions.forEach(tx => {
    tx.balanceChanges.forEach(change => {
      if (change.mint === tokenMint) {
        totalVolume += Math.abs(change.amount);
      }
    });
  });

  console.log(`Total ${tokenMint} volume: ${totalVolume}`);
  return totalVolume;
};

// Example: Calculate total USDC volume
calculateTradingVolume(
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" // USDC
);

Generate a tax report

Create a transaction report for tax filing:
const generateTaxReport = async (address, year) => {
  const transactions = await getAllTransactionHistory(address);

  const startDate = new Date(`${year}-01-01`).getTime() / 1000;
  // Set to end of December 31st (23:59:59.999) to include all transactions from that day
  const endDate = new Date(`${year}-12-31T23:59:59.999Z`).getTime() / 1000;

  const taxableTransactions = transactions
    .filter(tx => tx.timestamp >= startDate && tx.timestamp <= endDate)
    .map(tx => ({
      date: new Date(tx.timestamp * 1000).toISOString(),
      signature: tx.signature,
      fee: tx.fee,
      balanceChanges: tx.balanceChanges,
      explorerUrl: `https://orbmarkets.io/tx/${tx.signature}`
    }));

  console.log(`Found ${taxableTransactions.length} transactions in ${year}`);

  // Export as JSON
  const report = {
    address,
    year,
    transactionCount: taxableTransactions.length,
    transactions: taxableTransactions
  };

  console.log(JSON.stringify(report, null, 2));
  return report;
};

generateTaxReport("86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY", 2024);

Track failed transactions

Find all failed transactions to understand errors:
const getFailedTransactions = async (address) => {
  const data = await getTransactionHistory(address);

  const failed = data.data.filter(tx => tx.error !== null);

  console.log(`Found ${failed.length} failed transactions`);

  failed.forEach(tx => {
    const date = new Date(tx.timestamp * 1000).toLocaleString();
    console.log(`\n${date}`);
    console.log(`Signature: ${tx.signature}`);
    console.log(`Error: ${tx.error}`);
    console.log(`Fee Paid: ${tx.fee} SOL`);
  });

  return failed;
};

Reconstruct a historical balance

Calculate what the balance was at a specific point in time:
const getHistoricalBalance = async (address, targetTimestamp) => {
  const transactions = await getAllTransactionHistory(address);

  // Filter to transactions before target date
  const relevantTxs = transactions.filter(tx => tx.timestamp <= targetTimestamp);

  // Sum all balance changes
  const balances = {};

  relevantTxs.forEach(tx => {
    tx.balanceChanges.forEach(change => {
      if (!balances[change.mint]) {
        balances[change.mint] = 0;
      }
      balances[change.mint] += change.amount;
    });
  });

  console.log(`Historical balances as of ${new Date(targetTimestamp * 1000).toLocaleString()}:`);
  Object.entries(balances).forEach(([mint, balance]) => {
    console.log(`${mint}: ${balance}`);
  });

  return balances;
};

// Example: Get balances on Jan 1, 2024
getHistoricalBalance(
  "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
  new Date("2024-01-01").getTime() / 1000
);
For a single token’s exact balance at a point in time, the Historical Balance endpoint reads it directly from on-chain post-balances instead of summing changes client-side.

Analyze transaction fees

Calculate total fees paid:
const analyzeFees = async (address) => {
  const transactions = await getAllTransactionHistory(address);

  const totalFees = transactions.reduce((sum, tx) => sum + tx.fee, 0);
  const avgFee = totalFees / transactions.length;

  const successfulTxs = transactions.filter(tx => !tx.error);
  const failedTxs = transactions.filter(tx => tx.error);

  const wastedFees = failedTxs.reduce((sum, tx) => sum + tx.fee, 0);

  console.log(`Total Transactions: ${transactions.length}`);
  console.log(`Successful: ${successfulTxs.length}`);
  console.log(`Failed: ${failedTxs.length}`);
  console.log(`Total Fees Paid: ${totalFees.toFixed(6)} SOL`);
  console.log(`Average Fee: ${avgFee.toFixed(6)} SOL`);
  console.log(`Wasted on Failed Txs: ${wastedFees.toFixed(6)} SOL`);

  return {
    totalFees,
    avgFee,
    wastedFees,
    successRate: (successfulTxs.length / transactions.length) * 100
  };
};

Best practices

  • Use pagination for complete history. Some wallets have hundreds of thousands of transactions; always paginate when fetching all of them.
  • Cache historical data. Historical transactions never change. Cache them locally and only fetch new transactions.
  • Handle failed transactions. Check the error field to distinguish successful from failed transactions. Failed transactions still incur fees.
  • Use timestamps for date filtering. Timestamps are in Unix seconds. Convert to local dates for display and filtering.

Common errors

Error CodeDescriptionSolution
400Invalid wallet address formatVerify the address is a valid base58 Solana address
401Missing or invalid API keyCheck your API key is included in the request
429Rate limit exceededReduce request frequency or upgrade your plan

Next steps

Token Transfers

A transfer-only view with sender/recipient info — simpler than full history.

Wallet API Overview

All Wallet API endpoints and shared conventions.

API Reference

Request and response schemas for transaction history.