Three feeds -- fomo.family, pump.fun, and X -- real-time, no delay. Every request returns {"rows": [...], "total": N}, newest first. Base URL is https://commradar.xyz.
Every request requires a key, sent as an X-API-Key header:
curl "https://commradar.xyz/api/v1/fomo-feed?limit=1" \ -H "X-API-Key: YOUR_KEY"
CORS is enabled on all endpoints below (Access-Control-Allow-Origin: *) — safe to call directly from browser JS, no server-side proxy needed. Want a machine-readable version of this page instead? GET /api/v1/endpoints returns the same reference as JSON.
Token theses and callouts sourced from fomo.family's global feed, real-time — one row per post, across Solana, Ethereum, Base, BNB, Robinhood, and Monad.
| Param | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Max rows to return (capped at 200). |
before | string | — | A created_at value from a previous response — returns rows older than it, for pagination. |
chain | string | — | Filter to one chain: solana, ethereum, base, bnb, robinhood, or monad. |
curl "https://commradar.xyz/api/v1/fomo-feed?limit=1" \ -H "X-API-Key: YOUR_KEY"
{
"rows": [
{
"id": "6e2a69c0-12a1-4536-8f0f-26ca8b5bcd63",
"feed_type": "thesis_created",
"token_address": "Ai66LHZG9MCzg1WKdawwqduVAXpNDUuV8M3uyq5ppump",
"chain": "solana",
"ticker": "CATE",
"token_image_url": "https://token-media.defined.fi/...",
"display_name": "Faisal",
"user_handle": "Faisac67",
"user_image_url": "https://prod-fomo-profile-pics.s3.amazonaws.com/...",
"comment_text": "gm ratio htx\n\nhttps://x.com/poorgoat_/status/2092899810697253217",
"created_at": "2026-08-27T09:58:39.374Z",
"likes": 0,
"pct_unrealized_pnl": -8.099,
"pct_realized_pnl": 0.0,
"market_cap": 58666059.67,
"position_value_usd": 10091.17,
"convergence": { "fomo": 2, "pumpfun": 0 }
// ...plus every field in the table below
}
],
"total": 1625
}
| Field | Description |
|---|---|
| id | Unique post ID. |
| feed_type | thesis_created (a position-backed thesis) or manual (a plain callout with no position data — title is set instead). |
| token_address | Token contract address. |
| network_id | Numeric chain ID (1=Ethereum, 56=BNB, 143=Monad, 4663=Robinhood, 8453=Base, 1399811149=Solana). |
| chain | Human-readable chain name. |
| ticker | Token symbol. |
| token_image_url | Token logo, or null. |
| user_id / display_name / user_handle / twitter / user_image_url | Caller identity. user_handle is the caller's fomo.family account handle, not their X handle — fomo doesn't reliably expose a real X handle (twitter is typically empty). Cross-platform caller merges (see /api/v1/caller/<handle>) only catch fomo callers whose fomo handle happens to match their X handle. |
| comment_text | The post body / thesis text. |
| title / link | Only set when feed_type is manual. |
| created_at | ISO8601 UTC timestamp the post was made. |
| likes | Like count at time of discovery (not re-checked afterward). |
| unrealized_pnl_usd / realized_pnl_usd | Caller's position PnL in USD. |
| pct_unrealized_pnl / pct_realized_pnl | Same, as a percentage. |
| market_cap | Token market cap at time of discovery. |
| position_value_usd | Caller's position value in USD. |
| human_token_amount | Caller's token holding, in whole tokens. |
| current_price | Token price at time of discovery. |
| discovered_at | When CommRadar's own scraper first saw this post (not the same as created_at). |
| convergence | {"fomo": N, "pumpfun": M, "x": K, "both_apps": bool} -- unique callers (deduped by handle) who mentioned this same token on each platform in the last 15 minutes. both_apps is true when both fomo and pumpfun are non-zero. Always live/real-time, even on the delayed tier -- it's an aggregate signal, not the underlying post content. |
Token callouts from pump.fun's home feed, real-time, threaded — each row is an original callout with any follow-up replies nested under it in updates, matching pump.fun's own UI.
| Param | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Max rows to return (capped at 200). |
before | string | — | A last_activity value from a previous response — returns threads older than it, for pagination. |
curl "https://commradar.xyz/api/v1/pumpfun-callouts?limit=1" \ -H "X-API-Key: YOUR_KEY"
{
"rows": [
{
"callout_id": "a3080158-5aef-4e2e-bcc0-5e0ad7de7e58",
"coin_mint": "B8xtQz9CK7xr56dboGx8gL2Zu4dB2MiydFe4b8NPpump",
"coin_name": "My Life Is Solana",
"symbol": "Solana",
"chain": "solana",
"user_name": "thirty300",
"x_username": "gaynes_g",
"thesis": "Solana $105 — my life is Solana",
"called_out_at_mcap": 29240.0,
"multiple": 0.595,
"pnl_percentage": -28.76,
"callout_timestamp": "2026-08-27T09:55:15.528Z",
"last_activity": "2026-08-27T09:58:32.242Z",
"updates": [
{
"user_name": "thirty300",
"thesis": "All the reasons not to sell the dust...",
"callout_timestamp": "2026-08-27T09:58:32.242Z"
// ...same fields as a top-level row
}
],
"convergence": { "fomo": 0, "pumpfun": 3 }
// ...plus every field in the table below
}
],
"total": 10960
}
| Field | Description |
|---|---|
| callout_id | Unique ID for this callout or update. |
| entry_type | callout for a top-level post, update for a threaded reply (only appears inside updates). |
| parent_callout_id | Set on updates only — the callout_id they're threaded under. |
| coin_mint / coin_name / symbol / coin_image / chain | Token identity. |
| market_cap | Token market cap at time of discovery. |
| user_id / user_name / profile_image / wallet_address | Caller identity. |
| is_verified | 1 if pump.fun shows a verified badge on the caller, else 0. |
| x_username / x_profile_image / follower_count | Caller's linked X account, if any. |
| thesis | The callout or reply text. |
| called_out_at_mcap | Token market cap at the moment this was posted — compare to current market_cap for "since call" movement. Null on updates. |
| multiple | Token price growth multiple since the call (market performance — not the caller's own entry price). Null on updates. |
| callout_timestamp | ISO8601 UTC timestamp this was posted. |
| likes / view_count / repost_count / comment_count | Engagement counts at time of discovery (not re-checked afterward). |
| value_usd / cost_basis_usd | Caller's current position value and cost basis in USD. |
| pnl_usd / pnl_percentage | Caller's own PnL on this specific position (their real entry price, not the call-moment price). |
| max_multiplier | Highest multiple this callout has reached since being posted. Null on updates. |
| discovered_at | When CommRadar's own scraper first saw this (not the same as callout_timestamp). |
| last_activity | Top-level rows only — whichever is more recent, the callout itself or its newest update. This is what the feed sorts by. |
| updates | Top-level rows only — array of threaded replies, oldest first, same field shape minus updates/last_activity/follow_up_count. |
| follow_up_count | Top-level rows only — updates.length, provided so you don't have to count the array yourself. |
| is_kol | true if x_username matches a handle on CommRadar's own curated X KOL List (the same list /api/v1/x-calls is sourced from). Reflects our own list-import bookkeeping, not a live X membership check — added 2026-08-29, see "Known limitations" below. |
| convergence | Top-level rows only — {"fomo": N, "pumpfun": M, "x": K, "both_apps": bool}, unique callers (deduped by X handle, or wallet if unlinked) who mentioned this same token on each platform in the last 15 minutes. both_apps is true when both fomo and pumpfun are non-zero. Always live/real-time, even on the delayed tier. |
Token mentions from X (Twitter), real-time -- tweets from a curated KOL list that mention a resolvable token. A tweet only counts as a call if it contains either a raw contract address, or a $CASHTAG that resolves unambiguously against fomo/pumpfun's own recent ticker history. An ambiguous or unresolvable cashtag (no match, or the ticker collides across more than one real token) is dropped rather than guessed at -- a missed tweet is a gap, a wrong token attached to someone's real call is a correctness bug. Cashtag-only chatter with no resolvable token, and tweets with no token mention at all, never appear here.
| Param | Type | Default | Description |
|---|---|---|---|
limit | int | 50 | Max rows to return (capped at 200). |
before | string | — | A tweet_created_at value from a previous response — returns tweets older than it, for pagination. |
chain | string | — | Filter to one chain (e.g. solana). |
curl "https://commradar.xyz/api/v1/x-calls?limit=1" \ -H "X-API-Key: YOUR_KEY"
{
"rows": [
{
"tweet_id": "1234567890123456789",
"author_handle": "gsksolana",
"tweet_text": "This is the $CATE community...",
"image_url": null,
"avatar_url": "https://pbs.twimg.com/profile_images/.../abc_normal.jpg",
"token_address": "Ai66LHZG9MCzg1WKdawwqduVAXpNDUuV8M3uyq5ppump",
"chain": "solana",
"extraction_source": "cashtag_resolved:fomo",
"tweet_url": "https://x.com/gsksolana/status/1234567890123456789",
"tweet_created_at": "2026-08-27T13:21:37.000Z",
"discovered_at": "2026-08-27T13:22:04.118203+00:00",
"convergence": { "fomo": 2, "pumpfun": 1, "x": 1 }
}
],
"total": 340,
"list_member_count": 105
}
| Field | Description |
|---|---|
| tweet_id | The tweet's own ID. |
| author_handle | Caller's X handle, no @. |
| tweet_text | Full tweet text (fetched from the tweet's own page -- X's timeline view truncates long tweets, so this is never the clipped preview). |
| image_url | First attached image, if any. Null for text-only tweets or ones whose only media is a link-preview card, not an uploaded photo. |
| avatar_url | Caller's profile picture at time of discovery. |
| token_address / chain | The resolved token. See extraction_source for how it was resolved. |
| extraction_source | How the address was found: text_address (raw address in the tweet), pumpfun_link / birdeye_link / solscan_link (a direct token-address link), or cashtag_resolved:fomo / cashtag_resolved:pumpfun (a $CASHTAG matched against that feed's recent ticker history). |
| tweet_url | Link to the tweet on x.com. |
| tweet_created_at | ISO8601 UTC timestamp the tweet was actually posted (not when CommRadar saw it). |
| discovered_at | When CommRadar's own scraper first saw this (not the same as tweet_created_at). |
| convergence | {"fomo": N, "pumpfun": M, "x": K, "both_apps": bool}, unique callers who mentioned this same token on each platform in the last 15 minutes. both_apps is true when both fomo and pumpfun are non-zero. Always live/real-time, even on the delayed tier. |
Alongside the usual rows and total, this endpoint also returns list_member_count -- the current real size of the curated KOL list this feed sources from (checked directly against X roughly every 15 minutes). It's a measure of coverage, not of this specific response's row count.
Every call for one specific token, real-time, merged across all three platforms and sorted newest first. Pass an exact contract address for an unambiguous match, or a ticker/symbol (e.g. CATE) as a convenience -- since tickers aren't unique, a symbol search can surface multiple distinct tokens that happen to share a name; each result still shows its own real address so it's easy to tell them apart. Ticker search only matches fomo/pumpfun -- x-calls has no raw ticker field, only already-resolved addresses, so an address search is the only way to reach x-calls rows.
curl "https://commradar.xyz/api/v1/token/Ai66LHZG9MCzg1WKdawwqduVAXpNDUuV8M3uyq5ppump" \ -H "X-API-Key: YOUR_KEY"
Same shape as /api/v1/fomo-feed, /api/v1/pumpfun-callouts, and /api/v1/x-calls rows, merged into one list -- each row also carries a _source field ("fomo", "pumpfun", or "x") so you can tell which platform it came from. pump.fun rows here are flat, not threaded -- entry_type: "update" replies show up as their own individual rows instead of nested under a parent, since for "who's talking about this token" every reply is a real post by a real person.
Every call by one specific caller, real-time, merged across all three platforms. Matches on handle (with or without the @) -- x_username on pump.fun and author_handle on x-calls are real X handles, but user_handle on fomo is the caller's fomo.family account handle, not their X handle. A fomo caller only merges with their pump.fun/x-calls activity here if their fomo handle happens to match their X handle.
curl "https://commradar.xyz/api/v1/caller/gaynes_g" \ -H "X-API-Key: YOUR_KEY"
Same response shape as the token endpoint above.
Top 5 tokens right now by rolling 15-minute distinct-caller count across fomo.family and pump.fun (the same 🔥 mechanic shown on the live demo -- a call landing is +1, a call aging out past 15 minutes is -1, so this reorders live). X is excluded from this particular ranking by design. Each token comes with live price_usd/market_cap/price_change_24h from DexScreener already attached.
curl "https://commradar.xyz/api/v1/trending-tokens" \ -H "X-API-Key: YOUR_KEY"
{"tokens": [...]} -- each entry has token_address, chain, ticker, image, fomo/pumpfun (distinct-caller counts feeding the total), total, both_apps (true when both fomo and pumpfun are non-zero -- added 2026-08-29), plus the DexScreener fields above.
fomo.family callers ranked by win rate (min. 3 calls to qualify, override with min_calls). Important: every PnL figure in this product is frozen at the moment a call was scraped and never re-checked afterward -- this is not a live-updated or outcome-verified win rate, it's a snapshot ratio. Treat it as a rough signal, not a guarantee.
curl "https://commradar.xyz/api/v1/fomo-top-callers?limit=10&hours=24" \ -H "X-API-Key: YOUR_KEY"
| Param | Description |
|---|---|
min_calls | Minimum calls to qualify. Default 3. |
limit | Default 5, max 50. |
hours | Optional. Window the ranking to calls made in the last N hours (e.g. hours=24) instead of the default lifetime scope. Added 2026-08-29 -- ranking methodology is unchanged (still win rate, not $ value); this only narrows the time window it's computed over. |
Same as /api/v1/fomo-top-callers above, for pump.fun callers, plus the same hours param. Same frozen-at-scrape-time caveat applies. Each row also carries is_kol (see /api/v1/pumpfun-callouts row fields for what that reflects).
curl "https://commradar.xyz/api/v1/pumpfun-top-callers?limit=10&hours=24" \ -H "X-API-Key: YOUR_KEY"
Top individual KOL positions by $ value, across fomo.family and pump.fun. Not a sum -- each row is one caller's single largest known position on one token, deduped to their latest snapshot per (caller, token) pair. This sidesteps a real problem elsewhere in this product: the same real position gets re-logged as a new row on every repost/update (confirmed live -- one caller had 24 rows on one token), so summing raw position rows massively inflates the true number. Nothing here is added together, so that problem doesn't apply. Still frozen-at-scrape-time like every other $ figure in this product -- a position's value is whatever it was worth the moment it was last seen, not a live mark-to-market number. Added 2026-08-29.
curl "https://commradar.xyz/api/v1/top-kol-positions?limit=10&hours=24" \ -H "X-API-Key: YOUR_KEY"
| Param | Description |
|---|---|
hours | Window to look for positions in. Default 24. |
limit | Default 15, max 50. |
| Field | Description |
|---|---|
| source | fomo or pumpfun. |
| caller_handle / caller_name / caller_avatar | Caller identity. For fomo, caller_handle is fomo's own account handle, not necessarily a real X handle. |
| token_address / chain / ticker / token_image | Token identity. |
| position_value_usd | The single position snapshot value this row was ranked on. |
| market_cap | Token market cap as of this snapshot. |
| called_out_at_mcap | pump.fun only -- market cap at the moment of the original call. Always null for fomo rows; fomo has no equivalent distinct entry-MC field. |
| is_kol | pump.fun rows only -- see /api/v1/pumpfun-callouts row fields. Always false for fomo rows (can't reliably KOL-match fomo's handle). |
| ts | ISO8601 UTC timestamp of this snapshot. |
A missing or invalid X-API-Key returns 401 with {"error": "missing or invalid API key"}. There's no rate limit enforced yet — please keep polling reasonable (once every 15-20s is plenty; that's what the live demo itself does).
Provisioned per-partner on request. Rather than polling, we push each new row to your URL the instant it's written — this is the low-latency option if you need calls as they happen, not on a fixed interval. A short-poll cadence against the REST endpoints above still works fine and remains available as a reconciliation fallback (e.g. to catch anything during downtime on your end).
{
"event_id": "a8b51b6f-59af-479c-a8b9-ea9d92b9a08c",
"event_type": "fomo_feed_post",
"sent_at": "2026-08-27T14:21:38.382523+00:00",
"data": { ... same row shape as the matching REST endpoint ... }
}
| event_type | fomo_feed_post (fomo.family), pumpfun_callout or pumpfun_callout_update (pump.fun — mirrors the entry_type split on /api/v1/pumpfun-callouts), or x_call (X). |
| data | Same field names as the row-level fields documented above for that platform, but only the raw fields captured at insert time. Not included on webhook events (GET-endpoint-only, computed at request time, not at insert time): convergence (and its both_apps flag), pump.fun's follow_up_count and nested updates array (updates arrive as their own pumpfun_callout_update event instead), and is_kol. If you need any of these, poll the matching REST endpoint rather than relying on the webhook payload alone. |
Every request carries an X-CommRadar-Signature header: sha256= followed by the HMAC-SHA256 hex digest of the raw request body, keyed with your webhook secret. Verify against the raw bytes before parsing JSON.
import hashlib, hmac expected = "sha256=" + hmac.new(SECRET.encode(), raw_body, hashlib.sha256).hexdigest() if not hmac.compare_digest(expected, request.headers["X-CommRadar-Signature"]): raise Exception("invalid signature")
| X-CommRadar-Signature | sha256=<hex digest>, as above. |
| X-CommRadar-Event | Same value as the payload's event_type, for routing without a JSON parse. |
| X-CommRadar-Delivery | Matches event_id — use as an idempotency key, since retries reuse the same id. |
Any response outside 2xx, or a timeout, is retried up to 3 attempts total (immediate, then +2s, then +10s). Respond 2xx as soon as the delivery is durably received on your end — do your own processing after responding, not before, so a slow handler doesn't read as a failed delivery and trigger a redundant retry. A delivery that still fails after all 3 attempts is logged to a dead-letter file on our side, not automatically retried again — if a delivery is missing, tell us and we can check/replay it manually, or just poll the REST endpoint as a reconciliation fallback (a call is never dropped from the data itself, only from the push side).