Skip to main content

Documentation Index

Fetch the complete documentation index at: https://www.helius.dev/docs/llms.txt

Use this file to discover all available pages before exploring further.

Helius Exclusive Feature - getTransfersByAddress is available through Helius RPC nodes and is not part of standard Solana RPC. This endpoint requires a Developer plan or higher and costs 10 credits per request.
Data Retention - Only the most recent 1 year of transfer history is currently available.

Overview

getTransfersByAddress returns parsed, human-readable token and native SOL transfer objects for a wallet address. It is focused on transfer activity, so it returns concise transfer records instead of full transaction payloads. Use getTransfersByAddress when you need wallet transfer history for payments, portfolio activity, token movement analytics, balance reconciliation, or counterparty-specific transfer monitoring. You can filter transfer history by mint, block time, amount, slot, direction, and counterparty. Use getTransactionsForAddress when you need full transaction data, signatures-only history, or non-transfer activity.

Key Features

Parsed transfer objects

Return human-readable transfer records with parsed accounts, amounts, decimals, and transfer types.

Reconciliation ready

Model SOL, WSOL, Token-2022 fees, mints, burns, and account owner changes so balances can be reconciled accurately.

Mint, time, and amount filters

Narrow transfer history by mint address, block time range, or raw amount range.

Counterparty filters

Filter transfers by sender or recipient with with and direction.

Accuracy and Reconciliation

getTransfersByAddress is built for applications that need transfer history they can trust for ledgers, payment tracking, portfolio activity, and balance reconciliation. Instead of returning raw transaction payloads and leaving every edge case to your parser, the API returns normalized transfer objects with parsed owner accounts, token accounts, mints, raw amounts, decimals, UI amounts, instruction positions, and confirmation status. The response explicitly models the transfer cases that commonly make Solana history difficult to reconcile:
  • Standard SPL token and native SOL transfers.
  • Token-2022 transfers with withheld fees, represented as ordinary transfer rows with separate fee fields.
  • Mints and burns, represented as transfers with a null sender or recipient.
  • SOL wrapping and unwrapping behavior, with a default mode designed to avoid noisy lifecycle rows.
  • Token account owner changes via SetAuthority.
  • Token-2022 withheld fee withdrawals.
  • Intermediary account flows, returned as the underlying transfer records instead of being collapsed into a guessed net movement.
For supported visible transfer events, this lets you reconcile balance movement without reimplementing Solana token parsing logic. Known exclusions, such as hidden SOL movements inferred only from balance changes, are called out in Limitations.

Quick Start

const response = await fetch("https://mainnet.helius-rpc.com/?api-key=YOUR_API_KEY", {
  method: "POST",
  headers: { "Content-Type": "application/json" },
  body: JSON.stringify({
    jsonrpc: "2.0",
    id: "1",
    method: "getTransfersByAddress",
    params: ["86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY"]
  })
});

const data = await response.json();
console.log(data.result.data);

Request Parameters

The address parameter is the wallet owner address, not an associated token account (ATA). The API finds transfer activity for token accounts owned by that wallet.
address
string
required
Base58-encoded owner wallet address to query transfers for. Pass the wallet owner address, not an associated token account (ATA).
config
object
Optional configuration object for filtering, pagination, commitment, ordering, and SOL/WSOL behavior.
with
string
Filter by counterparty address. Returns only transfers to or from this address.
direction
string
default:"any"
Filter by transfer direction relative to address.
  • in: transfers received by address
  • out: transfers sent by address
  • any: incoming and outgoing transfers
mint
string
Filter by token mint address. Use So11111111111111111111111111111111111111111 for native SOL and So11111111111111111111111111111111111111112 for WSOL.
solMode
string
default:"merged"
Controls how native SOL and WSOL are represented.
  • merged: WSOL is treated as native SOL. Wrap and unwrap lifecycle rows are excluded, and WSOL mint values are rewritten to the native SOL mint.
  • separate: WSOL is preserved as a distinct mint, and wrap and unwrap lifecycle rows are included.
filters
object
Additional filters for amount, block time, and slot.
limit
number
default:"100"
Maximum number of transfers to return. Range: 1 to 100.
paginationToken
string
Cursor from the previous response for pagination.
commitment
string
default:"finalized"
Data commitment level.
  • finalized
  • confirmed
sortOrder
string
default:"desc"
Result ordering.
  • desc: newest first
  • asc: oldest first

Filters

Use comparison filters for numeric range queries. All comparison fields are optional and can be combined.
{
  "gt": 1000000,
  "gte": 1000000,
  "lt": 1000000000,
  "lte": 1000000000
}
FilterTypeDescription
amountComparisonFilterRaw transfer amount, not UI amount.
blockTimeComparisonFilterBlock timestamp in Unix seconds.
slotComparisonFilterSlot number.

Transfer Types

The type field identifies the transfer behavior represented by each row.
TypeDescriptionfromUserAccounttoUserAccount
transferStandard token or SOL transfer between two wallets.SenderRecipient
mintNew tokens minted to a wallet.nullRecipient
burnTokens permanently destroyed.Sendernull
wrapSOL wrapped into WSOL. Excluded by default in solMode: "merged".nullOwner
unwrapWSOL unwrapped back to native SOL, or rent recovered from closing a token account. Excluded by default in solMode: "merged".Ownernull or lamport destination
changeOwnerToken account ownership changed with SetAuthority.Old ownerNew owner
withdrawWithheldFeeToken-2022 withheld fees collected from a mint or accounts.nullFee recipient

Transfer Types and Instructions

Transfer typeCovered instructionsDefault visibility
transferSystemProgram::Transfer, SystemProgram::TransferWithSeed, SystemProgram::WithdrawNonceAccount, SystemProgram::CreateAccount, SystemProgram::CreateAccountWithSeed, SystemProgram::CreateAccountAllowPrefundAlways
transferToken::Transfer, Token::TransferChecked, Token-2022::Transfer, Token-2022::TransferCheckedAlways
transferToken-2022::TransferCheckedWithFee, with feeAmount and feeUiAmount fieldsAlways
mintToken::MintTo, Token::MintToCheckedAlways
burnToken::Burn, Token::BurnCheckedAlways
wrapToken::SyncNative, Token::InitializeAccount, Token::InitializeAccount2, Token::InitializeAccount3 when used for WSOL lifecycle handlingsolMode: "separate" only
unwrapToken::CloseAccount on WSOL with balance greater than zerosolMode: "separate" only
unwrapToken::CloseAccount rent recovery for non-WSOL token accounts, or WSOL accounts with zero token balancesolMode: "separate" only
changeOwnerToken::SetAuthority(AccountOwner)Always
withdrawWithheldFeeToken-2022::WithdrawWithheldTokensFromMint, Token-2022::WithdrawWithheldTokensFromAccountsAlways

Response Field Details

  • fromUserAccount and toUserAccount are always present. When a side does not exist, the value is null.
  • fromTokenAccount and toTokenAccount are only included when token-account endpoints are meaningful for the row. They are omitted completely for native SOL transfers.
  • Mint transfers are one-sided: fromUserAccount is null, and they can only be returned as inbound transfers for the recipient.
  • Burn transfers are one-sided: toUserAccount is null, and they can only be returned as outbound transfers for the burning owner.

SOL and wSOL Behavior

SOL exists on Solana in two forms that often appear together in real user activity:
  • Native SOL is the chain’s native asset. It lives directly in a wallet or account as lamports. One SOL is 1,000,000,000 lamports.
  • Wrapped SOL (WSOL, often written wSOL) is an SPL token representation of SOL. It uses the WSOL mint So11111111111111111111111111111111111111112 and lives in a token account, like USDC or any other SPL token.
Users and applications wrap SOL when they need SOL to behave like an SPL token, usually for DeFi, swaps, token-account-based accounting, or program interfaces that only accept SPL tokens. Wrapping typically funds a token account with native SOL and syncs it into WSOL. Unwrapping closes the WSOL token account and returns the SOL to a lamport destination. That lifecycle can create confusing history if you are trying to answer a simple question like “how much SOL moved between this wallet and someone else?” A wrap or unwrap often moves SOL between accounts controlled by the same owner. If those lifecycle rows are shown as ordinary transfers by default, apps can double count activity or show internal bookkeeping as external payments. By default, getTransfersByAddress uses solMode: "merged". In this mode:
  • Native SOL and WSOL are treated as one SOL asset when querying by So11111111111111111111111111111111111111111.
  • WSOL transfer rows are normalized to the native SOL mint so SOL-denominated history is easier to reconcile.
  • Wrap and unwrap lifecycle rows are excluded because they usually represent movement between accounts controlled by the same owner, not a payment to another user.
  • SOL and WSOL transfers between different owners are still represented as transfers.
  • Rent recovered from CloseAccount is represented as a native SOL unwrap row when close-account lifecycle rows are returned.
Use solMode: "separate" when you need WSOL as a distinct SPL token mint or want to inspect wrap and unwrap lifecycle records. In this mode, WSOL keeps the mint So11111111111111111111111111111111111111112, and wrap/unwrap records are returned with type: "wrap" or type: "unwrap". For WSOL account closures in solMode: "separate", unwrap records for the WSOL mint represent the remaining WSOL token balance returned as SOL. Rent refunded from the closed token account is returned as a separate native SOL unwrap row.

Token-2022 Transfer Fees

Token-2022 TransferCheckedWithFee instructions are represented as one transfer record with type: "transfer". The destination amount is returned in amount; withheld fee details are returned in feeAmount and feeUiAmount. For transfers with fees, the source is debited amount + feeAmount, while the destination is credited amount.
{
  "signature": "WcvF2eFxArpqRJySzDuiP6Xw8BMprWytMpYCxk2ExBt5C1WyxWzDWcCWXW8iKQVYR9AtdQxPE1uu1SMEZvbbhdr",
  "slot": 409259683,
  "blockTime": 1774635210,
  "type": "transfer",
  "fromUserAccount": "5aZZ4duJUKiMsJN9vRsoAn4SDX7agvKu7Q3QdFWRfWze",
  "toUserAccount": "FESSvM1cVUchc13XQY8e41oeYxMnyqQNYVZwoznfJsTo",
  "fromTokenAccount": "3VUYGjYktCzNhDVymNb3Z1iHewtfPFRvdA53qSWuxdXy",
  "toTokenAccount": "51cEFBA1virMuPqHXvNGs8FKKTMqeEVKzugv1hqPU2Zc",
  "mint": "CKfatsPMUf8SkiURsDXs7eK6GWb4Jsd6UDbs7twMCWxo",
  "amount": "48650000",
  "decimals": 5,
  "uiAmount": "486.5",
  "feeAmount": "13450000",
  "feeUiAmount": "134.5",
  "confirmationStatus": "finalized",
  "transactionIdx": 1315,
  "instructionIdx": 4,
  "innerInstructionIdx": 0
}

Limitations

  • Failed transactions are not included in V1.
  • Hidden SOL movements inferred only from balance changes are not supported in V1.
  • harvestWithheldTokensToMint is not supported in V1 because it does not indicate the collected amount.
  • Intermediary account flows are not reduced. If a transaction moves funds through intermediary accounts, the underlying transfer records are returned.

Examples

Filter by USDC

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v"
    }
  ]
}

Incoming Transfers From a Sender

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "with": "7hPhaUpydpvm8wtiS3k4LPZKUmivQRs7YQmpE1hFshHx",
      "direction": "in"
    }
  ]
}

Amount and Time Range

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "mint": "So11111111111111111111111111111111111111112",
      "filters": {
        "amount": {
          "gte": 1000000000,
          "lt": 10000000000
        },
        "blockTime": {
          "gte": 1735718400,
          "lt": 1738396800
        }
      }
    }
  ]
}

Paginated Request

{
  "jsonrpc": "2.0",
  "id": "1",
  "method": "getTransfersByAddress",
  "params": [
    "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
    {
      "limit": 50,
      "paginationToken": "315069220:308:2:1:splTransfer"
    }
  ]
}

Fetch Full Transactions for Transfer Rows

getTransfersByAddress returns parsed transfer rows, not full transaction payloads. If you need the full transaction for every transfer, page through transfers first, dedupe by signature, then fetch the full transactions with batched getTransaction calls.
getTransfersByAddress is not batchable across multiple owner addresses. Query one owner address at a time, then batch the resulting getTransaction requests by signature. A single transaction can emit multiple transfer rows, so always dedupe signatures before fetching transactions.
const API_KEY = "YOUR_API_KEY";
const RPC_URL = `https://mainnet.helius-rpc.com/?api-key=${API_KEY}`;
const OWNER_ADDRESS = "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY";

async function rpc(method, params) {
  const response = await fetch(RPC_URL, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      jsonrpc: "2.0",
      id: "1",
      method,
      params
    })
  });

  const body = await response.json();
  if (body.error) {
    throw new Error(body.error.message);
  }
  return body.result;
}

async function getAllTransfers(address) {
  const transfers = [];
  let paginationToken;

  do {
    const result = await rpc("getTransfersByAddress", [
      address,
      {
        limit: 100,
        ...(paginationToken ? { paginationToken } : {})
      }
    ]);

    transfers.push(...result.data);
    paginationToken = result.paginationToken;
  } while (paginationToken);

  return transfers;
}

async function getTransactionsInBatches(signatures, batchSize = 100) {
  const transactions = [];

  for (let i = 0; i < signatures.length; i += batchSize) {
    const batch = signatures.slice(i, i + batchSize).map((signature, index) => ({
      jsonrpc: "2.0",
      id: `${i + index}`,
      method: "getTransaction",
      params: [
        signature,
        {
          encoding: "jsonParsed",
          maxSupportedTransactionVersion: 0
        }
      ]
    }));

    const response = await fetch(RPC_URL, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(batch)
    });

    const results = await response.json();
    for (const item of results) {
      if (item.error) {
        throw new Error(item.error.message);
      }
      transactions.push(item.result);
    }
  }

  return transactions;
}

const transfers = await getAllTransfers(OWNER_ADDRESS);
const signatures = [...new Set(transfers.map((transfer) => transfer.signature))];
const transactions = await getTransactionsInBatches(signatures);

console.log(`Fetched ${transfers.length} transfer rows`);
console.log(`Fetched ${transactions.length} unique transactions`);

Response

{
  "jsonrpc": "2.0",
  "id": "1",
  "result": {
    "data": [
      {
        "signature": "5GEX7Q3X5Q8yJGbKYoR7mtzQmG8tpoEwzjPgqVmn3y5xg3yKwqXcDdN5YVcc9V6vA4TuH5iM6FHRVhTxvz4AX2zG",
        "slot": 315073428,
        "blockTime": 1736159420,
        "type": "transfer",
        "fromUserAccount": "7hPhaUpydpvm8wtiS3k4LPZKUmivQRs7YQmpE1hFshHx",
        "toUserAccount": "86xCnPeV69n6t3DnyGvkKobf9FdN2H9oiVDdaMpo2MMY",
        "fromTokenAccount": "HcvK3EJ74iM9g11cUgsaPvLSrhCvCwcrWxBNd87LsC1x",
        "toTokenAccount": "CBcYniR9G9CN3zGMnwNE4SWbqkYWvCFVreEob9xHnQCY",
        "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
        "amount": "2500000",
        "decimals": 6,
        "uiAmount": "2.5",
        "confirmationStatus": "finalized",
        "transactionIdx": 35,
        "instructionIdx": 1,
        "innerInstructionIdx": 0
      }
    ],
    "paginationToken": "315073428:35:1:0:splTransfer"
  }
}