> ## Documentation Index
> Fetch the complete documentation index at: https://docs.solanatracker.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Track Solana wallet and token transfers

> Query a wallet's SOL and SPL transfer history with filters and historic USD values, then stream new transfers by wallet or token on Datastream.

Load a wallet's transfer history with one REST call, then join a transfer room to receive new transfers as they happen. Both cover native SOL, SPL tokens and Token-2022 tokens.

> [card] [Query transfer history](#query-transfer-history)
>
> Filter by token, counterparty, time, amount or USD value.

> [card] [Stream transfers live](#stream-transfers-live)
>
> Follow a wallet, a token, or one token for one wallet.

## Query transfer history

`GET /account/{address}/transfers` returns transfers in and out of a wallet, newest first. SPL transfers are matched through the token accounts the wallet owns, and each side shows both the token account (`address`) and the wallet that owns it (`owner`).

By default the history leaves out transactions with DEX activity, such as swaps, liquidity adds and removes, and pool fee claims, so you get the wallet's plain transfers. Set `dex=include` to keep them or `dex=only` to get just those.

```bash USDC received theme={null}
curl --get "https://data.solanatracker.io/account/GachaNgyXTU3zFogQ8Z5jR2BLXs8215X2AtEH18VxJq3/transfers" \
  --header "x-api-key: YOUR_API_KEY" \
  --data-urlencode "mint=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v" \
  --data-urlencode "direction=in" \
  --data-urlencode "historicPrices=true" \
  --data-urlencode "limit=50"
```

```javascript Page through history theme={null}
const address = "GachaNgyXTU3zFogQ8Z5jR2BLXs8215X2AtEH18VxJq3";
let cursor;

do {
  const url = new URL(`https://data.solanatracker.io/account/${address}/transfers`);
  url.search = new URLSearchParams({ limit: "100", historicPrices: "true", ...(cursor && { cursor }) });

  const response = await fetch(url, { headers: { "x-api-key": "YOUR_API_KEY" } });
  if (!response.ok) throw new Error((await response.json()).error);
  const page = await response.json();

  for (const t of page.transfers) {
    console.log(t.direction, t.uiAmount, t.token.symbol, t.value.usd, t.from?.owner, "->", t.to?.owner);
  }
  cursor = page.pagination.next;
} while (cursor);
```

Each transfer looks like this:

```json theme={null}
{
  "signature": "2VxcHt8HKSt2T2EuUZLyWPsEKz4H4BPreWV28aZDEzoaHG4Fsu232oKKeQqpVqsSYaf3vv8KN7UoZ4MPJA8vw9EF",
  "status": "success",
  "type": "spl",
  "direction": "in",
  "from": { "address": "C2RjaMN2NeYAErS6KiBjPQhHCt95J8mCmmLiQqZXPisR", "owner": "BfG7WYmravgBhNdWpGoiFmF8L1duw2vdqdDHiZid2hoJ" },
  "to": { "address": "D9CEogjHA6CpS12F8St9zpSco7pQKJB5uR1RqDsuzQZk", "owner": "GachaNgyXTU3zFogQ8Z5jR2BLXs8215X2AtEH18VxJq3" },
  "token": { "name": "USD Coin", "symbol": "USDC", "mint": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v", "image": "https://image.solanatracker.io/proxy?url=…", "decimals": 6 },
  "amount": "25000000",
  "uiAmount": "25",
  "decimals": 6,
  "price": { "usd": 1 },
  "value": { "usd": 25 },
  "timestamp": 1792483949,
  "slot": 459159504
}
```

* **`amount`** is the raw integer amount and **`uiAmount`** the exact decimal amount, both as strings.
* **`timestamp`** is the block time in Unix **seconds**.
* **`type`** is `sol` for native SOL and `spl` for token transfers. SOL uses the wrapped SOL mint `So11111111111111111111111111111111111111112`.
* **`status`** is the transaction's outcome, `success` or `failed`. Failed transactions are left out unless you ask for `status=failed` or `status=any`.
* **`price`** and **`value`** are only there with `historicPrices=true` or a value filter.
* **`identity`** appears on `from` or `to` when the wallet is known: a KOL, an exchange, a pool, a developer, or an SNS name.

### Filter the history

| Filter | Parameters |
| - | - |
| Token | `mint`, `type=sol\|spl` |
| Direction | `direction=in\|out\|all` |
| Sender, receiver | `from`, `to`, `counterparty` (either side), `excludeFrom`, `excludeTo` (up to 5 comma-separated addresses each, wallet or token account) |
| Time | `start`, `end` (inclusive), in Unix seconds |
| Slot | `startSlot`, `endSlot` (inclusive) |
| Amount | `minAmount`, `maxAmount` in token units, `excludeZero=true` |
| USD value | `minValue`, `maxValue` (turns on `historicPrices`; `limit` at most 100) |
| DEX activity | `dex=exclude\|include\|only` (default `exclude`) |
| Outcome | `status=success\|failed\|any` (default `success`) |
| Order | `sortOrder=desc\|asc` |

Each parameter has one name. A name the endpoint doesn't know is a 400 that tells you the right one, for example `unknown parameter timeStart; use start`, so a typo never returns an unfiltered page.

`historicPrices=true` adds `price.usd` and `value.usd` with the token's USD price at the time of the transfer, from the last 1-minute candle at most an hour before it. Without a price they are `null`.

### What counts as DEX activity

A transaction has DEX activity when one of its transfers goes to or comes from a pool: an account a DEX or launchpad program owns, such as a pump.fun bonding curve or a Meteora DLMM pool, or a Raydium or Meteora vault authority. That covers swaps, liquidity adds and removes, and fee and reward claims. A transaction where the wallet sent one token and received another counts too. `dex=exclude` and `dex=only` act on whole transactions: every transfer of the transaction is left out or kept together. Only the transfers that match `direction` and `mint` are looked at, so with those set, a transaction whose pool leg is filtered out counts as a plain transfer.

### Group by transaction

Add `grouped=true` to also get `transactions`, the page's transfers grouped by signature. Each transaction has its `transfers`, the number of them in `legs`, `totals.in`, `totals.out` and `totals.tokens`, and `dex`. `type` is `swap` when `dex` is true, and `swap` names the token in and the token out when the wallet sent one token and received another. With `historicPrices=true`, the totals also carry USD: `totals.value`, `totals.net`, and `usd` on each side.

### Page through results

Pass `pagination.next` back as `cursor` with the same filters, and stop when `hasMore` is `false`. A page never splits a transaction, so it can hold a few transfers more or fewer than `limit`; with `grouped=true`, `limit` usually counts transactions. Filtered requests read a bounded number of transfers per call, so a page can hold fewer than `limit` rows, or none, while `hasMore` is still `true`. Keep paging.

With `minValue` or `maxValue`, each page prices the next `limit` transfers and returns those that match. If prices can't be read in time, the request returns 503; send it again.

### Use the TypeScript SDK

Install `@solana-tracker/data-api` version **0.6.0 or later**. `getAccountTransfers` takes the same filters as the endpoint, and the address filters accept an array or a comma-separated string. The SDK checks them with the API's rules and throws a `ValidationError` before sending a request the API would refuse. `iterateAccountTransfers` follows `pagination.next` for you and keeps going past empty filtered pages.

```typescript theme={null}
import { Client } from '@solana-tracker/data-api';

const client = new Client({ apiKey: 'YOUR_API_KEY' });
const wallet = 'GachaNgyXTU3zFogQ8Z5jR2BLXs8215X2AtEH18VxJq3';

// Every page of USDC received, with the USD value at the time.
for await (const page of client.iterateAccountTransfers(wallet, {
  mint: 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v',
  direction: 'in',
  historicPrices: true,
  limit: 100,
})) {
  for (const t of page.transfers) {
    console.log(t.signature, t.uiAmount, t.token.symbol, t.value?.usd, t.from?.identity?.name ?? t.from?.owner);
  }
}

// One entry per transaction, swaps included.
const grouped = await client.getAccountTransfers(wallet, {
  grouped: true,
  dex: 'include',
  historicPrices: true,
  limit: 50,
});
for (const tx of grouped.transactions) {
  console.log(tx.signature, tx.type, tx.totals.net?.usd, tx.swap?.out.token.symbol, '->', tx.swap?.in.token.symbol);
}
```

With `{ grouped: true }`, TypeScript knows the response has `transactions`.

## Stream transfers live

Connect to `wss://datastream.solanatracker.io/{apiKey}` with your Data API key. Datastream is available on Premium, Business, and Enterprise plans.

### Choose a room

* **[`transfer:wallet:{wallet}`](https://docs.solanatracker.io/datastream/websockets/transferwallet)**: every transfer to or from a wallet, across all tokens.
* **[`transfer:{mint}`](https://docs.solanatracker.io/datastream/websockets/transfertoken)**: every transfer of a token. Not available for SOL.
* **[`transfer:{mint}:{wallet}`](https://docs.solanatracker.io/datastream/websockets/transfertokenwallet)**: one token to or from one wallet. Works for SOL with the wrapped SOL mint.

Append **`:enriched`** to any room to add `token` (name, symbol, image, decimals), `price.usd`, `value.usd` and `marketCap.usd` to every transfer and balance change, and `identity` to each transfer's `from` and `to` and each balance change: the wallet's KOL profile, bot, platform, developer, pool or SNS labels, as in the trade rooms, or `null` for a wallet with none. SOL's `marketCap.usd` is its price times the circulating supply; USDC, USDT and USD1 have none. The enriched message can arrive up to 250 ms after the plain one; if a lookup took longer, it has `enrichmentStatus: "partial"` and `null` for what is missing.

```javascript theme={null}
const wallet = "GachaNgyXTU3zFogQ8Z5jR2BLXs8215X2AtEH18VxJq3";
const ws = new WebSocket("wss://datastream.solanatracker.io/YOUR_API_KEY");

ws.addEventListener("open", () => {
  ws.send(JSON.stringify({ type: "join", room: `transfer:wallet:${wallet}:enriched` }));
});

ws.addEventListener("message", (event) => {
  const msg = JSON.parse(event.data);
  if (msg.type === "ping") return ws.send(JSON.stringify({ type: "pong" }));
  if (msg.type !== "message") return;

  for (const t of msg.data.transfers) {
    console.log(t.direction, t.uiAmount, t.token.symbol, t.value.usd, msg.data.signature);
  }
});
```

### Subscribe with the SDK

The SDK handles heartbeats and reconnects. `transfers.wallet`, `transfers.token` and `transfers.tokenWallet` join the three rooms; set `{ enriched: true }` for the `:enriched` room. `transfers.token` throws for SOL: use `transfers.wallet`, or `transfers.tokenWallet` with the wrapped SOL mint.

```typescript theme={null}
import { Datastream } from '@solana-tracker/data-api';

const stream = new Datastream({
  wsUrl: 'wss://datastream.solanatracker.io/YOUR_API_KEY',
});
stream.on('error', console.error);
await stream.connect();

const sub = stream.subscribe.transfers
  .wallet('GachaNgyXTU3zFogQ8Z5jR2BLXs8215X2AtEH18VxJq3', { enriched: true })
  .on((update) => {
    for (const t of update.transfers) {
      console.log(t.direction, t.uiAmount, t.token.symbol, t.value.usd, t.from.identity?.name ?? t.from.owner);
    }
    // Some prices or identities timed out and are null.
    if (update.enrichmentStatus === 'partial') console.log(update.signature);
  });

// sub.unsubscribe();
// stream.disconnect();
```

### Read a message

Each message is one transaction:

```json theme={null}
{
  "type": "message",
  "room": "transfer:wallet:5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9",
  "data": {
    "signature": "3sGWwELDWpxMaTWkadG95XK3mYiY2TZw8X6VVG7eZopJ8hGvWt4s2A6KK7ZZMVN7Qujg4WtJcm8dXmwvfnyhZ4NS",
    "slot": 462944056,
    "timestamp": 1793290384,
    "commitment": "processed",
    "swapTx": false,
    "transfers": [
      {
        "id": "3sGWwELDWpxMaTWkadG95XK3mYiY2TZw8X6VVG7eZopJ8hGvWt4s2A6KK7ZZMVN7Qujg4WtJcm8dXmwvfnyhZ4NS:3:-1",
        "signature": "3sGWwELDWpxMaTWkadG95XK3mYiY2TZw8X6VVG7eZopJ8hGvWt4s2A6KK7ZZMVN7Qujg4WtJcm8dXmwvfnyhZ4NS",
        "slot": 462944056,
        "timestamp": 1793290384,
        "commitment": "processed",
        "instruction": 3,
        "inner": -1,
        "type": "spl",
        "program": "token-2022",
        "mint": "pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn",
        "decimals": 6,
        "amount": "18404223000000",
        "uiAmount": "18404223",
        "from": {
          "address": "CEbJzsx15hLQkHD6Tsp5vk58rcnMtvbgLReGLzjiy4uH",
          "owner": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9",
          "postBalance": "1151345685569531"
        },
        "to": {
          "address": "F5zXibinJCcNKY8BJhYC6iX5sKCKkaaSFV3MJgbVz25M",
          "owner": "G56HkiSheuhfjnTPGjGC1nNddu7NBtTqedueYKCrEHW2",
          "postBalance": "18404223000000"
        },
        "swapTx": false,
        "direction": "out"
      }
    ],
    "balances": [
      {
        "owner": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9",
        "account": "CEbJzsx15hLQkHD6Tsp5vk58rcnMtvbgLReGLzjiy4uH",
        "mint": "pumpCmXqMfrsAkQ5r49WcJnRayYRqmXz6ae8H7H9Dfn",
        "program": "token-2022",
        "decimals": 6,
        "pre": "1169749908569531",
        "post": "1151345685569531",
        "change": "-18404223000000",
        "cause": "transfer"
      },
      {
        "owner": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9",
        "account": "5tzFkiKscXHK5ZXCGbXZxdw7gTjjD1mBwuoFbhUvuAi9",
        "mint": "So11111111111111111111111111111111111111112",
        "program": "system",
        "decimals": 9,
        "pre": "1029258892726041",
        "post": "1029258892711041",
        "change": "-15000",
        "cause": "other",
        "fee": "15000"
      }
    ]
  }
}
```

* **`transfers`** are the room's transfers in instruction order. `id` is `signature:instruction:inner` and unique per transfer. `direction` is set in wallet rooms. Token-2022 transfers with a transfer fee carry `fee`, and `amount` is before the fee.
* **`balances`** are the room's balance changes in that transaction: the wallet's, the token's, or the wallet's for that token. `cause` is `transfer`, `swap` (the trader's traded tokens), or `other`. The fee payer's SOL entry has `fee`, which is included in `change`.
* **Swaps stay in the trade rooms.** A transfer that is a leg of a swap already streamed is not sent again. What remains of a swap, such as platform fees, tips or payouts to other wallets, arrives with `swapTx: true`.
* **Not transfers:** wraps, unwraps and moves between a wallet's own accounts. Failed transactions are not streamed.

In an `:enriched` room the same message also carries `token`, `price`, `value`, `marketCap` and `identity`. In this one, a KOL sold a token for SOL; the SOL fee paid to another wallet is what remains of the swap, so it arrives with `swapTx: true`.

> [accordion] Enriched message example
>
> ```json theme={null}
> {
>   "type": "message",
>   "room": "transfer:wallet:ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph:enriched",
>   "data": {
>     "signature": "3og3m2Rtw2L6P9Zv98J1ZhwGtrKVfmyTzJBSWKf1mCLGDzNddSyceNqHvTvP5oAZ42FpoAkqmEEStT42XMBmXuJp",
>     "slot": 463404942,
>     "timestamp": 1793388931,
>     "commitment": "processed",
>     "swapTx": true,
>     "transfers": [
>       {
>         "id": "3og3m2Rtw2L6P9Zv98J1ZhwGtrKVfmyTzJBSWKf1mCLGDzNddSyceNqHvTvP5oAZ42FpoAkqmEEStT42XMBmXuJp:1:-1",
>         "signature": "3og3m2Rtw2L6P9Zv98J1ZhwGtrKVfmyTzJBSWKf1mCLGDzNddSyceNqHvTvP5oAZ42FpoAkqmEEStT42XMBmXuJp",
>         "slot": 463404942,
>         "timestamp": 1793388931,
>         "commitment": "processed",
>         "instruction": 1,
>         "inner": -1,
>         "type": "sol",
>         "program": "system",
>         "mint": "So11111111111111111111111111111111111111112",
>         "decimals": 9,
>         "amount": "1984300",
>         "uiAmount": "0.0019843",
>         "from": {
>           "address": "ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>           "owner": "ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>           "postBalance": "89633841158",
>           "identity": {
>             "name": "Ducky",
>             "twitter": "@zXDuckyXz",
>             "avatar": "https://kol-avatar.solanatracker.io/ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>             "platforms": [
>               "axiom"
>             ],
>             "type": "kol",
>             "tags": [
>               "kol",
>               "axiom"
>             ]
>           }
>         },
>         "to": {
>           "address": "8GV86MhDQST6rh56oTMU9v5TdHwRtXnFQ3zdGD3WT3mG",
>           "owner": "8GV86MhDQST6rh56oTMU9v5TdHwRtXnFQ3zdGD3WT3mG",
>           "postBalance": "43378482944",
>           "identity": null
>         },
>         "swapTx": true,
>         "token": {
>           "mint": "So11111111111111111111111111111111111111112",
>           "name": "Solana",
>           "symbol": "SOL",
>           "image": "https://image.solanatracker.io/proxy?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolana-labs%2Ftoken-list%2Fmain%2Fassets%2Fmainnet%2FSo11111111111111111111111111111111111111112%2Flogo.png",
>           "decimals": 9
>         },
>         "price": {
>           "usd": 94.23572271990248
>         },
>         "value": {
>           "usd": 0.19
>         },
>         "marketCap": {
>           "usd": 55602827082.74623
>         },
>         "direction": "out"
>       }
>     ],
>     "balances": [
>       {
>         "owner": "ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>         "account": "CMkGUwGS7a7qxNKVUv2UwMoy92Awj9DbUNXcLy1ZbXxZ",
>         "mint": "6AyZsNDJctD1T1hmqPsZWGGSuWM7feNEUbph5SeLpump",
>         "program": "token-2022",
>         "decimals": 6,
>         "pre": "26109484455083",
>         "post": "0",
>         "change": "-26109484455083",
>         "cause": "swap",
>         "identity": {
>           "name": "Ducky",
>           "twitter": "@zXDuckyXz",
>           "avatar": "https://kol-avatar.solanatracker.io/ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>           "platforms": [
>             "axiom"
>           ],
>           "type": "kol",
>           "tags": [
>             "kol",
>             "axiom"
>           ]
>         },
>         "token": {
>           "mint": "6AyZsNDJctD1T1hmqPsZWGGSuWM7feNEUbph5SeLpump",
>           "name": "The Chill Penguin",
>           "symbol": "Penguin",
>           "image": "https://image.solanatracker.io/proxy?url=https%3A%2F%2Faxiomtrading-v2.axiom-cdn.io%2FCKUym5DFePEDCGA8VTVxZcNEpveHgb71JzhXGRqypump.webp",
>           "decimals": 6
>         },
>         "price": {
>           "usd": 0.000003898241016375787
>         },
>         "value": {
>           "usd": -101.78
>         },
>         "marketCap": {
>           "usd": 3898.241016375787
>         }
>       },
>       {
>         "owner": "ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>         "account": "ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>         "mint": "So11111111111111111111111111111111111111112",
>         "program": "system",
>         "decimals": 9,
>         "pre": "88473075092",
>         "post": "89633841158",
>         "change": "1160766066",
>         "cause": "swap",
>         "fee": "20700",
>         "identity": {
>           "name": "Ducky",
>           "twitter": "@zXDuckyXz",
>           "avatar": "https://kol-avatar.solanatracker.io/ADC1QV9raLnGGDbnWdnsxazeZ4Tsiho4vrWadYswA2ph",
>           "platforms": [
>             "axiom"
>           ],
>           "type": "kol",
>           "tags": [
>             "kol",
>             "axiom"
>           ]
>         },
>         "token": {
>           "mint": "So11111111111111111111111111111111111111112",
>           "name": "Solana",
>           "symbol": "SOL",
>           "image": "https://image.solanatracker.io/proxy?url=https%3A%2F%2Fraw.githubusercontent.com%2Fsolana-labs%2Ftoken-list%2Fmain%2Fassets%2Fmainnet%2FSo11111111111111111111111111111111111111112%2Flogo.png",
>           "decimals": 9
>         },
>         "price": {
>           "usd": 94.23572271990248
>         },
>         "value": {
>           "usd": 109.39
>         },
>         "marketCap": {
>           "usd": 55602827082.74623
>         }
>       }
>     ]
>   }
> }
> ```

Live transfers are sent at processed commitment. A transaction can be dropped on a fork, and there is no rollback message, so reconcile with the REST endpoint. Joining overlapping rooms delivers the same transfer once per room.

## Next

> [card] [Account transfers reference](https://docs.solanatracker.io/data-api/transfers/get-account-transfers.md)
>
> Every parameter and response field.

> [card] [Datastream protocol](https://docs.solanatracker.io/guides/datastream-protocol.md)
>
> Connect, join rooms, and handle heartbeats.


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.