On pump.fun-style launches, the first 20 wallets to buy tell you nearly everything you need to know. If those 20 are 14 bundlers and 3 snipe bots, the deployer is about to dump on whoever arrives next. If they're 4 known-alpha wallets and 2 KOLs, you're looking at an organic launch with smart money interest. Same chart, same market cap, completely different trade.
GET /api/v1/tokens/{mint}/cap-table returns that first cohort, enriched. Each buyer comes with their historical win rate, PnL, bot confidence, bundle flag, and KOL identity — so you're not just looking at anonymous addresses, you're looking at a scorecard of who got in early and whether that's good news or not.
The call
GET /api/v1/tokens/{mint}/cap-table
Authorization: Bearer msk_...
No query params. The mint is a standard base58 Solana address.
Tier gating:
- BASIC — 403. This endpoint requires paid access.
- PRO — top 10 non-deployer buyers.
- ULTRA — top 20 non-deployer buyers.
Important: the endpoint excludes the deployer's own rank-1 buy. "First 10 buyers" means first 10 other wallets to buy — which is the cohort that actually carries signal about whether the launch is organic.
The response
{
"mint": "26s2aY...pump",
"buyers": [
{
"rank": 2,
"wallet": "86AE...EdD",
"first_buy_sol": 2.022,
"first_buy_at": "2026-04-22T19:14:03Z",
"is_bundle": false,
"is_kol": true,
"kol_name": "Publix",
"bot_confidence": 0.12,
"historical_win_rate": 0.67,
"historical_pnl_sol": 248.3,
"historical_tokens": 142
},
{
"rank": 3,
"wallet": "5tQz...xPk",
"first_buy_sol": 0.45,
"first_buy_at": "2026-04-22T19:14:05Z",
"is_bundle": true,
"is_kol": false,
"kol_name": null,
"bot_confidence": 0.89,
"historical_win_rate": 0.18,
"historical_pnl_sol": -14.2,
"historical_tokens": 1847
}
],
"summary": {
"known_alpha_wallets": 3,
"known_kols": 2,
"bundle_buyers": 14,
"buyer_quality_score": 32,
"confidence": "high",
"signal": "negative"
}
}
Two sections: the buyers[] array with per-wallet enrichment, and the summary block with the aggregate quality score.
The buyers array
Ordered by rank (rank 2 first, because rank 1 is the deployer and is excluded). Each row has three categories of data:
Identity
wallet — raw address (PRO and ULTRA, not truncated).
is_kol / kol_name — is this wallet in the MadeOnSol KOL list? If yes, who? Strong positive signal.
is_bundle — did this wallet buy as part of a bundle transaction with the deployer or adjacent wallets? Bundles are the #1 rug tell on pump.fun.
Historical performance (from mv_alpha_wallets)
historical_win_rate — their win rate across every token they've traded historically.
historical_pnl_sol — lifetime realized PnL.
historical_tokens — how many distinct tokens they've touched.
bot_confidence — 0.0–1.0 score for how bot-like their behavior is (flat hour distribution, burst frequency, uniform sizing).
These fields come from our alpha wallet intelligence dataset (~25,000 scored wallets). If the buyer is a fresh wallet we haven't scored yet, these fields are null — itself a signal (no track record).
Position context
rank — their slot in the buyer queue, starting at 2 (deployer is rank 1, excluded).
first_buy_sol — size of their first buy, in SOL.
first_buy_at — timestamp.
A rank-2 wallet buying 2 SOL 3 seconds after deploy looks very different from a rank-15 wallet buying 0.3 SOL 8 minutes in. Use rank + timing together.
The summary block
The summary is the aggregate verdict on the cohort. Note: it always scores against all 20 buyers, not the tier-capped visible ones. So on PRO you see 10 wallets but the score reflects all 20. You're not buying a half-picture.
buyer_quality_score (0–100)
A composite score derived from:
- Average historical win rate of non-bot buyers → positive
- Count of known alpha wallets (up to +20 bonus) → positive
- Count of known KOLs (up to +20 bonus) → positive
- Count of bundle buyers → heavy negative
- Bot-dominated cohort (>50% high bot confidence) → heavy negative
Rough interpretation:
- ≥ 75 — very strong cohort. Multiple alpha wallets, few to no bundles.
- 60–75 — clean launch, some alpha signal.
- 40–60 — mixed / ambiguous.
- 20–40 — bundle-heavy or bot-heavy, caution warranted.
- < 20 — avoid. Dominated by bundles or low-quality actors.
confidence
high — cohort has enough historical data to score meaningfully.
medium — partial data coverage.
low — mostly fresh wallets with no track record. The score defaults to 50 with low confidence. Don't over-interpret.
signal
A categorical shortcut derived directly from buyer_quality_score:
positive — score > 60
neutral — score in [40, 60]
negative — score < 40
Use the raw score when you need fine-grained filtering; use the signal for quick gating.
A decision workflow
import { MadeOnSol } from "madeonsol";
const client = new MadeOnSol({ apiKey: process.env.MADEONSOL_API_KEY! });
async function analyzeLaunch(mint: string) {
const { buyers, summary } = await client.tokens.capTable({ mint });
// Hard kills
if (summary.bundle_buyers >= 10) return "skip: bundle-heavy launch";
if (summary.confidence === "low" && buyers.length < 5) return "skip: not enough buyers";
// Look for alpha concentration in rank 2-5
const topFive = buyers.slice(0, 4);
const alphaInTop = topFive.filter(b => (b.historical_win_rate ?? 0) >= 0.5).length;
const bundlesInTop = topFive.filter(b => b.is_bundle).length;
if (bundlesInTop >= 2) return "skip: bundles in first-four seats";
if (alphaInTop >= 2 && summary.buyer_quality_score >= 60) return "long signal";
return "neutral, watch volume";
}
The pattern worth internalizing: a bad signal in the first 4 ranks is more important than a bad summary score. Bundlers piled in at ranks 15-20 matter less than the same pattern at ranks 2-5.
The KOL ranks matter more than you'd think
When a known KOL shows up at rank 2, 3, or 4, it's not that they had a secret tip — it's that they have the tooling to detect launches fast and the filter to skip junk. Their presence in the top few ranks is a pre-computed signal. Five KOLs in the first 10 ranks is almost never a coincidence.
Inverse signal: a launch where ranks 2-10 are all is_kol: false and historical_win_rate: null is a launch that smart money didn't notice or deliberately ignored. Either way, not your trade.
Pairing with /tokens/{mint}/buyer-quality
/buyer-quality returns a simplified version of this endpoint: just the summary score + breakdown counts, no per-wallet rows. It's cheaper (5-minute LRU cache), available on every tier, and perfect for bulk pre-filtering.
The usual workflow: call /buyer-quality on every fresh mint as a gate, then call /cap-table only on the ones that pass to see the full per-wallet breakdown and decide entry.
const { score, signal } = await client.tokens.buyerQuality({ mint });
if (signal !== "negative" && score >= 50) {
const details = await client.tokens.capTable({ mint });
// deep decision on details
}
One API call per candidate at the gate stage, one only when warranted. Keeps you under quota.
Tier considerations
| Field | BASIC | PRO | ULTRA |
|---|
| Endpoint access | ✗ (403) | ✓ | ✓ |
buyers[] returned | — | top 10 | top 20 |
| Per-buyer wallet address | — |