Get token holders and concentration on pump.fun via API
A holder list that shows addresses and balances answers the least interesting question. The questions that actually decide trades are: how concentrated is the supply, at what price the biggest wallets entered, and whether they are sitting on profit or trapped. This is how to get token holders on Solana done properly — token holder analysis in two calls on the Raiden API: one fast aggregate for the rug math, one full top-holders list where every row is a complete position.
The number that matters first: /holder-stats
Before you look at any individual wallet, you want one aggregate: how many holders, and how much of the held supply the top of the book controls. That is a single fast call:
curl -H "X-API-Key: $RAIDEN_KEY" \ "https://terminal.raiden.wtf/api/tokens/9xQm…pump/holder-stats" { "holders": 1342, "held": "873421889999000", "top10": "412889123456000", "top25": "588123987654000" }
held is the total supply currently in holders' hands; top10
and top25 are the amounts held by the ten and twenty-five largest wallets
(raw token units, as strings). Concentration is a division you do yourself:
top10 / held — here 47.3% of the held supply in ten wallets, 67.3% in
twenty-five. That ratio is the number that matters for rug math: when a handful of
wallets control most of what is held, their coordinated exit is the chart, and no
amount of volume changes that.
held from the same
response, never by an assumed total supply. Effective supply differs per token — part
of it sits in the bonding curve or the pool — and the API indexes pump.fun and PumpSwap
tokens with different supply profiles. held is always the correct base.Who holds — and at what price: /holders
The full list is where this endpoint stops being a block-explorer clone. Holders come back ordered by balance, and each row is not an address with a number — it is the wallet's entire position on the token:
curl -H "X-API-Key: $RAIDEN_KEY" \ "https://terminal.raiden.wtf/api/tokens/9xQm…pump/holders?limit=20" { "data": [ { "trader": "8psN…VRtf", "mint": "9xQm…pump", "symbol": "QMASC", "name": "Quantum Mascot", "token_balance": "48200000000000", "sol_invested": "44800000000", "sol_received": "5500000000", "tokens_bought": "61400000000000", "tokens_sold": "13200000000000", "realized_pnl": "-4100000000", "avg_cost": "0.00073", "current_price": "0.00042", "first_trade_at": "2026-07-21T09:41:14Z", "last_trade_at": "2026-07-24T07:03:55Z", "trade_count": 7 }, { "trader": "Cb3f…g9rE", "mint": "9xQm…pump", "symbol": "QMASC", "name": "Quantum Mascot", "token_balance": "43600000000000", "sol_invested": "6910000000", "sol_received": "7700000000", "tokens_bought": "62800000000000", "tokens_sold": "19200000000000", "realized_pnl": "5450000000", "avg_cost": "0.00011", "current_price": "0.00042", "first_trade_at": "2026-07-21T09:41:12Z", "last_trade_at": "2026-07-23T22:12:03Z", "trade_count": 12 }, … ] }
Read the two rows as a story. The largest holder bought at an average cost of
0.00073 and the price is 0.00042: underwater, already
down 4.1 SOL realized (realized_pnl is net of all fees — swap fees,
creator fees, tips, priority fees). That wallet is a bagholder: it is not defending the
price, it is waiting for an exit. The second-largest entered at 0.00011
— nearly 4× in unrealized profit, with 5.45 SOL already banked. That wallet is latent
sell pressure: every uptick makes its exit more attractive. Same balances, opposite
implications — and invisible in a holders list that only shows amounts.
The rest of the position object rounds out the picture: sol_invested /
sol_received (lamport strings; 1 SOL = 1e9), avg_cost and
current_price in the same unit (lamports per raw token unit, so the
comparison is direct), tokens_bought /
tokens_sold, trade_count for churn, and
first_trade_at to separate launch-slot entries from late buyers — the same
timestamp trail behind finding who bought
first on a launch.
Reading the distribution: healthy vs captured
Patterns that separate an organic book from a staged one:
| Pattern in the data | Reading |
|---|---|
top25 clearly larger than top10, holder count growing while top-10 share falls | Depth beyond the leaders — supply is actually distributing |
top10 ≈ top25 ≈ held | Beyond the top ten nobody holds anything meaningful; the holder count is cosmetic dust |
| High top-10 share from the very first slots | Supply captured at launch, not accumulated — check the launch for bundling |
Top holders all deep in profit (avg_cost far below current_price) | Latent sell pressure — early wallets waiting for exit liquidity |
| Top holders mostly underwater | Bagholders; the wallets that could support the price already spent their ammunition |
The third row deserves its own tooling. When concentration exists from second one, it
was not earned on the open market: the dev or an operator bought a chunk of supply
inside the creation slot across coordinated wallets.
GET /tokens/{mint}/launch quantifies exactly that —
bundled_pct_supply, dev_bundle_pct_supply and the reconstructed
bundle groups — and the full walkthrough is in the
pump.fun bundle checker guide. The
Raiden Trust score folds the same signal in:
heavy bundling is one of the hard signals that caps the score
(capped: true, cap_reason: "bundled") no matter how good everything else
looks.
Python: a holder concentration checker in 25 lines
Concentration snapshot plus a top-holders API PnL table, for any mint:
import requests BASE = "https://terminal.raiden.wtf/api" H = {"X-API-Key": "YOUR_KEY"} MINT = "9xQm…pump" LAMPORTS = 1e9 # 1 · concentration snapshot — divide by held, never by an assumed supply hs = requests.get(f"{BASE}/tokens/{MINT}/holder-stats", headers=H).json() held = int(hs["held"]) print(f"holders: {hs['holders']}") print(f"top-10: {int(hs['top10']) / held:.1%} of held supply") print(f"top-25: {int(hs['top25']) / held:.1%} of held supply") # 2 · top-holder table: who holds, at what cost, in profit or underwater rows = requests.get(f"{BASE}/tokens/{MINT}/holders", params={"limit": 20}, headers=H).json()["data"] for r in rows: share = int(r["token_balance"]) / held invested = int(r["sol_invested"]) / LAMPORTS realized = int(r["realized_pnl"]) / LAMPORTS cost, px = float(r["avg_cost"]), float(r["current_price"]) state = "-" if px == 0 else ("in profit" if px > cost else "underwater") print(f"{r['trader'][:6]} share={share:6.2%} invested={invested:8.2f} SOL " f"realized={realized:+8.2f} SOL trades={r['trade_count']:3} {state}")
Three lines of output tell you more than most dashboards: a token where the top-10 share
is high and every top row prints in profit is a coiled spring; the
same share with rows printing underwater is a graveyard. The share column
uses held as its base, so the script works unchanged on any indexed
pump.fun or PumpSwap token regardless of its supply profile.
Watching holders change: page the tape, don't re-poll
Polling /holders in a loop to detect accumulation is the wrong tool: you
re-download the whole book to discover one change, and you can't see what happened
between two snapshots. Holders are built from trading positions, so every change to
the list comes from a swap — and the tape is pageable with a cursor:
# every swap is a balance delta: +token_amount on buys, -token_amount on sells cursor, balances = None, {} p = {"order": "asc", "limit": 200} while True: if cursor: p["cursor"] = cursor page = requests.get(f"{BASE}/tokens/{MINT}/swaps", params=p, headers=H).json() for s in page["data"]: delta = int(s["token_amount"]) * (1 if s["is_buy"] else -1) balances[s["trader"]] = balances.get(s["trader"], 0) + delta if not page.get("next_cursor"): break cursor = page["next_cursor"]
With order=asc and the cursor you replay the token's whole trading history
once and then keep the map current by polling only for new rows — each swap row carries
trader, is_buy, token_amount,
sol_amount, price, slot and
block_index, so the same loop doubles as an accumulation/distribution
detector with exact ordering. For push instead of pull, swap events also arrive over a
WebSocket stream — streams are scoped to
a wallet list rather than a mint, so put the holders you care about on a list and get
their swaps pushed in real time.
One last shortcut: GET /tokens/{mint}/pack returns
holder_stats alongside the launch analysis, trust score, smart-money and
funding-cluster views in a single dossier call — the whole due-diligence fan-out in one
request. The exact shapes for every endpoint above, with runnable examples, are in the
interactive API docs.
Frequently asked questions
How do I get the top holders of a pump.fun token via API?
GET /tokens/{mint}/holders returns holders ordered by token balance. Each row is a full position object: balance, SOL invested and received, tokens bought and sold, realized PnL net of all fees, average cost, current price, first/last trade timestamps and trade count — so you see not just who holds, but at what price.
How do I check holder concentration on a Solana token?
GET /tokens/{mint}/holder-stats returns the holder count plus the supply held by the top 10 and top 25 holders in one fast aggregate call. Divide top10 or top25 by the held field from the same response to get concentration percentages without assuming any total supply.
Why shouldn't I compute concentration against a 1 billion supply?
Effective supply differs across tokens — part of it sits in the bonding curve or the pool, and not every token is minted the same. The held field in holder-stats is the actual holder-held denominator, so the ratio stays correct for any indexed pump.fun or PumpSwap token.
Can I tell whether top holders are in profit or underwater?
Yes. Every holder row carries avg_cost and current_price: an average cost far below the current price means the holder sits on unrealized profit — latent sell pressure — while avg_cost above the price marks a bagholder. realized_pnl, net of all fees, shows what they already took off the table.
How do I track holder changes in real time?
Don't re-poll the holders list. Holders are built from trading positions, so every change to the list comes from a swap: page the tape with GET /tokens/{mint}/swaps using order=asc and the cursor, and apply each swap's token_amount as a balance delta per trader.
How far back does the holder and swap data go?
The API keeps a 6-month rolling window with a complete record since May 1, 2026. Holder stats and holder positions are computed live from that record for any indexed pump.fun / PumpSwap token.