There's a thing that happens with KOL coordination clusters on Solana that's easy to miss if you're only looking at counts: the same number of KOLs can pile into a $40K-cap micro and a $2M-cap mover, and the trading implication is opposite.
Six KOLs entering a $40K token is alpha discovery — they got there early, before the broader memecoin algo did. Six KOLs entering a $2M token is participation, not discovery — they're chasing what the rest of the tape has already priced. Either can make money, but the next buyer pays a very different price for the same kol_count: 6 signal.
The market_cap_usd_at_first_buy field on the coordination and first-touches endpoints lets you separate those two cases programmatically. This post walks through the field, the entry-MC filters that sit on top of it, and a worked-example "early-entry alpha hunter" scanner.
What the field means
For any KOL cluster on a given token, the first KOL buy is the chronologically-earliest buy in the window from a tracked KOL wallet. We stamp the market cap at that exact moment (market_cap_usd_at_trade from the kol-tracker enrichment pipeline) into the response as market_cap_usd_at_first_buy.
The same response carries market_cap_usd (current cap from mc-tracker) and last_price_usd. Together, you get three reference points:
{
"token_symbol": "PEPECAT",
"kol_count": 6,
"first_buy_at": "2026-05-14T11:02:14Z",
"last_buy_at": "2026-05-14T11:14:48Z",
"market_cap_usd_at_first_buy": 41_200,
"market_cap_usd": 287_000,
"last_price_usd": 0.000287
}
Three numbers, one cluster. The first KOL bought at $41K, by the time you're reading this the cap is $287K. The 6 KOLs are now sitting on roughly 7× from the cluster's entry point. The next person buying this is the seventh buyer at the $287K level — a meaningfully different position than the early entrants had.
The math you can do with three numbers
Two derived ratios matter:
entry_to_now = market_cap_usd / market_cap_usd_at_first_buy
entry_to_now < 1.5 — the cluster is still near its entry. Following is closer to following the alpha than chasing it.
entry_to_now between 2 and 4 — the cluster's already up but not blown out. Following at this point is a momentum trade, not an alpha trade.
entry_to_now > 5 — most of the move already happened. KOLs are sitting on real PnL; you're buying their bag.
implied_kol_pnl_pct = (entry_to_now - 1) * 100
In the PEPECAT example above, entry_to_now = 6.96, so the implied per-KOL PnL is +596% on the entry cap (before sell pressure). Useful as a quick sanity check on whether the cluster is "still entering" (low PnL) or "already won" (high PnL).
Server-side filtering on entry-cap
Both endpoints accept min_mc_usd and max_mc_usd parameters that filter on the entry MC, not the current MC:
# Coordination clusters where the first KOL bought at $20K-$200K cap
curl -H "Authorization: Bearer msk_..." \
"https://madeonsol.com/api/v1/kol/coordination?period=6h&min_kols=4&min_mc_usd=20000&max_mc_usd=200000"
# First-touches where the first KOL bought at <$50K cap, from S-tier scouts
curl -H "Authorization: Bearer msk_..." \
"https://madeonsol.com/api/v1/kol/first-touches?preset=scout&max_mc_usd=50000"
When you set the filter, rows where we can't determine the entry MC are dropped — you asked for a specific band, so silently returning unknowns would be wrong. The filter is exact and strict.
The two endpoints share the same semantics: min_mc_usd and max_mc_usd always refer to the cap at the chronologically-first qualifying KOL buy. The current cap is always exposed alongside — and if you want the full live picture for a mint surfaced by one of these clusters, the /v1/token/{mint} endpoint returns cap, volume, liquidity, and the MEV split in a single call.
A worked example: the "alpha hunter" scanner
The "alpha hunter" pattern: find clusters where multiple KOLs piled in at very early caps, regardless of where the token is now. The output is your watchlist of "tokens KOLs are entering before the algo does":
import { MadeOnSol } from "madeonsol";
const client = new MadeOnSol({ apiKey: process.env.MADEONSOL_API_KEY! });
async function alphaHunter() {
const { coordination } = await client.kol.coordination({
period: "24h",
min_kols: 3,
window_minutes: 30,
min_score: 60,
min_mc_usd: 5_000,
max_mc_usd: 75_000,
include_majors: false,
});
return coordination
.map((c) => ({
symbol: c.token_symbol,
mint: c.token_mint,
kols: c.kol_count,
entry_mc: c.market_cap_usd_at_first_buy,
now_mc: c.market_cap_usd,
move: c.market_cap_usd && c.market_cap_usd_at_first_buy
? ((c.market_cap_usd / c.market_cap_usd_at_first_buy) - 1) * 100
: null,
score: c.coordination_score,
first_buy_at: c.first_buy_at,
}))
.sort((a, b) => (b.move ?? -Infinity) - (a.move ?? -Infinity));
}
The filter says: "3+ KOLs piled in within 30 minutes on a token with entry cap between $5K and $75K, with a coordination score of at least 60, in the last 24 hours." The sort puts the biggest realized moves first.
What you get back is a curated watchlist of tokens where the alpha cluster fired at micro-cap. Most of these tokens have already moved — you can see by how much in the move field. The trading question becomes: which ones still have room to run, and which ones to skip because the move is exhausted? If you'd rather have an autonomous agent consume this scanner, we walk through building an AI agent that buys KOL signals in 20 lines of Python on top of the same endpoints.
A second worked example: the chase filter (inverse)
The same field, inverted, gives you the "late-stage participation" detector:
async function lateChaseDetector() {
const { coordination } = await client.kol.coordination({
period: "1h",
min_kols: 4,
min_score: 60,
min_mc_usd: 1_000_000,
});
// Coordination clusters firing on already-large tokens.
// These are NOT alpha — they're momentum participation.
return coordination.map((c) => ({
symbol: c.token_symbol,
entry_mc: c.market_cap_usd_at_first_buy,
now_mc: c.market_cap_usd,
kols: c.kol_count,
}));
}
Use case: a copy-trade bot that explicitly wants to AVOID late-stage chases. Run this as a blacklist filter and skip any cluster whose mint appears in the result set.
First-touches: per-event entry caps
The first-touches endpoint goes one step further: every event has its own entry cap stamped, plus the current cap, on a per-event level:
{
"event_id": 18342,
"token_mint": "4k3Dyj...",
"token_symbol": "PEPECAT",
"first_kol": {
"name": "@earlyscout",
"winrate_7d": 71.4,
"scout_tier": "S",
"n_first_touches_30d": 42
},
"first_buy_at": "2026-05-14T11:02:14Z",
"first_buy_sol": 1.4,
"token_age_minutes": 6,
"market_cap_usd_at_first_buy": 41_200,
"price_usd_at_first_buy": 0.0000412,
"market_cap_usd": 287_000,
"last_price_usd": 0.000287
}
A typical alpha-hunting pattern combines scout-tier and entry-cap:
# S-tier scouts entering at <$50K MC — the tightest filter we expose
curl -H "Authorization: Bearer msk_..." \
"https://madeonsol.com/api/v1/kol/first-touches?preset=scout&max_mc_usd=50000"
preset=scout expands to min_scout_tier=B + min_n_touches=30 + token_age_max_min=60. Stacking max_mc_usd=50000 on top tightens it further: not just any scout-tier entry, but scout-tier entries firing while the cap is still micro.
For trading this signal in production, use the kol:first_touches WebSocket channel (ULTRA-tier) — the median lead time before the second KOL piles in is ~12 seconds, and REST polling won't catch that consistently.
When the field is null
market_cap_usd_at_first_buy is null in a few cases:
- The first buy fired before mc-tracker started stamping caps on KOL trades (pre-2026-05-04). Historical clusters from before that date have null entries.
- The first buy hit a token that hadn't been observed by mc-tracker yet. Rare, but possible for genuinely first-second mints — the
market_cap_usd_at_trade join needs both kol-tracker and mc-tracker to have seen the token.
- The cluster's first-buy row was lost or the join is incomplete. Very rare.