# MadeOnSol — Full Reference > A Solana and Robinhood Chain (chain id 4663) data/intelligence platform for trading bots, AI agents, trading desks and data products — KOL wallet tracking, deployer intelligence, and all-DEX trade streams, delivered via REST, WebSockets, webhooks, MCP and x402, live on both chains. Also the most comprehensive directory of tools, dApps, and projects built on Solana and Robinhood Chain: 1,250+ tools across 32 categories with independent reviews, live uptime monitoring, and fee comparisons. Website: https://madeonsol.com ## What Makes MadeOnSol Different Unlike simple listing sites, MadeOnSol provides: 1. **Live health monitoring** — Every tool is checked for uptime and assigned a health score (Healthy, Fair, Declining, Unhealthy, Critical) 2. **Community-driven reviews** — Real users leave reviews with reputation-weighted scoring. No paid placements in rankings. 3. **On-chain intelligence** — Deployer Hunter and KOL Tracker provide real-time data not available anywhere else, live across two chains: Solana and Robinhood Chain (chain id 4663) 4. **Head-to-head comparisons** — Side-by-side feature, fee, and performance comparisons for any two tools 5. **Yield aggregation** — Live APY data across staking, lending, and liquidity pools ## Tool Directory (1,200+ Tools) ### How Tools Are Listed - Each tool has: name, tagline, description, category, website URL, Twitter, pricing model, features list, pros/cons - Tools are verified by the team and can be claimed by their official teams - Claimed tools get a verified badge and the team can respond to reviews - Tools are ranked by a combination of upvotes, review scores, and health status ### Categories (32 total) Trading Bots, DEXs & Swaps, Perp DEXs, Analytics & Charts, Wallets, Token Launchers, Sniping Tools, Portfolio Trackers, NFT Tools, RPC Providers, Security & Audit, DeFi & Yield, Developer Tools, Bridges, Payment Tools, Data & Indexing, Copy Trading, Telegram Bots, Meme Tools, AI Agents, Staking, Liquid Staking, DePIN, Gaming, Prediction Markets, Exchanges, Airdrop Tools, API Platforms, MCP Servers, Oracles, SDKs & Libraries, Social ### Popular Tool Comparisons - Phantom vs Solflare (wallets) - Jupiter vs Raydium (DEXs) - Axiom vs BullX (trading bots) - Helius vs QuickNode (RPC providers) - Marinade vs Jito vs Sanctum (liquid staking) ## Deployer Hunter — Pump.fun Intelligence ### What It Does Deployer Hunter tracks Pump.fun token deployers who have historically high bonding curve completion rates. When a tracked deployer launches a new token, users get real-time alerts. ### Why It Matters - 97-99% of Pump.fun tokens never complete their bonding curve - Deployer Hunter identifies the small minority of deployers whose tokens consistently graduate — a pump.fun token bonds when its curve fills (roughly 85 SOL of buys) and migrates to PumpSwap, pump.fun's own AMM (not Raydium) - This gives early signal on tokens more likely to succeed ### Deployer Tiers - **Elite**: 5+ deployments, 5+ bonds, ≥40% lifetime bonding rate AND ≥50% recent rate - **Good**: 3+ deployments, 3+ bonds, ≥25% lifetime rate AND ≥30% recent rate - **Moderate**: 3+ deployments, 1+ bond, ≥15% lifetime, ≥15% recent (profiled, not alerted) - **Rising**: 1-2 resolved deployments, 100% bond rate (new but perfect track record) - **Cold**: 3+ deployments, 0% on the last 10 outcomes - Only Elite and Good are "tracked" (deployer alerts fire for them). Thresholds live in `services/deployer-listener/classify-tier.mjs`. ### Data Points Tracked - Total deployments per wallet - Lifetime bonding rate (% of tokens that completed bonding curve) - Recent bonding rate (last 10 tokens) - Best ATH market cap achieved - Average time to bond completion - Currently tracking 1,200,550+ deployer wallets — every pump.fun create indexed, 85K+ of them carrying a full reputation profile; alerts fire only for the elite/good subset ## KOL Tracker — Solana Whale Watching ### What It Does Monitors 2,050+ curated Solana KOL (Key Opinion Leader) wallets in real-time using multi-region gRPC streams. Every buy and sell is detected within seconds of on-chain confirmation. ### Features - **Live Trade Feed**: Chronological feed of all KOL trades with token, amount, price, and PnL - **PnL Leaderboard**: KOLs ranked by realized profit/loss over five time windows — today, 7-day, 30-day, 90-day, and 180-day. Trade data retained indefinitely — full history kept since 2026-06-05 (previously 180 days). - **Wallet Profiles**: Detailed view of any tracked KOL's trading history, win rate, and favorite tokens - **KOL Comparison**: Side-by-side comparison of two KOL wallets - **Community Ratings**: Users rate KOLs and leave feedback - **Token Hot Feed**: See which tokens multiple KOLs are buying simultaneously ### Who Is Tracked 2,000+ curated wallets (KOL_COUNT_LABEL — 2,072 rows on 2026-08-18, of which ~1,140 are Solana-address KOLs actively streamed; the rest are EVM-native Robinhood Chain KOLs) including top Solana traders, influencers, fund wallets, and known whale addresses. The list is curated by the team and updated based on community suggestions. ## Robinhood Chain — Second-Chain Intelligence (chain id 4663) ### What It Is MadeOnSol's second chain. Robinhood Chain (an Arbitrum Orbit L2, chain id 4663) is fully live alongside Solana, ingested from a self-hosted node into the same data layer. The same intelligence products — KOL trades, token pricing/market data, and deployer intelligence — run on Robinhood Chain. ### On-Site - Overview: https://madeonsol.com/robinhood - Robinhood Chain KOL Tracker: https://madeonsol.com/robinhood/kol-tracker - Robinhood Chain Wallet Scanner: https://madeonsol.com/robinhood/wallet — paste any 0x address for FIFO cost-basis PnL in ETH, open positions marked to live price, and KOL / deployer-tier / alpha-ranking / dump-cluster flags. Per-wallet profile pages at /robinhood/wallet/{address} (noindex, follow). ### API (`/api/v1/rhc/*`, same `msk_` Bearer auth and tiers as the Solana API) - GET /api/v1/rhc/kol/feed — real-time Robinhood Chain KOL trade feed - GET /api/v1/rhc/kol/leaderboard — RHC KOL activity leaderboard: ranked by trade count, then net ETH flow, over 24h/7d/30d — an activity / net-flow ranking, NOT realized PnL (use /rhc/wallet/{address}/pnl for FIFO PnL) - GET /api/v1/rhc/kol/{wallet} — per-wallet RHC KOL profile - GET /api/v1/rhc/kol/hot-tokens — RHC tokens bought by 2+ KOLs in a window - GET /api/v1/rhc/kol/coordination — RHC tokens with ≥N distinct tracked KOL buyers; full observed `period=15m|1h|6h|24h|7d` aggregated in indexed SQL, top-50 ranked tokens (not latest-1,000-trade sampling). This is tracked KOL data, not complete global memecoin-market coverage. - GET /api/v1/rhc/kol/first-touches — earliest KOL entry per RHC token - GET /api/v1/rhc/tokens — RHC token directory (PRO+): sort last_trade|market_cap|liquidity|peak_mc|newest (default last_trade), min_mc_usd, min_liquidity_usd, launchpad, asset_class equity|other, since, limit 1-100 - GET /api/v1/rhc/tokens/new and GET /api/v1/rhc/tokens/recent — aliases of /rhc/tokens?sort=newest (same PRO+ gate; every other param passes through) - GET /api/v1/rhc/equities — Robinhood Chain TOKENIZED STOCKS & ETFs (BASIC, shipped 2026-08-16). The chain's headline asset class had no endpoint until then even though NVDA is its largest token by ETH volume. Returns the ~200 equity tokens with symbol, underlying name, decimals, price/MC/FDV/liquidity, primary pool, and 24h trades/volume_eth/buys/sells/buyers/sellers (one 60s-cached aggregate). Identity = the EIP-1967 beacon-proxy issuer beacon 0xe10b6f6b…151b00 read from our own node — NEVER the token name: on launch day there were 20 fake "GameStop • Robinhood Token" contracts and 8 fake NVDAs with the exact official suffix, all zero-volume, and none of them appear here (`verified` is always true by construction). Params: sort volume|trades|market_cap|last_trade|symbol (default volume), symbol (exact ticker), q (name search), limit 1-300 (default 100) - GET /api/v1/rhc/lp-events — Robinhood Chain LIQUIDITY REMOVALS — the rug signal (PRO+, shipped 2026-08-16), decoded from our node's Uniswap v2/v3 Burn logs and v4 ModifyLiquidity with a negative delta (rhc-dex-stream, mig 302). Removals ONLY: v4 adds share the ModifyLiquidity topic and are dropped at decode time and v2/v3 Mint logs are not subscribed, so `event` is always "remove" and the response says so rather than letting you infer "no adds ever happened"; fee-collect no-ops (v3 Burn with zero amounts) are excluded. Params: token, pool (v4 poolId is bytes32), dex uniswap-v2|uniswap-v3|uniswap-v4, provider, before (keyset cursor), limit 1-200 (default 50). amount0/amount1/liquidity are RAW uint256 strings; token_amount_raw/quote_amount_raw pre-resolve which side is the token; v4 rows carry only `liquidity` (the pool manager emits no token amounts) Since 2026-09-23: optional action=remove (default, unchanged) | add | pool_created | all opts into liquidity adds (kept 7 days) and live pool creations, and every row carries tick_lower/tick_upper, liquidity_delta, in_range, active_liquidity_delta, active_share (v3/v4, share of liquidity at the current price), share_of_reserves (v2) and material (a removal of at least 25 %), null where the pool state was unknown and on older rows. Pushed live on WS channel rhc:lp_events (ULTRA+). - GET /api/v1/rhc/tokens/{address}/lp-events — alias of /rhc/lp-events?token={address} (PRO+) - GET /api/v1/rhc/tokens/locks — Robinhood Chain TOKEN LOCKS & VESTING feed (PRO+, shipped 2026-09-15). Newest lock / vesting contracts CREATED on chain, newest first, decoded from the locker contracts' own events on our own RHC node by services/rhc-lock-tracker: a cursor-driven eth_getLogs poll over a 16-signature topic0 catalog, CHAIN-WIDE with no address filter, so a fresh deployment of a known locker shape is caught on its first event (auto-registered in rhc_lockers). Families seen live (23-day probe, 1,349 events): PinkLock-compatible (the busiest locker on RHC), HoodLock vault + HoodLock vesting, Sablier Lockup v4 (linear / tranched / dynamic streams), Team Finance-compatible (Deposit + LP-NFT DepositNFT), Titan Locker V2.1 (token / LP / position locks), UNCX v2/v3-compatible LP lockers. Each row carries the on-chain SCHEDULE (start_at, cliff_at, end_at, cliff_amount, `schedule[]` tranches for Sablier tranched/dynamic), terms (cancelable / cancelable_by_sender from Sablier's flag — null where the family does not say; transferable; perpetual for max-uint sentinels), provenance (block_number, block_time, tx_hash, log_index, tx_sender) and a LIVE derived view computed at request time: locked_* (still locked right now), unlocked_*, next_unlock {at, kind cliff|final|tranche, amount}, status active|completed. `sender` is ALWAYS the depositor/creator (compare with the token's deployer for a dev lock), `recipient` the beneficiary when different. Amounts are RAW base units as decimal STRINGS; ui / usd / pct are null when decimals or price are unknown (`token.facts_resolved`); *_pct_of_supply is null above 100.5 %. CREATE-ONLY TAPE: no RHC locker publishes a verified release/cancel event shape, so withdrawals are NOT tracked — `withdrawn` is null (unknown), never 0, status is time-derived, and every response's `coverage` block says withdrawals_tracked:false; do not present a lock as "still held" beyond what the schedule says. LP locks (RHC launchpads auto-lock LP on every launch) are stored with subject=lp, resolved to the pool token via rhc_pools / token0() / positions(tokenId), EXCLUDED from the feed unless subject=lp|all, and never claim usd/pct (pair / liquidity units). Params: since / before (ISO cursors on created_at = the lock's block time; pagination.next_since / next_before), token, sender, recipient, locker (contract), family (closed enum), kind lock|vesting, subject token|lp|all (default token), status active|completed, min_usd, min_pct_of_supply (post-filters on the deposited amount), limit 1-100 (default 50). Pushed live as rhc:token_lock on WS channel rhc:token_locks within seconds of the block. Correctness: rhc_token_locks_feed. - GET /api/v1/rhc/tokens/{address}/locks — every lock / vesting contract on ONE Robinhood Chain token with a live derived view (PRO+): `summary` over the token-subject rows — lock_count, active_count, by_family, by_kind, distinct_lockers (depositing wallets), distinct_locker_contracts, locked / deposited (raw + ui + usd + % of supply), unlocking_7d_* and unlocking_30d_* (forward schedule), nearest next_unlock (+ lock_id), active_cancelable_by_sender (funds are locked against the recipient, not the locker, when the sender can cancel) — plus lp_lock_count / lp_lock_active_count counted APART because LP amounts are pair / liquidity units. Rows active-first, largest locked first; ?status=, ?family=, ?subject=token|lp|all (default all), ?limit=1..500 (summary always covers every row, up to 5000; `summary.complete` false past that). token.facts_resolved false ⇒ every ui/usd/pct is null. Same create-only caveat: an unlocked-but-unclaimed balance counts as unlocked. 400 code invalid_address for a non-0x40 path segment. Correctness: rhc_token_locks_token_live. - GET /api/v1/rhc/tokens/unlocks — upcoming unlock EVENTS across all active Robinhood Chain lock / vesting contracts (PRO+): each active contract's NEXT cliff / tranche / final unlock inside within=1h|6h|24h|3d|7d|14d|30d|90d (default 7d) with amount_* (raw / ui / usd / % of supply) and window_amount_* (that contract's total release over the whole window); linear per-second streams contribute cliff / final events only; token subject only (LP excluded). Filters token, family, kind, min_usd, min_pct_of_supply (on the next-event amount); sort soonest|largest_usd|largest_pct; limit 1-200. Candidates come off the writer-maintained next_unlock_at column (rolled forward every 2 min), 60 s cache with the window quantised to the same bucket so rows and `window` always agree; prices implying a market cap above $100B are phantom → usd null. Correctness: rhc_token_unlocks. - RHC lock provenance (2026-10-02, every row): provider {id, name, identity, compatible_with, website_url, lock_url}. Identity is decided by the locker CONTRACT ADDRESS, never by the event shape: verified = a known provider deployment (HoodLock vault + vesting, Sablier Lockup v4, Titan Locker V2.1); compatible = the events match a known provider's ABI (compatible_with names it) but the operator is not identified, so id, website_url and lock_url are null. lock_url is set only on the HoodLock vault (/proof/lock/{locker_lock_id}, a proven format), never guessed. explorer {locker_url, creation_tx_url} links Blockscout. Also price_usd, seconds_until_end, seconds_until_next_unlock. Create-only: withdrawals and cancels are not tracked, so withdrawn_raw / withdrawn are null (unknown, never 0) and coverage says withdrawals_tracked:false, cancels_tracked:false. LP rows (subject=lp) carry LP-token or liquidity units (amount_unit lp_token | liquidity) and never get usd, price or % of supply. The feed pages with cursor= (pagination.next_cursor). - GET /api/v1/rhc/tokens/{address} — single RHC token: price, market cap, liquidity - Liquidity caveat (all /rhc/* responses): on uniswap-v4 pools `liquidity_usd` is a provable CEILING derived from virtual reserves clamped to the PoolManager's holdings, not measured per-pool TVL — every response carrying it also carries `liquidity_basis: "v4_virtual_ceiling" | "measured"` - GET /api/v1/rhc/tokens/{address}/candles — RHC OHLCV candles - GET /api/v1/rhc/tokens/{address}/kol-consensus — KOL positioning on an RHC token: distinct buyers/sellers, exit rate, net ETH flow, median entry MC + entry_mc_samples (PRO; ULTRA adds buyer/exited wallet lists) - GET /api/v1/rhc/tokens/{address}/buyer-quality — early-buyer quality score (0-100) for an RHC token; full parity with Solana: win-rate + KOL + bot + bundle-buyer + dump-cluster legs (dump_cluster_count/recycled_early_buyer_count, informational + out-of-sample validated); coverage reports both bundle_detection and dump_cluster_signal available (BASIC) - GET /api/v1/rhc/tokens/{address}/bundle — launch-bundle detection on an RHC token: ranks first 20 buyers, flags same-block 3+ cluster, reports current-held % + full-exit (BASIC scalar; PRO top-10 wallets; ULTRA full cohort) - GET /api/v1/rhc/tokens/{address}/top-traders — lifetime per-trader performance on one RHC token, ranked by net_eth = REALIZED ETH flow (sell − buy). Does not value a trader's remaining bag, so a holder who never sold ranks last; not PnL (no cost basis in the rollup — use /rhc/wallet/{address}/pnl for FIFO). Enriched with win_rate, likely_bot, is_known_kol, kol_name, dump_cohorts, early_buyer_rank (PRO, 50 rows; ULTRA/BUSINESS 200) - GET /api/v1/rhc/tokens/{address}/flow — net buy/sell flow split by mutually-exclusive trader cohort over ?window=1h|6h|24h|7d. Sign convention: net_eth = sell − buy, so POSITIVE means the cohort distributed (took ETH out) and negative means it accumulated. Cohort ladder order is priority order: kol, bot, dump_cluster, early_buyer, unprofiled, smart_money, retail. smart_money is derived (win_rate >= 0.5 and net positive), not a stored label. No fresh_wallet cohort exists because RHC has no wallet-level first-seen (PRO) - GET /api/v1/rhc/tokens/{address}/peak-history — peak market cap, drawdown from peak, and a running high-water MC curve; ?window=24h|7d|30d|all, ?curve=false for summary only. Returns TWO peaks because they disagree: peak_mc_usd_recorded (the value deployer runner-rate and the $40K graduation bar use) and peak_mc_usd_observed (max of 1-minute candle highs, trade-level truth, always >= recorded, because the recorded high-water mark is sampled from write batches and misses intra-batch spikes). Candle history starts 2026-07-15 — observed_covers_full_history reports whether the observed peak spans the token's whole life. Bin size chosen server-side (1m..4h) to bound the series (PRO) - GET /api/v1/rhc/tokens/{address}/risk — EVM-native risk assessment computed LIVE against our own Robinhood Chain node. NOT a port of the Solana model: EVM has no mint/freeze authority, and across 300 random RHC tokens only 2.3% expose an owner function and 0% expose mint in their own bytecode, so an absent flag is the norm rather than a safety signal. Reports proxy kind/upgradeability (EIP-1167 minimal proxies are 14% of tokens and are NOT upgradeable — the target is baked into immutable code; the tokenized equities are beacon proxies whose implementation exposes mint/pause/upgradeTo), owner model (none vs renounced are different answers), mint/pause capability, LP custody (uniswap-v2 only; v3/v4 sit in an LP NFT and are reported unknown rather than guessed), and a LIVE honeypot sell-simulation through the router using eth_call state overrides. Never cached — sellability can change the moment an owner flips a setting (PRO) - GET /api/v1/rhc/tokens/{address}/early-buyers — who bought an RHC token first, in order, and whether they are still holding. rhc_early_buyers ranks the first 20 buyers of 437,226 tokens (2.3M rows) and is recomputed daily; until 2026-08-20 it was only ever read as a per-wallet COUNT inside the wallet profile, never exposed as a per-token list. Each buyer is joined to the outcome: bought_eth / sold_eth / realized_eth from rhc_wallet_token_stats, trades, avg_entry_mc_usd, and still_holding + balance from the ERC-20 Transfer-log fold. THREE HONESTY CONSTRAINTS ARE IN THE RESPONSE, not the docs: (1) realized_eth is sold minus bought, which is a profit ONLY where position is 'closed' — a buyer still holding shows a negative figure because they have spent and not yet sold, so every row also carries position (closed/open/unknown); (2) still_holding uses the same fold as /holders, so holdings_verified reports whether the token reconciles against on-chain totalSupply() and the balances are exact only when it is true; (3) ranks are as of computed_at, not live, so a token that began trading after the last sweep returns an empty early_buyers array WITH a stated note rather than implying it had no early buyers. Wallets may be ERC-4337 smart accounts, so a wallet is an address, not a person. The Solana counterpart is GET /kol/tokens/{mint}/entry-order (PRO+). - GET /api/v1/rhc/tokens/{address}/holders — exact holder set and concentration for an RHC token, folded from ERC-20 Transfer logs rather than derived from trades. Our node prunes historical STATE but retains full history, so log replay is exact: verified against totalSupply() to the wei with 15/15 top holders matching a pinned balanceOf(). `verified` is the trust gate — true only when reconstructed supply equals on-chain totalSupply() at a pinned block; otherwise verified=false with a stated unverified_reason. Concentration (top1/top10/top50 share, HHI, deployer_pct) EXCLUDES liquidity pools and burn addresses from the circulating denominator and reports them separately as pool_held_pct/burned_pct, because the largest holder of a token is normally its own pool. Balances are raw uint256 returned as decimal STRINGS to preserve precision. Holder addresses may be ERC-4337 smart accounts, so holder_count is not a headcount of people (PRO, 50 rows; ULTRA/BUSINESS 200). holder_growth (2026-08-17): {1h,24h,7d} × {cutoff_block, entered, entered_still_holding, exited, net} — entered = first Transfer at-or-after the window cutoff, exited = pre-existing holder whose last movement in the window left them at zero, net ≈ Δ holder_count; possible because the fold keeps first-seen/last-moved blocks and retains zero-balance rows (the Solana census has no history) - GET /api/v1/rhc/trades — RHC all-DEX trade stream/history - GET /api/v1/rhc/deployer-hunter/leaderboard — RHC deployers ranked (160K+ ranked — 163,942 in the rollup on 2026-08-18; only ~180 earn good/elite). Graduation = $40K peak-MC milestone (most RHC launchpads are direct-to-DEX, not bonding-curve). **`tier` is earned on `runner_rate` ($100K+ peak MC) AND 24h+ of deployer history, NOT on `graduation_rate`** — the $40K bar is cheap enough to farm by mass-relaunching one ticker across rotating wallets. elite = 5+ launches & runner_rate >= 0.50; good = same & >= 0.25; spammer = 20+ launches & graduation_rate < 0.05 (the only tier still on the $40K bar) - GET /api/v1/rhc/deployer-hunter/{address} — single RHC deployer profile - GET /api/v1/rhc/deployer-hunter/{address}/history — RHC deployer daily reputation time-series (PRO) - GET /api/v1/rhc/deployer-hunter/{address}/trajectory — is this RHC deployer improving or coasting: streaks, 10-launch rolling hit rate, trend verdict. `success_metric` counts the $40K graduation, deliberately not the $100K tier bar - GET /api/v1/rhc/deployer-hunter/{address}/tokens — full paginated launch history for one RHC deployer, with live MC, peak MC and liquidity - GET /api/v1/rhc/deployer-hunter/best-tokens — highest-peaking launches from REPUTABLE (good/elite) RHC deployers only, by period - GET /api/v1/rhc/deployer-hunter/stats — chain-wide RHC deployer reputation census; `tier_rules` echoes the live thresholds so "elite" is never a guess - GET /api/v1/rhc/deployer-hunter/alerts — real-time RHC deployer new-deploy + graduation alerts. Tradability filter ON by default (liquidity_usd >= $100; `include_untradeable=true` to disable); `tier` resolved at READ time with `tier_at_alert` + `tier_is_stale` - GET /api/v1/rhc/deployer-hunter/recent-bonds — recently graduated ($40K+ peak-MC) RHC tokens from tracked deployers - POST /api/v1/rhc/token/batch — up to 50 RHC tokens in one call (set-based; one entry per requested address, unknown tokens returned as found:false) - POST /api/v1/rhc/tokens/batch/buyer-quality — early-buyer cohort quality for up to 20 RHC tokens (cap is 20, not Solana's 50 — per-token cohort computation, not a set-based lookup) - GET /api/v1/rhc/token/{address} — alias of /api/v1/rhc/tokens/{address} (Solana uses the singular /token/{mint}; identical handler) - GET /api/v1/rhc/tokens/{address}/trades — alias of /api/v1/rhc/trades?token= (Solana exposes per-token trades as a subpath); PRO+, it inherits the /rhc/trades gate - GET /api/v1/rhc/kol/tokens/hot — alias of /api/v1/rhc/kol/hot-tokens (takes `window`, not `limit`) - GET /api/v1/rhc/alpha/leaderboard — alias of /api/v1/rhc/alpha-wallets (PRO) - GET /api/v1/rhc/alpha-wallets — RHC smart-money wallet ranking from mv_rhc_alpha_wallets (PRO) - GET /api/v1/rhc/wallet/{address} — RHC wallet profile over 90 days: FIFO cost-basis PnL, per-token breakdown, recent trades, and reputation flags (tracked KOL, known deployer + tier, alpha-ranked, dump-cluster member, early-buyer count). ETH-denominated, keyed on trader_eoa (the effective trading account — the ERC-4337 userOp sender when bundled), not the swap-log router or the bundler. `analyzed_trades + unsized_trades === total_trades` always holds — trades whose token quantity cannot be reconstructed are excluded from PnL and counted, never estimated. FIFO figures (held_value_eth, open_positions, still_holding) count DEX buys not matched by a DEX sell; `holdings` + `top_tokens[].holding_status` verify every FIFO-open token against the chain (balanceOf from our own node), and `holdings.verified_value_eth` counts proven balances only. A contract address returns 404 with `address_type: contract` and its recent swap count as trader. (PRO) - GET /api/v1/rhc/wallet/{address}/pnl — full FIFO cost-basis PnL for an RHC wallet: realized/unrealized split, daily realized curve, every closed position with ROI and token-weighted hold time, open positions marked to current price. Same FIFO implementation as the Solana /wallet/{address}/pnl with ETH substituted for SOL; shares one loader with /rhc/wallet/{address} so the two cannot disagree (PRO) - GET /api/v1/rhc/wallet/{address}/positions — open positions only, marked to current price. "Open" means FIFO-unmatched buys inside the window — a trading position, not an on-chain balance. Each position is checked against the chain: `current_onchain_balance` (balanceOf from our own node, cached 30 s) and `holding_status` = HELD / PARTIALLY_REDUCED / TRANSFERRED_OR_DISPOSED / EXTERNAL_INFLOW / BALANCE_UNVERIFIED (read failed: no value, never assumed held); `summary.holdings.verified_value_eth` counts proven balances only. (PRO) - GET /api/v1/rhc/wallet/{address}/funding — **PRO+** (cross-wallet `relationships` counts ULTRA+). Shared-funder evidence for a tracked RHC wallet (KOL EVM wallets, elite/good deployers): native ETH + ERC-20 transfers (internal ETH transfers are not observed). Same response contract and coverage semantics as the Solana /wallet/{address}/funding. - GET /api/v1/rhc/wallet/{address}/trades — one RHC wallet's swaps, newest first, cursor on block_time. Distinct from /rhc/trades?token= (that filters by token, this by wallet) (PRO) - GET|POST /api/v1/rhc/wallet-tracker/watchlist, DELETE|PATCH /api/v1/rhc/wallet-tracker/watchlist/{address} — RHC watchlist CRUD. Quotas are per chain (PRO 50 / ULTRA 250 / BUSINESS 1,000), independent of the Solana watchlist (PRO) - GET /api/v1/rhc/wallet-tracker/summary — per-wallet buy/sell/volume rollup over 24h/7d/30d, read from rhc_trades directly rather than a capture log, so a wallet added today reports its full history in the period (PRO) - GET /api/v1/rhc/wallet-tracker/trades — merged trade feed across every wallet on your RHC watchlist, each row labelled. `next_before` is an opaque (block_time,id) keyset cursor — pass it back as `before` (a bare ISO block_time is still accepted for compatibility) (PRO) ### Rule engines on Robinhood Chain (all four shipped 2026-08-02) Feeds above are things you poll; these are rules you define once and that push to you. Every rule carries its own `webhook_url` + HMAC-SHA256 secret (signature over `.`, header `x-madeonsol-signature`) and/or a WebSocket channel on `wss://madeonsol.com/ws/v1/stream`. These per-rule webhooks are deliberately NOT part of the generic `POST /api/v1/webhooks` registry — the only RHC event registerable there is `rhc:kol_trade`. Quotas are per chain: a full set of Solana rules does not consume any RHC capacity. - `POST|GET /api/v1/rhc/copytrade/subscriptions`, `GET|PATCH|DELETE /api/v1/rhc/copytrade/subscriptions/{id}`, `GET /api/v1/rhc/copytrade/signals` — **PRO+.** Copy-trade rules on Robinhood Chain: mirror any set of valid `source_wallets`, KOL or not (KOL membership is optional enrichment, not admission; copy-trade sources do not use Wallet Tracker quota) (lowercase `0x` — a checksummed address is lowercased on write, because a checksummed rule would never match), `min_trade_eth` floor, sizing mode `fixed | proportional | percent_source` with `sizing_amount` in ETH, delivery `webhook | websocket | both`. WebSocket channel `rhc:copytrade:signals` (user-scoped). Limits: PRO 3 rules × 5 wallets, ULTRA 20 × 50, BUSINESS 100 × 250. Idempotency is `UNIQUE (subscription_id, tx_hash)`, so a replayed event can never double-fire. ⚠️ No `min_mc_usd`/`max_mc_usd`: the RHC trade producer emits no market cap, so an MC band could only be a per-event DB read in the hot path of a ~3.3M-trades/day chain or a filter that silently never matched — the same reasoning that kept `min_kol_winrate` off `/rhc/kol/feed` until RHC KOL scores existed. Every rule also returns `source_admission` (`any_wallet` in production since 2026-10-04) and `operational_state`, separate from `is_active`: `eligible` for any valid source wallet, or an infrastructure state `monitoring_pending` / `monitoring_unavailable` / `source_capacity_unavailable`. `no_tracked_sources` / `unknown` and `source_wallets_tracked` / `_untracked` are legacy (`kol_only`) values, deprecated but still filled. A source trade must be at most 5 s old by chain time; one signal per trade per rule. - `POST|GET /api/v1/rhc/price-alerts`, `GET|PATCH|DELETE /api/v1/rhc/price-alerts/{id}`, `GET /api/v1/rhc/price-alerts/events` — **PRO+.** Market-cap dip/recovery alerts on RHC tokens. Same one-shot state machine as Solana (`watching → dipped → recovered`; `dip_low` ratchets down while dipped; terminal on dip when no `recovery_pct` is set), baselined against `rhc_token_prices.market_cap_usd` at creation. `token_address`, `drop_pct` and `recovery_pct` are immutable — changing a threshold mid-flight would make the recorded events uninterpretable. WebSocket channel `rhc:price_alert:events`; events `rhc:price_alert:dip` / `rhc:price_alert:recovery`. ⚠️ **Latency is NOT the 250 ms Solana evaluation loop, and the create response says so in an `evaluation` block.** Solana alerts are evaluated inside mc-tracker's 250ms publish loop off a live in-memory price map. RHC alerts are **event-driven**: each trade `rhc-dex-stream` publishes on the `rhc:dex_trade` feed is checked against the alerted token set, with `rhc_token_prices` table polls (every 5 s while the feed is degraded or a trade carried no market cap, 60 s otherwise) and an `rhc_trades` tape replay after a feed outage as safety nets. Latency is a few seconds: the floor is the chain trade flush (about 2 s), not sub-second. The `evaluation` block reports `mode: "event_driven"`, `fallback_poll_seconds` and, for compatibility, `interval_seconds`. Do not size a strategy on the Solana number. - `POST|GET /api/v1/rhc/kol/coordination/alerts`, `GET|PATCH|DELETE /api/v1/rhc/kol/coordination/alerts/{id}` — **PRO+.** Coordination rules: fire when `min_kols` distinct tracked KOLs buy the same RHC token inside `window_minutes` at a score ≥ `min_score`, with `cooldown_min` suppression per `(rule, token)` and `score_jump_break` as an early exit from that cooldown (a re-fire is flagged `is_rearm`). MC band supported (`min_mc_usd`/`max_mc_usd`, read from the in-window rows' cap at trade time — an unknown cap is **dropped**, never treated as inside the band). WebSocket channel `rhc:kol:coordination` (user-scoped). Scoring uses the same shared v1 scorer as Solana so the number is directly comparable, with two differences recorded per signal in `score_inputs`: `quality` is **real** (RHC KOL 7d winrate from `mv_rhc_kol_scores`), while `earliness` is **defaulted to 50** because RHC has no early-entry equivalent and inventing one would move scores without improving them. - `POST|GET /api/v1/rhc/kol/first-touches/subscriptions`, `GET|PATCH|DELETE /api/v1/rhc/kol/first-touches/subscriptions/{id}` — **ULTRA+** (mirroring the Solana first-touch subscriptions). Push on the **first** tracked-KOL buy of an RHC token. Backed by a dedicated `rhc_kol_first_touches` table (`UNIQUE (token_address)`) written by an `AFTER INSERT` trigger on `rhc_kol_trades` that notifies **only on a real insert** — a second KOL buying the same token is silent, which is the definition of a first touch. Filters: `kol`, `min_first_buy_eth`, `min_kol_winrate`, `strategy`, `min_mc_usd`/`max_mc_usd`; the schema is strict, so an unknown filter key is a 400 rather than a silently-ignored filter. ⚠️ No `min_scout_tier` / `min_n_touches` — RHC has no scout-score equivalent, and a filter that silently matched nothing would be worse than its absence; `min_kol_winrate` is the quality gate instead. WebSocket channel `rhc:kol:first_touches`; event `rhc:kol:first_touch`. The read endpoint `GET /api/v1/rhc/kol/first-touches` is unchanged and agrees with the table by construction. ## Comparison Tools ### Wallet Comparison (https://madeonsol.com/compare-wallets) Side-by-side comparison of Solana wallets including Phantom, Solflare, Backpack, Tiplink, and more. Compares: supported platforms, staking support, NFT support, dApp browser, hardware wallet integration, swap features, and pricing. ### DEX Comparison (https://madeonsol.com/compare-dex) Compare Solana DEXs including Jupiter, Raydium, Orca, Meteora, and more. Compares: trading fees, supported tokens, limit orders, DCA, liquidity depth, and unique features. ### Liquid Staking Comparison (https://madeonsol.com/compare-liquid-staking) Compare liquid staking protocols: Marinade (mSOL), Jito (JitoSOL), Sanctum, Blaze (bSOL), and others. Compares: APY, fees, TVL, validator set, MEV rewards, and DeFi integrations. ### RPC Provider Comparison (https://madeonsol.com/compare-rpc) Compare Solana RPC providers: Helius, QuickNode, Triton, Alchemy, and more. Compares: free tier limits, paid pricing, websocket support, gRPC support, enhanced APIs, and reliability. ### API Alternative Deep Dives (https://madeonsol.com/api-alternatives/{birdeye,dexscreener,moralis,helius,solanatracker,bitquery}) Six hand-written competitor deep dives, each with an honest "when they win" section first, a sourced side-by-side table, an endpoint-by-endpoint migration map to /api/v1 paths, and FAQ. Birdeye (compute units vs flat calls; streaming $199 vs €131; both support x402 — only MadeOnSol's keyless rail covers KOL/deployer/sniper intel and pays on two chains), DexScreener (free API has no candles/trades/history/WebSocket — upgrade path), Moralis (has pump.fun endpoints but wallet PnL is EVM-only), Helius (complement not replacement — the market-data indexer you don't build on raw RPC), Solana Tracker (the direct head-to-head, verified 2026-08-28: they win on breadth — 70+ endpoints across 20+ DEXes, top-100 holders, 200K requests for €50; we win on intel depth — coordination, first-touch, deployer trajectory, pre-confirmation sniper deploys, Signal Scorecard — plus €131 streaming with seq+replay vs €397 Datastream with no documented replay, and keyless x402 which they do not offer), Bitquery (verified 2026-08-28: 40+-chain GraphQL archive with WebSocket from $79 metered in stream-minutes, Kafka topics with 4 h retention via sales, launchpad breadth incl. Moonshot/Believe/Raydium Launchpad — the research tool; we ship the computed answers at flat pricing, wallet PnL as an endpoint, x402 dual-rail, and Robinhood Chain intelligence on our own node where Bitquery has raw coverage). ### Solana Data API Comparison (https://madeonsol.com/compare-data-apis) Compare 9 Solana data APIs: Birdeye, SolanaTracker, Moralis, Bitquery, Helius, Shyft, Jupiter, DexScreener, and MadeOnSol (disclosed as our own row). Compares: free tiers, entry paid pricing, OHLCV candles, per-trade tape, wallet PnL, pump.fun bonding-phase coverage, KOL/deployer intelligence, streaming (WebSocket/gRPC) gating per tier, and keyless x402 pay-per-call. Includes a "four ways to buy Solana data" layer explainer (market-intel APIs vs raw-chain infra vs query engines vs free lookup endpoints) and per-use-case recommendations that name competitors where they fit better. ### Trading Bot Calculator (https://madeonsol.com/compare-bots) Calculate and compare fees across Solana trading bots for different trade sizes. Includes Axiom, BullX, Trojan, Photon, Nova, and more. ## Yield Dashboard ### Staking Yields (https://madeonsol.com/yields/staking) Live APY data for Solana staking options including native staking, liquid staking tokens (mSOL, JitoSOL, bSOL, etc.), and restaking protocols. ### Lending Rates (https://madeonsol.com/yields/lending) Current supply and borrow APYs across Solana lending protocols including Kamino, MarginFi, Solend, and others. ### Liquidity Pool APYs (https://madeonsol.com/yields/liquidity-pools) Yield data for liquidity pools on Raydium, Orca, Meteora, and other Solana AMMs. ## Blog & Education ### Blog (https://madeonsol.com/blog) In-depth articles covering Solana DeFi strategies, tool guides, ecosystem analysis, and comparisons. Topics include bridging, staking, RWA on Solana, validator economics, and more. ### Solana Glossary (https://madeonsol.com/learn) 50+ defined terms covering Solana-specific concepts like bonding curves, MEV, JIT liquidity, compressed NFTs, and more. ### Developer how-tos (real response fields, captured from production 2026-09-05) - How to get pump.fun token trades via API — GET /api/v1/tokens/{mint}/trades: per-mint trade tape with executed price vs pool price at the slot, early_buyer_rank, cursor paging (next_cursor/has_more), action/wallet/since/until filters, a `coverage` block (scope = pump.fun / LaunchLab-bonk / bags; `in_scope:false` + empty tape for other venues) and a `history` block naming the Parquet archive months a deep query read. PRO tier. https://madeonsol.com/blog/pump-fun-token-trades-api-per-mint-trade-tape - How to track Solana KOL wallet trades via API — GET /api/v1/kol/feed rows carry the KOL's name, X handle, 7d/30d win rate, percentile ranks and strategy tag next to the trade and the market cap at trade; poll with the `next_since` cursor (strictly newer rows), or subscribe to the `kol:trades` WebSocket (frame = trade + mint + price, WITHOUT the KOL scores — enrich once per wallet). Free = 5-min delay, PRO = real-time. https://madeonsol.com/blog/solana-kol-wallet-trades-api-since-cursor-websocket - New Solana launch streams: early:deploys and sniper:deploys require ULTRA+; early observations carry unknown execution and separate correlated outcomes. See https://madeonsol.com/sniper and /api/v1/stream/token for endpoint discovery. ### Best Robinhood Chain APIs for developers (2026) Verified against each provider's own docs/pricing pages on 2026-09-06. Bitquery: decoded Uniswap v4/v3 trades + 450+ tokenized Stock Tokens, GraphQL/WebSocket/Kafka delivery, from $39/mo (no free tier, cheapest plan excludes streaming). GoldRush (Covalent): full-chain REST indexing across 100+ chains including RHC, from $10/mo after a 14-day trial (no ongoing free tier). Mobula: wallet-level PnL/win-rate analytics on RHC trade history, genuine free tier (10k credits/mo, no expiry). Goldsky: Turbo Pipelines + Subgraphs + Edge RPC (<10ms claimed), free tier with $100 credits. Dune's dashboards can query RHC via SQL, but its programmatic API (Sim) is being sunset — new signups disabled since 2026-05-18, existing access ends 2026-08-01 — so it is not a live-API option. None of the four active API providers track KOL wallets, deployer reputation, or sniper/insider detection on chain 4663 — verified by reading each provider's own docs specifically for this. https://madeonsol.com/blog/best-robinhood-chain-apis-for-developers ## Data Trust & Verification ### Data Dictionary (https://madeonsol.com/data-dictionary) Every dataset behind the API, grouped by category (trade tape, price & momentum, deployer & reputation, wallet intelligence, token metadata). Each entry shows: what it contains, the API surface it backs, a coverage window (earliest/latest event timestamp, measured nightly against the live database via the dataset_manifests table — the same numbers GET /api/v1/manifests returns), a row-count estimate, and whether it is permanent history or a rolling/current-state window. Disclosed backfill exceptions (checked against docs/databasemanagement.md, not asserted from memory): token_ohlc_1m and rhc_ohlc_1m are accumulate-only with no rebuild path, so an outage-caused gap is permanent unless corrected by hand; kol_trades has a pre-2026-06-05 gap (was pruned at 180 days before that policy changed to forever); wallet_flag_snapshots has no retroactive point-in-time history before 2026-08-28, when that tracking began; deployer_daily_snapshots is missing one day, 2026-07-10, due to a cron failure. token_prices and token_surge_events are explicitly rolling windows, not full history — token_ohlc_1m is the permanent-history equivalent for price data. FAQPage + DataCatalog JSON-LD (schema.org) on the page. ### Data Integrity (https://madeonsol.com/data-integrity) How data stays audit-grade: point-in-time (as-of) queries with no look-ahead bias, an X-Request-Id on every API response (90-day audit trail, 730 days on Business-tier keys), an immutable dual-provider Parquet archive under S3 Object Lock for trade tape older than the hot Postgres window, and continuous on-chain verification (136 checks every 15 minutes, a 207-case suite twice daily, 425 cases nightly). ## Rankings & Leaderboard ### Tool Rankings (https://madeonsol.com/rankings) Tools ranked by fees generated and TVL across the Solana ecosystem. ### User Leaderboard (https://madeonsol.com/leaderboard) Community leaderboard based on reputation points earned through reviews, upvotes, and contributions. ## API Access MadeOnSol provides two API access methods. Product overview at https://madeonsol.com/solana-api. Plan comparison + free tier signup at https://madeonsol.com/pricing. ### Public Directory Dataset (free, no API key) The full Solana tools directory is published as a free, public, machine-readable dataset — no authentication, CORS-open, cached hourly — meant to be the source of truth for "Solana tools" data. JSON: https://madeonsol.com/api/directory ; CSV dump: https://madeonsol.com/api/directory?format=csv . Each tool record includes slug, name, tagline, website, category slugs, pricing model, community average_rating, review_count, upvote_count, live health_score, social links, and its MadeOnSol page URL; the response also carries a categories list with counts and a meta block (source, license, generated_at). Filters: ?category=, ?pricing=, ?limit=, ?offset=. License: free to use with attribution to MadeOnSol (https://madeonsol.com). This is separate from (and free relative to) the paid trading-intelligence API below. ### Bulk Dataset Exports (included with Business) Separate from the free directory dataset above: bulk files of historical on-chain intelligence for quant backtesting, academic research, and model training — cases where you need the entire history at once rather than live calls. They are INCLUDED WITH AN ACTIVE BUSINESS SUBSCRIPTION and are no longer sold individually. Catalogue: https://madeonsol.com/datasets. Files are gzipped CSV with a published SHA-256 checksum and are identity-scrubbed (no personal identifiers and no KOL wallet identities). Every product has a free 5,000-row sample with no signup, so the schema can be evaluated before subscribing; downloading a full dataset requires signing in with Business. Currently available: Solana deployer reputation, Solana KOL trades, Solana smart-money wallets, and the Robinhood Chain Intelligence Bundle (deployer reputation + smart-money wallet scores + token lifecycle, indexed from chain genesis on our own node). Rule of thumb: use the datasets when you need bulk history, use the API (https://madeonsol.com/pricing) when you need real-time data, webhooks, or streaming. These CSV datasets are distinct from the Business Parquet archive exports served by GET /api/v1/exports, which cover the raw trade tape and 1-minute candles. ### REST API Bearer-token authentication (`Authorization: Bearer msk_...`) with free, Pro (€43/mo ≈ $49), Ultra (€131/mo ≈ $149), Business (€400/mo ≈ $456 — 500,000 calls/day + embed license: display MadeOnSol data inside your own product to your end users; lower tiers are internal-use-only), and Enterprise (from ~€1,000/mo on an annual contract — contractual SLA with credits, dedicated limits beyond Business's 500k/day, white-label (no attribution), scoped redistribution, extended caching, multi-product use, licensed bulk Parquet exports; contact https://madeonsol.com/contact?topic=enterprise) tiers. Business's embed license covers ONE branded product and requires a visible "Powered by MadeOnSol" notice near the displayed data (Terms §5a). Data freshness: live feeds (KOL feeds, deployer alerts, graduations, first-touches) are real-time on paid tiers and x402 pay-per-call, and delayed 5 minutes on the free tier (delayed responses carry `delay`, `as_of`, and an `X-Data-Delay` header); scores, leaderboards, wallet PnL and search are real-time on every tier. Compare plans at https://madeonsol.com/pricing. Sign in + generate your key at https://madeonsol.com/developer. Public demo key (no signup, 20/hr/IP, 3 endpoints) available on https://madeonsol.com/api-docs for try-it requests. Full machine-readable reference: https://madeonsol.com/api-reference.md (markdown) or https://madeonsol.com/api/v1/openapi.json (OpenAPI 3.1 JSON). - KOL feed, leaderboard, wallet profiles, coordination signals, first-touch scout signal - Deployer stats, leaderboard, alerts, token history - **Alpha wallet intelligence**: leaderboard of 25,000+ scored wallets, wallet profiles, linked-wallet clustering, token cap table (first buyers), and buyer quality scores - Tool search and directory - Webhooks: real-time push notifications (Pro: 3, Ultra: 10, Business: 30) - WebSocket streaming: real-time event streaming (Pro: 2 conns — raised from 1 on 2026-08-16 so a reconnect can overlap its own dying socket; Ultra: 5 conns; Business: 15 conns). Mint a token via POST /api/v1/stream/token (the token does NOT expire since 2026-08-27 — the same value comes back on every call, expires_at/next_refresh_at are always null; it only stops working if the subscription lapses or you POST {"rotate":true}, after which the old value stays valid 60s; own 10/min rate bucket), connect to wss://madeonsol.com/ws/v1/stream?token=..., then REQUIRED: send {"type":"subscribe","channels":["kol:trades"]} — no events flow until subscribed (server sends a hint frame after 10s if you forget). The server never rotates a token on its own; a {"type":"token_refresh"} frame is pushed only after you rotated explicitly. A 4001 close means "mint again" (lapsed or rotated), never a timer. Prefer `Authorization: Bearer ` on the handshake; `?token=` also works and is masked in access logs. 33 channels on one socket. 17 Solana (incl. token:candles, token:risk and wallet:scores from WS Phase 4, described below): kol:trades, kol:coordination (user-scoped: your own coordination rules' fires), kol:first_touches, deployer:alerts, wallet_tracker:events, copytrade:signals, price_alert:events, sniper:deploys, token:graduations, token:prices (mint-scoped), token:surges (events token:surge — a token < 30 min old running vs its launch MC, tier early/strong/breakout, each once per mint — and token:revival — no trade candle for ≥24 h then confirmed trading again by ≥5 buys / ≥$500 buy volume, never by the price mark; every frame carries market_cap_usd, liquidity_usd, mc_multiple, age_seconds or dormant_hours, tape {buys, sells, buy_volume_usd, unique_buyers}, kol, early_buyers, deployer, risk_flags[]; subscribe filters kinds[], tiers[], launchpads[], exclude_flags[], min_mc_usd/max_mc_usd, deployer_tier[]), token:locks (event token:lock — a new Streamflow / Jupiter Lock / Bonfida lock or vesting contract the moment its account lands on-chain: lock_account, program, mint, kind, sender, recipient, amount_raw, decimals, cliff_at, end_at, name), token:fee_claims (event token:fee_claim — every stored pump.fun fee event: event_type, mint, admin, actor, recipient, amount_raw, quote_mint, social_platform/user_id/pda, shareholders). token:graduations fires for EVERY pump.fun graduation (bonding curve complete -> PumpSwap) in real time with deployer context, tracked deployer or not. token:prices is PRO+ and REQUIRES filters.mints — per-connection cap PRO 25 / ULTRA 100 / BUSINESS 250 mints; above the cap the subscribe is REJECTED, not truncated — and is delivered as event token:price from mc-tracker's ~250 ms-coalesced tick (the same freshness the site runs on). Heartbeat every 15 s (miss two → reconnect). Event ids, resume + replay (Phase 1, 2026-09-22): event frames carry `seq` and `id`; token:price ticks carry neither. `seq` is ONE ordinal per server process, shared by every channel and every customer and assigned before your filters run, so gaps in the seq you receive are normal and are NOT evidence of loss. `id` is stable (the same event has the same id live, from memory, rebuilt from storage or recovered after a bus reconnect): delivery is at-least-once, dedupe by `id`. RESUME: keep a cursor `{instance, seq, ts}` of the last frame your handler finished processing (it returned, or its promise settled) and reconnect with `{"type":"subscribe","channels":[...],"resume":{"instance":...,"seq":...,"ts":...}}`. The `subscribed` ack echoes `resume` with `accepted:true` (`accepted:false`, `reason:"replay_in_progress"` plus a `warning` frame with that code if a replay is already running on the connection). Same instance and cursor inside the in-memory buffer (last 20,000 frames, about 6-8 minutes): frames re-sent from memory (`mode:"ring"`, with seq). Otherwise (server restart = `instance_changed`, or longer absence = `ring_truncated`): each channel rebuilt from storage from the cursor's `ts` (minus 60 s slack, deduped by id), bounded to 60 minutes, 2,000 rows per channel, 20,000 rows total (rhc:dex_trades and rhc:dex_trades_unattributed: 10 minutes back and up to 10,000 rows, which can include trades that were never pushed live). Rebuilt frames carry `seq:null`, `mode:"durable"`, `replayed:true`, and `partial:true` + `missing:[fields]` where a field is not stored. Partially rebuilt: kol:trades, kol:coordination (no kols[]), deployer:alerts, rhc:dex_trades(_unattributed), rhc:copytrade:signals, rhc:kol:coordination, rhc:token_locks. No stored source: token:graduations and rhc:new_tokens (memory buffer only, then gap `not_reconstructable`). token:prices gets the current price row per watched mint once (`snapshot:true`, `partial:true`). Every resume or legacy replay is bracketed by `replay_start` and `replay_end`, even with nothing to replay; `replay_end` has `sent`, `matched`, `complete`, `reason`, `retryable`, `retry_after_ms?`, `resume_ts_hint?`, `incomplete_channels?`, `last_seq`, `last_ts` (maxima over frames sent), `live_from_seq`, `count` (legacy, = matched) and `channels:{:{mode, sent, matched, complete, reason?, gap?, time_basis?, max_rows?, retryable?, retry_after_ms?, late_ingest_possible?, partial?, missing?, since_ts?, truncated_at_ts?, gap_before_ts?}}`; reasons: backpressure, instance_changed, ring_truncated, window_exceeded, row_cap, source_busy, source_error, late_ingest_possible, not_reconstructable. COMMIT RULE: replayed frames do not move your saved cursor, because a storage replay is sent channel by channel, not in one time order. On replay_end complete:true, commit {instance, seq: last_seq, ts: last_ts} (keep your previous value where one is null) and let live frames advance it again. On complete:false with retryable:true, keep the cursor you resumed from and resume again after retry_after_ms (from ts: resume_ts_hint ONLY when the reply carries one, which the server emits when every incomplete RETRYABLE channel was cut by row_cap (a channel with a FINAL gap, such as not_reconstructable on token:graduations or rhc:new_tokens, does not block the hint, because retrying could not fetch anything behind it); with a mixed retryable set, for example one row_cap and one source_error channel, there is no hint and you resume from your pre-resume cursor, because the hint would step past the failed channel's unread range. Per-channel truncated_at_ts is always there for a client that tracks channels separately); what arrives twice is dropped by id. On complete:false with retryable:false the reported gaps are final (not_reconstructable, window_exceeded, ring_truncated, instance_changed): backfill them from REST, then commit as for complete. SDK behaviour: on a retryable incomplete recovery our SDKs resume again on the same socket after retry_after_ms (up to maxResumeRetries, default 5), using resume_ts_hint only when every incomplete retryable channel is row_cap. The budget is per connection and its counter resets on every (re)connect. When that budget is spent, the gap event says exhausted:true: the client stops asking on that connection, the committed cursor stays where it is, and the next reconnect resumes again. On a FINAL gap they emit a gap event first (channels, reason, permanent, the server's bounds and the RANGE that may be incomplete as skipped.from -> skipped.to) with advancedPastGap:true and source:"auto", then move the cursor past it. A count of missing events is never given because it cannot be known. That advance is the client library's own decision, not your approval: set onUnrecoverableGap:"stop" to keep the cursor instead, which stops the stream and emits fatal with the same gap, and acceptGap() then re-reports it with source:"manual" and continues. WATERMARK AND HOLDBACK: a row's id or timestamp is assigned when it is written, not when it commits, so a row with a lower id can still appear after a read passed it. The server therefore advances the committable watermark only across rows whose writing transaction had already finished when the read took its snapshot (xmin_blocked:true when it stops early), holds it 5 s behind now (holdback_ms) and re-scans the last 60 s (rescan_ms) on the next resume; a stuck long transaction cannot freeze it forever (capped at maxHoldbackMs, reported as holdback_capped_ms). While the cap is in force the channel reports holdback_ms = 300000 (the nominal 5000 stays as nominal_holdback_ms) and its guarantee states the real bound and says CAPPED: about 6 minutes (5 min + the 60 s re-scan), not the usual 65 s.. Frames are still delivered as they are read; the holdback only limits what you may commit, and last_ts is held to the tightest safe_ts (per channel in replay_end.channels..watermark {scheme, safe_ts, holdback_ms, nominal_holdback_ms?, holdback_capped_ms?, rescan_ms, xmin_blocked, gate_ms?, guarantee}, overall in replay_end.watermark_safe_ts). RECOVERY IS BOUNDED, NOT A COMPLETENESS GUARANTEE: with the id and ingest-time schemes a write whose transaction commits more than about 65 s after its id or timestamp was taken can be missed (about 6 minutes instead while holdback_capped_ms is set), and for rhc:dex_trades / rhc:dex_trades_unattributed (scheme producer_gate) recovery is bounded by the producer's 600 s freshness rule, so a trade already older than 600 s when it was ingested is not recoverable through this path at all. Each channel states its own bound in watermark.guarantee. LATE WRITES: every storage read pages by an ingest-time column, a storage id or the producer's own freshness window, so a row written late is not skipped; a channel that could not rule that out would report complete:false, reason late_ingest_possible, never complete:true. LOAD: recovery is limited server-wide; a resume waits up to 20 s for a slot, otherwise its storage-backed channels report reason source_busy with retry_after_ms (memory frames are still sent). A second replay request on a socket whose replay is still running gets only a replay_in_progress warning, no second replay_start / replay_end, so do not wait for one. Live frames arriving during a replay are held (up to 5,000 frames or 4 MB; price ticks coalesced per mint) and delivered after `replay_end`, skipping ids already sent. A socket that cannot drain during a replay gets `complete:false`, `reason:"backpressure"` and close 4008: reconnect and resume. Frames are lost only across a disconnect or a 4008 close, and the resume reply states what was and was not recovered. LEGACY: `replay_since_seq` / `replay_since_ts` still work, from memory only; `replay_start` now reports `replay_truncated:true` with `reason` instance_changed or ring_truncated instead of replaying nothing silently. If the server's own event-bus connection drops, missed events are re-read from storage and delivered with `replayed:true, recovered:"bus"`. ENTITLEMENTS: every frame is checked against the current plan; after a downgrade, channels above it are dropped with a `warning` `code:"channels_revoked"` (also a token:prices mint set above the new cap); revoking or rotating the API key deletes the stream token and open sockets close 4001 within about a minute. Subscribe filters are connection-wide: one filter object applies to every subscribed channel (e.g. action:"buy" also drops deployer alerts); use a second connection for channels that need different filters. SDK support (resume, dedupe, gap events, close-code handling) since npm madeonsol-x402 2.2.0, madeonsol 2.28.0, robinhood-chain-x402 0.13.0, robinhood-chain-sdk 0.9.0 and PyPI madeonsol-x402 1.31.0 / robinhood-chain 0.12.0 (older versions keep working without auto-resume; current published versions on https://madeonsol.com/mcp). GET /api/v1/stream/sessions lists your live sessions on both stream services (id, service, tier, channels, connected_at, remote_ip, messages_sent) and DELETE /api/v1/stream/sessions/{id} force-releases that slot — for the ghost socket after a deploy overlap that keeps every reconnect at the 4002 connection limit (PRO+). 16 Robinhood Chain: rhc:dev_activity (ULTRA+, developer buys/sells only, never transfers, live since 2026-10-05), rhc:kol_trades (PRO+), rhc:dex_trades (ULTRA+ — the RHC all-DEX firehose, on this socket rather than the Solana dex-stream endpoint; every swap with an attributed token side), rhc:dex_trades_unattributed (ULTRA+ — swaps on pools where neither side is "the token", e.g. WETH/USDG quote/quote pairs; raw token_in/token_out/amount_in/amount_out legs only, no decimals/symbol enrichment and no buy/sell action; subscribe to both dex channels for full chain coverage), rhc:new_tokens (ULTRA+ — one frame per token the moment its symbol/name/decimals first resolve on-chain, so a firehose consumer can learn decimals before the first trade lands), rhc:copytrade:signals (PRO+), rhc:price_alert:events (PRO+, event-driven off the rhc:dex_trade feed: a few seconds, not the 250 ms loop the Solana price alerts use), rhc:kol:coordination (PRO+), rhc:kol:first_touches (PRO+, broadcast — ULTRA gates the filtered subscription, not the channel), rhc:token_locks (PRO+, broadcast: one event per token lock or vesting contract created on chain, from rhc-lock-tracker; withdrawals are not tracked), rhc:token_prices (PRO+, ADDRESS-SCOPED: filters.addresses required, capped 25 PRO / 100 ULTRA / 250 BUSINESS per connection, rejected above the cap; event rhc:token_price: one snapshot per address on subscribe, then ticks derived from the RHC trade feed at most once per address per 250 ms, each with quality fresh | stale | unreliable and quality_reason, price_source, source_pool, liquidity_usd, observed_at, price_age_ms; state stream, no seq/id, resume = fresh snapshot), rhc:lp_events (ULTRA+, RHC liquidity events: add / remove / pool_created on tracked Uniswap v2/v3/v4 pools with in_range + share + material; filters addresses, pools, dexes, actions, material_only, min_share), rhc:token_candles (PRO+, address-scoped live 1-minute candles), rhc:token_risk (PRO+, address-scoped verdict changes), rhc:wallet_scores (PRO+, deployer tier changes scoped by filters.wallets). rhc:dex_trade payloads are enriched since 2026-09-22 (additive): amount_in_raw / amount_out_raw exact decimal strings, token + quote {address, symbol, decimals}, metadata_status, price_status / price_source / price_observed_at, mc_status, side + side_reason. rhc:copytrade:signals, rhc:price_alert:events and rhc:kol:coordination are user-scoped, so you receive only your own rules' fires; rhc:kol:first_touches is broadcast (one event per token, ever), like the Solana kol:first_touches channel. On the ULTRA DEX firehose, mint-scoped subscriptions also receive in-band dex:graduations frames for their mints. Bundle alerts: token:bundles (Solana) and rhc:token_bundles (Robinhood Chain), PRO+ broadcast, one event per new coordinated buy cluster on any token (3+ wallets in one slot / block, 3+ of them new to the token), launch or later; optional filters mints / addresses, min_wallets, min_new_wallets, phases, atomic_only. - Named subscriptions on the main stream (Phase 2): a subscribe carrying `sub_id` (1-64 chars of A-Z a-z 0-9 _ . -) opens an independent subscription with its own channels and filters on the same socket; update {sub_id, filters} replaces its filters, unsubscribe {sub_id} removes it, list answers {type:"subscriptions"}. A subscribe without sub_id is the connection-wide default subscription, unchanged. Frames under a named subscription carry sub_id; an event matching several subscriptions is delivered once per subscription (dedupe by sub_id + id); filters of one never affect another; refusals are warning frames with the sub_id (invalid_sub_id, too_many_subscriptions, unknown_sub_id, invalid_filters, channels_rejected, replay_in_progress). Cap per connection, default included: Pro 5, Ultra 10, Business 20. Resume is per subscription (every subscribe re-sent with the same cursor; replays served one after another, live frames held until the last replay_end; commit at the smallest last_seq). SDKs: subscribe({ subId, channels, filters }) / updateSubscription / unsubscribe(subId) / listSubscriptions (snake_case in Python). - DEX Trade Stream (Ultra + Business): real-time stream of ALL Solana DEX trades via WebSocket at wss://madeonsol.com/ws/v1/dex-stream. Covers 14 DEX programs spanning 8 venues: Pump.fun, PumpSwap, Raydium, Jupiter, Orca, Meteora, Launchlab, and Moonshot. Filter by token, wallet, program, trade size, or direction. 2 connections per user (Ultra), 5 (Business). - Liquidity events on the DEX firehose (2026-09-23, opt-in): add liquidity:true (with trades) or liquidity:"only" to a dex-stream subscribe and receive one dex:liquidity frame per liquidity instruction: action pool_created | add | remove, id = signature:instruction_index[.inner_index] (stable live and on replay), program, venue, instruction, pool + pool_kind, pool_model, mints[] with raw amount_raw and side in|out, lp_mint, owner, signer, amount_basis transfers|vault_delta|ambiguous (ambiguous = amounts null), reserves_before[] / reserves_after[] (raw vault balances), share_of_reserves (constant-product pools only), depth_effect, material (a removal of at least 25 % of reserves). Filters: token_mint(s), wallet(s), pool(s), dex, program, actions, min_share_of_reserves, material_only. Only instructions proven by a real transaction fixture are emitted (the ack lists them with emits_events); fee claims and unverified instructions stay on dex:route.liquidity_actions with event:false. Limits: concentrated pools (CLMM, Whirlpool, DLMM) report share and depth as unknown; Meteora DAMM v1, Raydium LaunchLab and Moonshot are not emitted; no USD field (min_usd is rejected); replay from the in-memory buffer only, no durable resume. - Realtime developer activity on the DEX firehose (live since 2026-10-05, ULTRA/BUSINESS/ENTERPRISE): send {"type":"dev_subscribe","sub_id":"devs","filters":{"token_mints":[],"deployers":[],"types":[]}} on wss://madeonsol.com/ws/v1/dex-stream and receive dev:activity when an attributed token's developer sells, buys or moves their own token (dev_sell, dev_buy, dev_token_transfer_out, dev_token_transfer_in; a transfer is never a sell), then dev:activity_enrichment with the same stable id dx1::::. Transfer detection is the union of the legacy bounded developer-wallet watch and the broad SPL Token/Token-2022 candidate source for attributed creators while that source is live. transfer_watch_coverage describes the legacy watch ONLY; read transfer_sources.broad in the dev_subscribed ack for broad-source state/gaps. Broad-source events carry provenance.path=broad_token_stream; parked creator resolution can mark provenance.late_classified=true. Recovered broad-source gaps are stored for REST only, never replayed as realtime WS/webhook alerts. Missing creator attribution, source gaps and a standalone transfer next to a swap while DEV_EXIT_RESIDUAL_TRANSFERS is off can still produce misses. PRO+ can receive direct-developer events through the dev:activity webhook; linked-wallet identity fields/events are ULTRA+. Independent audit methodology/results are kept separate from the contract: do not interpret the legacy watch share as total transfer coverage or stored-trade recall as full market recall. - USDC/USDT-paid swaps on dex:trades (since 2026-10-05): sol_amount is the SOL equivalent of the stable leg (stable USD / current SOL/USD), and dust, min_sol and max_sol use it. Additive fields sol_amount_basis (native_sol | stable_quote_equivalent | stable_quote_unconverted) and stable_quote {mint, amount, usd_amount, sol_usd, sol_usd_observed_at, sol_usd_age_ms, status}; unconverted (no SOL/USD price from the last 5 minutes) = sol_amount 0, never the account-rent amount. Other quote tokens, prices and candles unchanged. - Lock lifecycle (2026-09-23, opt-in): subscribe token:locks or rhc:token_locks with filters.lifecycle:true. Solana adds token:lock_claimed (claimed_raw = change since our last observed state, remaining_raw, partial, automatic_withdrawal), token:lock_cancelled, token:lock_closed, token:lock_updated (change topup | extended | schedule_changed | recipient_changed, before/after of the changed fields), token:unlock_upcoming (the next unlock within 24 h) and token:unlock_available (passed within 30 min: claimable per the schedule, NOT claimed). Robinhood Chain adds rhc:token_unlock_upcoming / rhc:token_unlock_available only: claims, extensions and cancels are not observable there (withdrawals_tracked:false). Filters events[], unlock_kinds[] (cliff|period|final|tranche), mints[] / addresses[], include_automatic_claims (default false hides Streamflow keeper-cranked withdrawals, about 90 % of claims). Ids :, deduplicated durably server-side; no events for history. Without lifecycle both channels are unchanged. - Live candles, risk inputs and wallet scores (WS Phase 4, 2026-09-23). Six PRO+ channels, all SCOPED (no firehose), each with its OWN per-connection cap of 25 PRO / 100 ULTRA / 250 BUSINESS tokens or wallets (over the cap the channel is rejected, never truncated; 25 price mints + 25 candle mints + 25 risk mints fit one PRO socket). token:candles (filters.mints) / rhc:token_candles (filters.addresses): every closed 1-minute candle as stored (open/high/low/close price and MC, volume, trade counts; event candle:closed, RHC rhc:candle_closed, plus rhc:candle_revised with a revision number when a stored RHC candle is rewritten), id candle:::[:r], usually 10-25 s after the minute ends; filters.updates:true adds the minute in progress (candle:update / rhc:candle_update, at most once per token per second, never replayed, no snapshot on subscribe). Fully flat minutes with no trades are not sent live nor on replay; Solana has no candle:revised; a replay gives the latest RHC revision only. token:risk (filters.mints): risk:authority_changed (mint or freeze authority revoked, Token-2022 transfer fee changed) and risk:supply_inflated (first 0.5 % / 5 % supply-drift crossing), plus a risk:inputs snapshot per mint on subscribe (risk_snapshot:false turns it off; risk_events[] narrows). rhc:token_risk (filters.addresses): rhc:risk_verdict_changed when a recheck stores a different contract-risk verdict, with before/after, checked_at and previous_checked_at; the change happened somewhere in that window, which is NOT bounded to 24 h (days to weeks today); score is higher = safer (the opposite of Solana's risk_score); rhc:risk_verdict snapshot on subscribe. These are input changes, not a risk-band stream (the band moves with price; GET /tokens/{mint}/risk computes it). wallet:scores (filters.wallets, base58): deployer:tier_changed (an unranked wallet entering a ranked tier counts, entered_ranking:true) and kol:score_state_changed (is_cold, is_heating_up, auto_strategy_tag); rhc:wallet_scores (filters.wallets, 0x deployers): rhc:deployer_tier_changed. Every score frame carries source (live_write | scheduled_recompute | matview_refresh) and computed_at: a recompute at that time found a new value, not a change at that moment. Filter score_events[] narrows. Closed candles, risk events and score events resume from storage (up to 60 minutes); ids are stable live and on replay. - SDKs: `npm install madeonsol` (TypeScript), `cargo add madeonsol` (Rust), `pip install madeonsol-x402` (Python: keyed REST + keyless x402); current published versions on https://madeonsol.com/mcp - Developer deep-dive pages (2026-08-28), each with FAQ schema and dated figures: - https://madeonsol.com/surges — Token surge & revival alerts (GET /api/v1/tokens/surges, WS token:surges, webhook events token:surge / token:revival; PRO+, keyed only). Surge tiers vs launch MC: early ≤10 min / ≥$12k / ≥3×, strong ≤30 min / ≥$30k / ≥6× and ≥2× the 3-min low, breakout ≤2 min / ≥$45k / ≥8× — each once per mint, sustained ≥10 s, nothing before 20 s of age. Revival: no 1-minute candle for ≥24 h, then ≥5 buys + ≥$500 buy volume with MC ≥1.5× the pre-dormancy close (or ≥20 buys / ≥$5k). Gates: liquidity ≥$1.5k and ≥2 % of MC, MC ≤ $100B, buy volume ≥3 % of the MC gained. 12 risk flags with thresholds, +1 h outcomes after 65 min, ?stats=1 per-tier hit-rates (out-of-sample), 60-day retention. The page renders the live 7-day stats table and the 10 newest fires. - https://madeonsol.com/streaming — WebSocket streaming: 33 channels (17 Solana + 16 RHC, including rhc:dev_activity (ULTRA+, developer buys/sells only, never transfers, live since 2026-10-05)) on one socket, tier gate per channel, pushed events never metered against the daily quota, seq + id on every event frame (seq gaps are normal, not loss), resume:{instance, seq, ts} from memory or, after a server restart, from storage (up to 60 minutes, 2,000 rows per channel) with a per-channel recovery report, heartbeat 15 s, slots PRO 2 / ULTRA 3 / BUSINESS 10, non-expiring stream token (since 2026-08-27), token:prices / token:candles / token:risk mint caps and wallet:scores wallet caps 25 / 100 / 250 each, webhooks as the alternative (9 registry events, HMAC-SHA256, 3 retries, auto-disable after 10 failures). - Early Solana deploy observations: https://madeonsol.com/sniper — ShredPrism, ULTRA/BUSINESS/ENTERPRISE. Direct early:deploys, asynchronous sniper compatibility and REST catch-up. Instruction presence is not execution proof. Current coverage: supported outer Pump/LaunchLab creates; no guaranteed timing lead. - https://madeonsol.com/mcp — MCP servers & SDKs: mcp-server-madeonsol (msk_ key or keyless x402) and mcp-server-robinhood-chain, Claude Desktop / Cursor / Claude Code config JSON, the 14-package table with the current published versions and MCP tool counts, install lines and github.com/madeonsol mirrors, free key 200 calls/day + 60/min, no card, 30-day expiry with regeneration. ### Core REST endpoint index (Solana; tier in brackets — every route not listed elsewhere in this file) - `GET /api/v1/kol/feed` — live KOL trade feed [all tiers]. Params: limit 1–100 (default 50), action buy|sell, kol, min_sol, strategy scalper|day_trader|swing_trader|hodler|mixed, min_kol_winrate, token_age_max_min, min_mc_usd/max_mc_usd, exclude_sells, since/before (ISO cursors). Every trade carries market_cap_usd_at_trade + price_usd_at_trade. - `GET /api/v1/kol/{wallet}` — single KOL profile [all]; `?include=` adds optional blocks. `GET /api/v1/kol/{wallet}/timing?period=7d|30d` — entry-timing profile [all]. `GET /api/v1/kol/{wallet}/pnl?period=7d|30d|90d|180d` — per-KOL FIFO PnL: summary + daily curve + closed positions on all tiers; ULTRA/BUSINESS add open_positions[] marked to live price. - `GET /api/v1/kol/compare?wallets=a,b,c` — 2–5 KOL wallets side by side [all; ULTRA depth]. `GET /api/v1/kol/pairs` — affinity pairs: period 7d|30d, min_shared 1–20 (default 3), limit 1–50, offset [all; ULTRA depth]. - `GET /api/v1/kol/tokens/hot` — tokens with ACCELERATING KOL buy interest (acceleration score, net flow, participating KOLs): period 1h|6h (default 6h), min_kols 1–20, min_avg_winrate, unique_strategies=true|false, limit 1–50, offset [all]. `GET /api/v1/kol/tokens/trending` — tokens ranked by RAW KOL buy volume: period 5m|15m|30m|1h|2h|4h|12h (default 1h), min_kols, limit 1–50, offset [all]. `GET /api/v1/kol/tokens/{mint}` — KOL activity on one token [all]. `GET /api/v1/kol/tokens/{mint}/entry-order` — ranked KOL first-buyers, limit 1–100 (default 50) [all]. - `GET /api/v1/kol/coordination` — multi-KOL convergence clusters [PRO+]: period 1h|6h|24h|7d (default 24h), min_kols 2–50 (default 3), window_minutes 1–60 (15), min_score 0–100, min_avg_winrate, unique_strategies=true|false, include_majors, min_mc_usd/max_mc_usd, limit 1–50. `GET /api/v1/kol/alerts/recent` — unified live alert feed (consensus clusters, fresh-token KOL buys, heating-up wallets) [PRO+]: window 1h|6h|24h (default 6h), types, limit 1–100 (default 30). - `POST|GET /api/v1/kol/coordination/alerts`, `GET|PATCH|DELETE /api/v1/kol/coordination/alerts/{id}` — Solana coordination RULES [PRO 5 / ULTRA 20 / BUSINESS 100]: name?, min_kols 2–50 (default 5), window_minutes 1–60 (15), min_score 0–100, include_majors, cooldown_min 1–1440 (30), score_jump_break 0–100 (20), min_mc_usd/max_mc_usd, delivery_mode websocket|webhook|both, webhook_url (HTTPS). Fires on WS channel kol:coordination and/or the rule's webhook (HMAC-SHA256). - `POST|GET /api/v1/copytrade/subscriptions`, `GET|PATCH|DELETE /api/v1/copytrade/subscriptions/{id}`, `GET /api/v1/copytrade/signals` — Solana COPY-TRADE rules [PRO 3 rules × 5 wallets / ULTRA 20 × 50 / BUSINESS 100 × 250]. Create body: name?, source_wallets (1 to the per-rule limit: PRO 5 / ULTRA 50 / BUSINESS 250; any valid Solana wallet, KOL or not, since 2026-10-04, with no Wallet Tracker quota used; rules report `source_admission` `any_wallet` and `operational_state`; a source trade must be at most 10 s old by chain time; one signal per trade per rule), min_trade_sol (default 0), only_action buy|sell|both (default buy), sizing_mode fixed|proportional|percent_source (default fixed), sizing_amount (SOL, required), delivery_mode webhook|websocket|both (default webhook), webhook_url (HTTPS), min_mc_usd/max_mc_usd (MC band on the source trade — unknown MC is dropped when set). Rows: integer id, name, source_wallets[], min_trade_sol, only_action, sizing_mode, sizing_amount, delivery_mode, webhook_url, min_mc_usd, max_mc_usd, is_active, created_at, updated_at. Signals feed: subscription_id, since, min_mc_usd/max_mc_usd, limit; WS channel copytrade:signals (PRO+). MadeOnSol emits the sized signal — it never executes trades. - `GET|PATCH|DELETE /api/v1/kol/first-touches/subscriptions/{id}` — per-rule CRUD for the first-touch subscriptions above [ULTRA+]. - `GET /api/v1/tokens/search?q=` — token SEARCH by symbol / name / mint prefix [all; shipped 2026-08-16]: q 1–64 chars, limit 1–50 (default 10) → mint, symbol, name, price, market cap, liquidity, primary DEX. `GET /api/v1/tools/search?q=&category=&limit=` — search the Solana & Robinhood Chain tools directory [all; limit ≤ 50]. - `GET /api/v1/tokens/{mint}/candles` — OHLCV candles from the trade firehose [PRO+]: tf 1m|5m|15m|1h|4h|1d (default 1h), from/to (ISO), limit 1–1500 (one full day of 1m fits one call); PRO the last 30 days, ULTRA/BUSINESS full retained history. `GET /api/v1/tokens/{mint}/top-traders` — every wallet that traded a mint ranked by realized SOL PnL or ROI [PRO+]: sort, window_days, min_bought_sol (default 0.1), limit/offset; PRO top 25, ULTRA/BUSINESS 100; enriched with is_kol / is_alpha_tracked / bot_confidence. - `POST /api/v1/tokens/batch/risk` — the /tokens/{mint}/risk score for up to 50 mints in one call, body {"mints":[...]} [PRO+]. `POST /api/v1/wallet/batch/trades` — recent trades for up to 50 wallets in ONE call [PRO+; 2026-08-16]: body { wallets: string[] (1–50), since?: unix seconds (≤ 90 d back), limit_per_wallet?: 1–100 (default 20), action?: buy|sell } → one grouped result per wallet. - Deployer Hunter [all tiers unless noted]: `GET /api/v1/deployer-hunter/alerts` (limit 1–50 default 20, tier, priority high|medium|low, alert_type, token_mint, min_kol_buys, since/before cursor AND offset — both paginations on every tier), `GET /api/v1/deployer-hunter/alert-stats?period=7d|30d|all` (alert volume + outcome stats), `GET /api/v1/deployer-hunter/leaderboard` (sort bonding_rate|recent_bond_rate|total_bonded|last_deploy_at|post_bond_survival_rate, tier, limit/offset), `GET /api/v1/deployer-hunter/best-tokens` (period 7d|30d|all, limit 1–20 default 5), `GET /api/v1/deployer-hunter/recent-bonds` (limit 1–50 default 20, since, tier, peak_mc_min — pump.fun graduations, curve → PumpSwap), `GET /api/v1/deployer-hunter/stats`, `GET /api/v1/deployer-hunter/{wallet}` (profile), `GET /api/v1/deployer-hunter/{wallet}/tokens` (limit 1–50 default 20, offset). - Wallet Tracker [PRO+ only — BASIC gets 403 on every route; capacity PRO 50 / ULTRA 250 / BUSINESS 1,000 wallets, 120-day retention]: `GET|POST /api/v1/wallet-tracker/watchlist` (body wallet_address, label?; 409 when already tracked or at capacity), `PATCH|DELETE /api/v1/wallet-tracker/watchlist/{address}`, `GET /api/v1/wallet-tracker/trades` (wallet, action buy|sell (transfers have action null: use event_type=transfer), event_type swap|transfer, limit ≤ 200, before cursor), `GET /api/v1/wallet-tracker/summary` (period 24h|7d|30d, wallet). Webhook event wallet_tracker:event; WS channel wallet_tracker:events (ULTRA+, subscriber-scoped). - Webhooks [PRO+; PRO 3 / ULTRA 10 / BUSINESS 30]: `POST|GET /api/v1/webhooks`, `GET|PATCH|DELETE /api/v1/webhooks/{id}`, `POST /api/v1/webhooks/test`. Registerable events (11): kol:trade, kol:coordination, deployer:alert, deployer:bond, wallet_tracker:event, sniper:deploy, rhc:kol_trade, token:surge, token:revival, dev:activity (Solana developer sells/buys/token transfers; PRO direct-developer events, ULTRA+ identity stitching), rhc:dev_activity (Robinhood Chain developer buys/sells only; no developer-transfer events). Retries 5s/30s/2min, auto-disabled after 10 consecutive failures; HMAC-SHA256 over `.`. - Meta [keyless]: `GET /api/v1/status` (service health, uptime %, stream lag — https://madeonsol.com/api-status), `GET /api/v1/ping` (liveness), `GET /api/v1/openapi.json` (full spec; `/api/v1/rhc/openapi.json` = Robinhood-Chain-only view), `GET /api/v1/postman.json`. `GET /api/v1/me` (any key) is documented below. - Machine-readable discovery: API catalog (RFC 9727) https://madeonsol.com/.well-known/api-catalog; APIs.json https://madeonsol.com/.well-known/apis.json; AsyncAPI (WebSocket streams + webhook events) https://madeonsol.com/api/v1/asyncapi.json; MCP packages (stdio, no hosted public endpoint) https://madeonsol.com/mcp-packages.json; agents.json https://madeonsol.com/agents.json. The keyed OpenAPI at /api/v1/openapi.json is the complete contract; /openapi.json is only the keyless x402 pay-per-call subset. ### KOL Leaderboard Endpoint - `GET /api/v1/kol/leaderboard` — PnL leaderboard ranked by realized SOL. Params: `period` (today/7d/30d/90d/180d), `limit` (1–100, default 50), `offset`, `sort` (pnl/winrate/volume/avg_roi/profit_factor/early_entry_pct/consistency), `strategy`, `min_winrate`. Each entry includes: `name`, `wallet`, `pnl`, `buy_count`, `sell_count`, `volume`, `median_hold_minutes_30d: number | null` (median hold duration in minutes over the last 30 days), `percentile_early_entry_30d: number | null` (0–100 percentile rank of this KOL's early-entry rate compared to all tracked KOLs over 30 days). ### Alpha Wallet Intelligence Endpoints **Data note:** Early buyer tracking started in early 2026. Wallets with < 5 tokens in the dataset show low confidence. Scores will improve as the dataset grows — this is expected behavior, not a bug. Scored from 25,000+ token_early_buyer records — wallets identified buying tokens in their first 20 buyers on Pump.fun. - `GET /api/v1/alpha/leaderboard` — Top statistically profitable wallets by win rate, PnL, or ROI. Params: period (7d|30d|all), min_tokens (1–20), sort (win_rate|pnl|roi), exclude_bots (true|false). Paginated `limit` 1–100 (default 100) + `offset` on every tier, full wallets + full precision for all. BASIC and PRO: top 100. ULTRA/BUSINESS: a 500-deep window reachable via offset, plus per-row bot_confidence + behavioral signals (bundle_rate, buy_size_stddev, active_hours). - `GET /api/v1/alpha/{wallet}` — Full alpha profile for one wallet: per-token breakdown, win rate, realized PnL, ROI, and a bot_signals array explaining the confidence level. ULTRA only. - `GET /api/v1/alpha/{wallet}/linked` — Wallets behaviorally linked to this one (co-bought 3+ tokens within a 2-second window). Returns shared_token_count and similarity_score. ULTRA only. - `GET /api/v1/tokens/{mint}/cap-table` — First 10–20 non-deployer early buyers for a token. Each buyer enriched with historical win rate, realized PnL, KOL identity, bot confidence, and bundle flag. Summary block: buyer_quality_score, known_alpha_wallets, known_kols, bundle_buyers. BASIC: 403. PRO: top 10. ULTRA/BUSINESS: top 20. Full wallet addresses on every paid tier. **New (2026-07-05):** each buyer also carries realized-PnL fields from `token_trades` — `realized_pnl_sol`, `total_sol_bought`, `total_sol_sold`, `first_sell_at`, `still_holding` — so you can see which early buyers already dumped vs are still holding. - `GET /api/v1/tokens/{mint}/buyer-quality` — 0–100 buyer quality score for a token's first-buyer cohort. Score formula: avg win rate of non-bot buyers + KOL bonus (up to +20) − bundle penalties − bot domination penalty. Returns score, confidence (low/medium/high), signal (positive/neutral/negative), and breakdown incl. dump_cluster_count (first-20 buyers on a rolling dump-cluster wallet list — out-of-sample, 3+ predicted a sub-15-min peak 94% of the time vs 61% base) and recycled_early_buyer_count (inverse signal when high with zero cluster). All tiers receive the full breakdown. 5-minute LRU cache per mint (max 1000 entries). - `POST /api/v1/tokens/batch/buyer-quality` — Bulk scoring for up to 50 mints. Body: `{ "mints": [...] }`. Shares the same LRU cache — repeat calls return `cache_hits: N` at ~zero cost. Response: `{ tokens: [...], count, cache_hits }`. All tiers. - `GET /api/v1/tokens/{mint}/locks` — Token LOCKS & VESTING on a Solana mint (PRO+): every Streamflow stream, Jupiter Lock VestingEscrow and Bonfida token-vesting contract on the mint, decoded from the locker programs' account state (lock-tracker: Yellowstone account subscription on the three programs + a daily getProgramAccounts reconciliation; mig 326). Each row = the on-chain schedule (start/cliff/period/end, cliff + per-period amounts), the terms (cancelable_by_sender/recipient, transferable, can_topup) and a LIVE derivation at request time: locked_raw (still locked now = deposited − unlocked-so-far), unlocked, withdrawn, claimable, status (active/completed/cancelled/closed), next_unlock {at, kind cliff|period|final|tranche, amount}. summary: lock_count, active_count, by_program, by_kind, distinct_lockers, locked/deposited (raw + ui + usd + % of supply), unlocking_7d/30d, next_unlock, active_cancelable_by_sender. Token/vesting locks ONLY — LP locks are not included. raw = base-unit digit strings; ui/usd/pct null when decimals/price unknown (token.facts_resolved). - `GET /api/v1/tokens/locks` — Newest lock/vesting contracts across ALL mints (PRO+): same row shape + token {symbol, decimals, price_usd, market_cap_usd}; since=/before= cursors on created_at (pagination.next_since / next_before), filters mint, sender, recipient, program, kind, status, min_usd, min_pct_of_supply; backfilled Jupiter Lock rows with an estimated created_at are excluded unless include_estimated=1. Pushed live as token:lock events on WS channel token:locks. - `GET /api/v1/tokens/unlocks` — Upcoming unlock EVENTS (PRO+): for every active contract, its next cliff / periodic (period ≥ 1h) / final / tranche unlock inside within=1h|6h|24h|3d|7d|14d|30d|90d, with amount (raw/ui/usd/% of supply) and window_amount_* (that contract's total release over the whole window); continuous per-second streams contribute only cliff/final events; sort=soonest|largest_usd|largest_pct; filters mint/program/kind/min_usd/min_pct_of_supply. - Lock provenance (2026-10-02, every Solana lock row): provider {id, name, identity, compatible_with, website_url, lock_url} (Streamflow / Jupiter Lock / Bonfida are identified by program id, identity verified; lock_url is always null because no per-lock URL format is proven for them, none is guessed), explorer {lock_account_url, creation_tx_url} on Solana Explorer, price_usd (the price behind every *_usd field), seconds_until_end (0 once completed, null when perpetual or cancelled/closed) and seconds_until_next_unlock. withdrawn_raw = claimed so far, read from the contract's own state; claimable = unlocked minus withdrawn. Bonfida rows carry their tranche schedule. A % of supply above 100.5 (supply changed since the deposit) reads null. The feed pages with cursor= (pagination.next_cursor, strict keyset). - `GET /api/v1/tokens/{mint}/fee-shares` — pump.fun CREATOR-FEE SHARING on a mint (PRO+): the on-chain SharingConfig (pump_fees program PDA ['sharing-config', mint]) decoded — admin, admin_revoked, status, each shareholder {address, share_bps, share_pct, is_admin, is_social_pda, social{platform, platform_label, user_id, lifetime_claimed}, received (from our distribution log), payout_count}, redirected_bps (share going to non-admin addresses), social_bps, is_default (100% to the admin — pump creates one per coin, so this is a real answer, not missing data). Plus distributions {count, total, total_usd, recipients[], past_recipients[]}, history (config created/updated/reset, creator transferred), recent_distributions. Source: fee-claim-tracker (Yellowstone tx subscription on pump + pump_fees, Anchor events) + live PDA read; history from 2026-08-17. - `GET /api/v1/tokens/surges` — TOKEN MOMENTUM FIRES (PRO+), newest first. kind=surge: a token < 30 min old whose market cap runs vs its LAUNCH MC (baseline = first MC sample ≤90 s after birth; birth from the pre-confirm sniper deploy, the confirmed deployer create, or first observed trade) — tier early (≤10 min, ≥$12k, ≥3× launch), strong (≤30 min, ≥$30k, ≥6× launch AND ≥2× the lowest sample of the last 3 min), breakout (≤2 min, ≥$45k, ≥8×); each tier fires once per mint, independently. kind=revival: no 1-minute trade candle for ≥24 h (measured on token_ohlc_1m, which covers every DEX mc-tracker prices — graduated Raydium/Meteora tokens included; token_prices.last_trade_time is deliberately NOT the anchor), then CONFIRMED by the tape — ≥5 buys, ≥$500 buy volume, MC ≥1.5× the pre-dormancy candle close (or ≥20 buys / ≥$5k regardless) — never by the price mark alone; one fire per dormancy episode. Every row = the WS/webhook payload + outcome: id, kind, tier, mint, symbol, name, launchpad, primary_dex, fired_at, birth_at, birth_source, age_seconds, market_cap_usd, liquidity_usd, liquidity_to_mc_ratio, baseline_mc_usd, baseline_source (launch|late — late = the engine first saw the token mid-life, multiple not applied), mc_multiple, mc_change_3m_pct, dormant_hours, prev_mc_usd, mc_vs_prev_multiple, peak_mc_usd, pct_of_peak, bonding_progress_pct, tape {since, buys, sells, trades, buy_volume_usd, sell_volume_usd, volume_usd, mev_volume_usd, unique_buyers, unique_wallets, trades_per_wallet, wallet_data_available — unique_* are null when the mint is outside token_trades coverage, never inferred}, kol {buyers, buys, sells, names[]}, early_buyers {count, bundled, cohort_sol, sold, sniper_wallets}, deployer {wallet, tier, bonding_rate, total_bonded, total_deployed, runner_rate, labeled_tokens, recent}, risk_flags[] (bundled_launch ≥3 same-block early buyers · few_buyers <8 unique buyers / <10 buys · wash_pattern ≥4 trades/wallet across <15 wallets · thin_liquidity <$3k or <3% of MC · cold_deployer · sniper_heavy ≥3 sniper wallets in the cohort · early_buyers_exiting ≥50% of a ≥5 cohort sold · sell_pressure sells>buys · no_prior_price · mint_authority_active · transfer_fee), outcome {mc_usd_1h_after, peak_mc_usd_1h_after, low_mc_usd_1h_after, mc_1h_multiple, peak_1h_multiple, priced_after_1h} (null until the fire is ≥65 min old; priced_after_1h=false means no candle in the hour, not zero). stats=1&days=7 → per-(kind, tier) fires, with_outcome, up_1h_pct, median/p75 peak multiple, doubled_1h_pct (out-of-sample: the fire is recorded before the outcome exists). Filters (DB-native): kind, tier (400 with kind=revival), mint, launchpad, deployer_tier, min_mc_usd, max_mc_usd, min_buys, exclude_flags=a,b (drop rows carrying ANY; unknown → 400 + known_flags[]), only_clean=1; since=/before= cursors on fired_at (pagination.next_since / next_before); limit 1–200. definitions echoes the live thresholds. Pushed live on WS channel token:surges (events token:surge / token:revival) and the webhook registry. - `GET /api/v1/tokens/fee-claims` — pump.fun FEE-CLAIM FEED (PRO+), newest first: distribution (creator fees paid pro-rata to SharingConfig shareholders; payouts[] {address, share_bps, amount, amount_usd}), social_claim (fees earmarked for a platform identity — platform 2 = X, user_id = platform-native numeric id, NOT the handle — claimed to recipient; amount + lifetime in payload), shares_created / shares_updated / shares_reset (config changes with shareholders snapshot), creator_transferred (SetCreator), creator_claim (plain creator vault claim, per creator, no mint — excluded unless type= asks). Filters type (comma list), mint, recipient, actor, social_platform, social_user_id, min_sol, since/before; pagination.next_since cursor; WS channel token:fee_claims (event token:fee_claim). Amounts in quote base units (SOL lamports unless a stable-quoted coin) with amount/amount_usd. Default 100%-to-creator configs and zero-amount distributions are not stored. - `GET /api/v1/tokens/{mint}/holders` — Live holder CENSUS for a Solana mint (PRO+; disclosure PRO ranks 1–10 / ULTRA 1–50 / BUSINESS 1–100, maths tier-independent). Mint-scoped getProgramAccounts on the mint's token program at `confirmed` (pump.fun mints are Token-2022) → every token account, merged per owner → EXACT `holder_count` (distinct non-zero owners minus pools/curves/burns), `token_accounts_nonzero`, ranks 1–100, `top1/10/20/50/100_share` over the circulating denominator, plus `deployer_pct`, `kol_pct`, `early_buyer_pct`, `bundle_pct`, `bot_pct`, `dump_cluster_pct`. Each disclosed owner is labelled from MadeOnSol data (deployer / kol / early_buyer / buyer / bundle / bot / dump_cluster; empty = unknown to us, not verified clean). Program-derived owners and burns are EXCLUDED from the denominator and listed in `excluded[]`, NAMED where possible: `reason` = pool (+ `dex`, `pool_address` — matched on our known pools for the mint or the shared Raydium v4 / Meteora DAMM v2 vault authorities), bonding_curve (pump.fun / LaunchLab), burn, or program_account (an off-curve owner we could not attribute); `concentration.pool_pct / burned_pct / program_pct` split the exclusion (sum = `pool_and_program_pct`, all over total supply). Amounts are raw u64 STRINGS. Mega-caps the provider refuses (TRUMP/JUP/BONK class) fall back to the top-20 getTokenLargestAccounts view with `holder_count: null`, `source.method: getTokenLargestAccounts` and `source.census_fallback_reason` — never a trade-derived estimate. Large tokens take 5–30 s upstream: 503 `holder_scan_in_progress` (Retry-After 20) while the scan finishes into the cache; retry is instant. 503 `holder_rpc_unavailable` (Retry-After 15) if the holder RPC is down; 404 `not_a_mint`. Distinct from `/cap-table` (who bought FIRST) — this is who holds NOW. The same top-20 fallback is used when the census times out or when its balances add up to more than the mint's supply (an inconsistent read, refused: `census_fallback_reason: census_inconsistent_sum_exceeds_supply`); `source.note` states the reason. - `GET /api/v1/tokens/{mint}/bundle` — Bundle intelligence for a token: the same-slot **bundle cohort** (≥3 wallets buying in one slot = `is_bundle`) and, the headline, **how much of supply it still holds** — computed from confirmed on-chain trades (`token_trades`), not a pre-execution shred feed. This is the incumbents' (e.g. Trench Radar) "current held %" rug/insider signal done the confirmed-data way, with atomicity added. Returns `{ mint, bundle: { wallet_count, bundle_kind ("atomic_tx"|"same_slot"|"none"), held_ratio (0–1|null), held_pct_of_supply (0–1|null — the headline, net tokens held ÷ supply, clamped), fully_exited (bool), buy_volume, tokens_held }, wallets: [...] }`. Honest about inputs: `held_pct_of_supply`/`tokens_held` are swap-derived net proxies (not a holder census), and `buy_volume` is cumulative buy volume — NOT distinct tokens, so it can exceed supply. Field-gated across **all tiers** (funnel-hook, like cap-table / buyer-quality): BASIC gets the scalar `bundle` block only; PRO adds the top-10 wallets (flags only); ULTRA returns the full cohort enriched with KOL/alpha identity (`kol_name`, `win_rate`, `bot_confidence`). - `GET /api/v1/tokens/{mint}/flow?window=1h|24h` — Per-token trade-flow aggregate straight from the trade firehose — the organic-vs-fake-volume read for a single mint. Returns `{ mint, window, from, unique_wallets, unique_buyers, unique_sellers, buy_count, sell_count, total_trades, buy_sol, sell_sol, net_sol, trades_per_wallet }`. `trades_per_wallet` is a wash-trading proxy (high trade count over very few wallets = synthetic volume). Counts and flows only — no holder/balance data. PRO+. - `GET /api/v1/tokens/{mint}/trades` — **PRO+ (2026-07-10)** mint-scoped **trade tape**: every captured trade for one token, newest first, cursor-paginated — the backfill complement to the live firehose (seed history, then stay current via the stream). Params: `limit` (1–500, default 100), `cursor`, `action` (buy/sell), `wallet` (one wallet's trades on this token), `since`/`until` Unix seconds (default **full history**). Per trade: `tx_signature`, `wallet_address`, `action`, `sol_amount`, `token_amount`, `price_sol`, `price_usd`, `early_buyer_rank`, `slot`, `block_time`, `traded_at`. Response carries `coverage { history_start: 2026-04-12, scope: "pump.fun pipeline" }` — the honesty markers for the capture window. Size floor (`coverage.size_floor`): trades stored from 2026-10-22T19:53:00Z have no size floor (`coverage.size_floor.removed_at`). Before 2026-10-22T19:53:00Z (legacy policy) buys under 0.05 SOL (under $3.50 when paid in USDC/USDT) were not stored; sells that receive SOL were kept at any size. Live streams, prices and candles were never subject to it. - `GET /api/v1/tokens/{mint}/pools` — **PRO+ (2026-07-05)** per-venue **liquidity map**: every DEX pool a token trades in (pump.fun / PumpSwap / Raydium / Meteora / Orca), which are live vs parked, and how fragmented its liquidity is. Complements `GET /token/{mint}`, which collapses everything into one aggregate liquidity number — this breaks it out per pool, so you can tell a token whose headline liquidity is really one dominant pool + dust from one genuinely spread across venues. Returns `pools[]` — each `{ pool_address, dex, quote_mint, liquidity_usd, last_price_sol, last_swap_at, amm_id, is_active }` (`is_active` = traded recently, i.e. live vs parked) — and a `summary` block `{ pool_count, active_pool_count, dex_count, dexes, total_liquidity_usd, primary_pool, primary_dex, top_pool_share_pct }` (`top_pool_share_pct` = the primary pool's share of total liquidity, the fragmentation/concentration read). Self-hosted from our pool index. - `GET /api/v1/tokens/{mint}/risk` — **PRO+** transparent 0–100 token rug-risk / safety score (higher = riskier). Returns `risk_score`, `band` (safe/caution/danger), an auditable `factors[]` array (each `{ key, label, status, points, detail }` — mint/freeze authority, liquidity depth & thinness, Token-2022 transfer fee, LP burn/lock (reads unknown: LP-token custody is not observed for Solana pools), bundled/sniped open, deployer track record, KOL distribution, supply_inflation, blacklist), raw `inputs` (incl. `sniper_footprint`, the slot-window snipe rollup — informational, does not move the score), `score_version`, and `as_of`. **dev block (2026-07-11)**: deployer self-activity — the dev's exact create-tx self-buy (`buy_sol`/`buy_tokens`/`buy_supply_pct`), post-create trading on their own mint (`bought_tokens_after`, `sold_tokens`, `sold_sol`, `first_sell_at`/`last_sell_at`), and live on-chain holdings (`holdings_tokens`, `holdings_supply_pct`, `wallet_empty` — "has the dev already exited?" — and `transferred_out`: chain balance well below trade-derived expectation ⇒ tokens moved out via transfer, `null` when not honestly assertable). `dev: null` for mints pre-dating the deploy pipeline. Sibling `POST /api/v1/tokens/batch/risk` scores up to 50 mints per call (no dev block). - `GET /api/v1/tokens/{mint}/depth` — **PRO+ (2026-07-11)** per-pool **price-impact / slippage**: "how much SOL to move price N%" and the impact + tokens received per buy size. `?sizes=` up to 8 SOL amounts (default `0.5,1,5,10`). Per pool: `spot_price_sol`, `quotes[]` (`size_sol`, `tokens_out`, `avg_price_sol`, `price_impact_pct`), `to_move_price { "1pct", "5pct", "10pct" }`, `fee_pct`, `source` (`"stream"` = our streamed constant-product reserves, zero RPC; `"live_rpc"` = pump.fun/bonk bonding curve priced from a live read of the curve's virtual reserves), `reserves_age_ms`. Validated against Jupiter (exact for constant-product AMMs: PumpSwap, Raydium v4/CPMM, Meteora DAMM). Honesty: impact is per-pool (not router-optimal); concentrated-liquidity pools (Raydium CLMM, Orca, Meteora DLMM) and unclassified pools return under `unsupported_pools[]` with a `reason` instead of a wrong number (backed by `token_pools.pool_model`). A sharper liquidity-quality read than raw `liquidity_usd`. - `POST /api/v1/token/batch` — Batch lookup of up to 50 mints, returning the same per-mint shape as `GET /api/v1/token/{mint}` (price, MC, volume, **velocity deltas**, deployer, KOL activity, `age_seconds`, `is_blacklisted`, `liquidity_to_mc_ratio: number | null`, `launch_cohort_sol: number | null`, `launch_cohort_size: number`). DB queries batched with `IN (...)`; dex-stream + RPC fan-outs run in parallel. Built for sniper workflows — typically 10–20× cheaper than N sequential calls. - `GET /api/v1/tokens` — **PRO+** filtered, sortable token directory + trending/momentum board. Complements `/token/{mint}` (single lookup), `/tokens/almost-bonded` (pre-bond pump.fun), and the KOL-scoped `/kol/tokens/{hot,trending}` (KOL-only ranking). DB-side filters (cheap, indexed): `min_mc`, `max_mc`, `min_liq` (default **2000** — set 0 to disable phantom-MC dust floor), `active_h` (only tokens traded in last N hours, 0.1–168), `primary_dex` (pumpfun/pumpswap/raydium/meteora/orca/raydium_clmm), `authority_revoked` (both mint+freeze), `exclude_token2022` (drops transfer-fee scam vector), `lp_burned`. **Momentum filters are now fully DB-native** (read-time `token_prices_trending` view, migration 193 — exposes momentum metrics as columns so they sort + paginate correctly with NO over-fetch): `min_volume_1h_usd`, `max_mev_share_pct`, `min_liq_mc_ratio: number` (minimum liquidity_usd / market_cap_usd ratio), `max_liq_mc_ratio: number`, `mc_change_1h_min_pct`, `mc_change_1h_max_pct`. Only `deployer_tier: string` ("elite" | "good" | "moderate" | "rising" | "cold" | "unranked") remains a post-filter (joined from deployer_tokens, over-fetches 3×). Sort: `mc_desc` | `mc_asc` | `last_trade_desc` | `liquidity_desc` | `cumulative_volume_desc` | **`mc_change_5m_desc`** | **`mc_change_1h_desc`** | **`volume_1h_desc`** | **`trending`** — `trending` = recent-volume × positive-momentum composite, recency-bounded to the last 1h (rides `idx_token_prices_recent_mc`), and echoes `filters.trending_version: "v1"`. Limit max 100, offset max 10k. Response: `tokens[]` with `mint`, `symbol`/`name` (from deployer_tokens when launched on pump.fun), `price_usd`, `market_cap_usd`, `fdv_usd`, `liquidity_usd`, `primary_dex`, `authorities_revoked`, `lp_burned`, `is_token_2022`, `last_trade_time`, `mc_change_5m_pct`, `mc_change_1h_pct`, `organic_volume_1h_usd`, `mev_share_pct`, `liquidity_to_mc_ratio: number | null` (liquidity_usd / market_cap — structural thinness gauge), `deployer_tier: string | null` (tier of the token's deployer). Pagination includes `post_filtered: true` flag so clients can detect when page size may be smaller than limit (only when `deployer_tier` is set). Filters echo includes `min_liq_default_applied`. - `GET /api/v1/tokens/almost-bonded` — **PRO+ (2026-06-27)** pre-bond pump.fun tokens approaching graduation, ranked by **velocity** (Δbonding-progress per minute) and enriched with **deployer reputation**. Differentiator: nobody else ships pre-bond + reputation + velocity in one feed — "95% and accelerating" beats "92% stalled". `bonding_progress_pct` is persisted by mc-tracker on `token_prices` from on-chain `real_token_reserves` depletion. Filters: `min_progress` (default 80), `max_progress` (default 99.99 — `is_bonded=false` enforced, excludes graduated), `min_velocity_pct_per_min` (momentum — needs a 5m-ago snapshot; rows without one drop out when set), `max_age_minutes` (freshness), `deployer_tier` ("elite" | "good" | "moderate" | "rising" | "cold" | "unranked"), `authority_revoked` (both mint+freeze), `min_liq`. Sort: `velocity_desc` (default) | `progress_desc` | `eta_asc` (`velocity_desc`/`eta_asc` place unmeasured tokens last). Limit max 100, default 50. Response: `{ tokens[], filters, returned, note }` — each token: `mint`, `symbol`, `name`, `progress_pct`, `velocity_pct_per_min` (null until a 5m snapshot exists), `eta_minutes` (linear projection from current velocity), `stalled` (|velocity| < 0.05 %/min), `real_sol_reserves`, `market_cap_usd`, `liquidity_usd`, `authorities_revoked`, `deployer_tier`, `age_minutes`. - `GET /api/v1/me` — **v1.7 (2026-05-12), all authenticated tiers** self-inspect quota and feature usage. Reads from the same in-memory counters that drive rate-limit enforcement — `quota.daily.remaining` is authoritative (no header parsing). Returns `{ subscriber, tier, tier_label, subscription: { status, billing_cycle, current_period_end, started_at } | null, quota: { daily: { limit, used, remaining, resets_at }, burst: { limit, used, remaining, window_seconds } }, features: { webhooks, copytrade_wallets, copytrade_wallets_per_rule, copytrade_rules, coordination_rules, first_touch_subscriptions, ws_connections, dex_connections, wallet_tracker_watchlist, price_alerts } }`. Use for self-throttling and quota-aware retry logic. ### Universal Wallet API (new 2026-05-20) Per-wallet endpoints that work on **any** Solana wallet — not just curated KOLs. Reads `token_trades` directly via the `idx_token_trades_wallet_cover` btree index (sub-100ms even on heavy wallets). FIFO cost-basis PnL computed on-demand, cached in `wallet_analyses` with dynamic TTL (5min active / 1h recent / 24h dormant). **PRO+ on every endpoint. Cache hits don't count against your daily quota.** Backed by `get_wallet_stats()` SQL function (migration 147) for the stats endpoint and the shared `src/lib/wallet-pnl.ts` FIFO helpers for the compute-heavy ones. No new ingestion pipeline — the data was already being captured by `dex-stream` into `token_trades` for every DEX swap. - `GET /api/v1/wallet/{address}` — Aggregate stats over 90d (first/last seen, total_trades, buys/sells split, bought_sol/sold_sol, unique_tokens) plus cross-product flags joined from `kol_wallets` (is_kol + kol_name), `mv_alpha_wallets` (is_alpha_tracked + bot_confidence — string enum none/low/medium/high — + alpha_win_rate + alpha_net_pnl_sol + alpha_tokens_traded), and `deployers` (is_deployer + deployer_tokens_deployed + deployer_bonding_rate). **Reputation flags (2026-07-10)**: `is_sniper` (≥5 tokens early-bought with ≥80% flipped <5min; refreshed ~12min), `is_bundler` (bought >1 token in the same block, ever — lifetime flag), `is_dumper` (≥5 dump cohorts + 0 runner cohorts, rolling 42d) + `dump_cluster { dump_cohorts, runner_cohorts, total_cohorts, as_of }`. Flags are pump.fun-pipeline scoped — `false` means *not observed*, not verified clean. **v1.9.0 `derived` block (additive)**: win_rate, roi, best_trade/worst_trade (with token + SOL amount), AI-classified verdict string ("Degen flipper", "Smart money", etc.), biggest_miss (scans all round-trip tokens and calculates missed SOL profit using pump.fun ATH), ticker symbols resolved via pump.fun API (no more raw contract addresses), ATH market cap per token sourced from pump.fun. Returns 404 if the wallet has no trades AND no flag-table presence. Degraded reads are flagged, never shown as empty: `stats_unavailable: true` = the 90-day aggregation failed (stats null is unknown, not inactive); `enrichment_unavailable: true` + `degraded_fields` (top_tokens / trading_style / deployer_breakdown / recent_trades / biggest_miss) = those blocks' query failed, so their null / [] is unknown; retry later. - `GET /api/v1/wallet/{address}/pnl` — Full per-wallet PnL. Response shape: - `summary`: realized_sol, unrealized_sol, total_pnl_sol, total_bought_sol, total_sold_sol, wins, losses, win_rate, profit_factor (gross_wins / gross_losses; null if no losses, 0 if no wins), avg_hold_minutes, median_hold_minutes, max_drawdown_sol (running peak-to-trough on realized curve), open_positions_count, closed_positions_count, total_tokens_traded, best_realized, worst_realized - `pnl_curve[]`: sparse daily UTC buckets (only days with at least one realized event) — `{ date, day_pnl, cumulative_pnl, trades }` - `closed_positions[]`: tokens with no open lots remaining AND with both buys and sells in window. Sorted by pnl_sol DESC — winners first. Per row: token_mint, buy_count, sell_count, bought_sol, sold_sol, pnl_sol, roi_pct (realized / bought × 100), hold_minutes (first buy → last sell), result (win/loss/breakeven), first_trade, last_trade - `open_positions[]`: per row token_mint, token_amount, cost_basis_sol, avg_entry_price_sol, current_price_sol (live from market-cap tracker via /mc/{mint} batched call), current_value_sol, unrealized_sol, unrealized_pct, first_buy_at, buys_in_position - `notes`: cost_basis_observable_from (data window cutoff), truncated_trades (if 50k cap was hit) - Response also carries cache_hit boolean + computed_at (on cache hits) + ttl_seconds (on cache miss) - `GET /api/v1/wallet/{address}/positions` — Open lots only, lighter response for UI clients that don't need the full PnL summary. Same `WalletOpenPosition` shape as `/pnl`'s `open_positions[]`. Shares the `wallet_analyses` cache — calling `/positions` immediately after `/pnl` on the same wallet is a cache hit. - `GET /api/v1/wallet/{address}/holdings` — **ULTRA.** Verified *current* on-chain holdings, read live from the wallet's SPL + Token-2022 token accounts (`getTokenAccountsByOwner` × 2 programs) + native SOL balance via `withRpcFallback`. Unlike `/positions` (trade-derived from `token_trades`, so blind to transfers), this is the actual chain state — it reflects airdrops, CEX withdrawals, and wallet-to-wallet moves. Each holding is enriched from our own data: `price_usd`/`value_usd`/`market_cap_usd`/`is_bonded` (token_prices), `name`/`symbol` (token_metadata), and `transfer_delta` = on-chain `amount` − `trade_derived_amount` (90-day buy/sell net) — a non-zero delta flags tokens that arrived or left WITHOUT a swap (airdrops, insider funding, wallet-hopping); `null` when the wallet never traded that mint (honest unknown). Params: `limit` (1–500, default 200), `min_value_usd` (default 0). Response: `sol_balance`, `holdings[]` (sorted by `value_usd` desc, unpriced last), `summary` (`token_accounts`, `non_zero`, `returned`, `priced`, `total_value_usd`, `truncated`), `verified_at`, `cache_hit`, `ttl_seconds`. Protected by a 90s cache, a 6-uncached-lookup/min per-key limiter (cache hits exempt), and a global RPC concurrency guard; enrichment queries are chunked at 80 mints so airdrop-spam wallets don't hit a gateway 414. - `GET /api/v1/wallet/{address}/funding` — **PRO+** (cross-wallet `relationships` counts ULTRA+). Shared-funder evidence for a tracked Solana wallet (active KOLs, elite/good deployers): addresses that sent a qualifying SOL transfer to this wallet AND to other tracked wallets, with the supporting transactions. Evidence of a funding connection, not proof of common ownership. SOL-only, forward-looking coverage from monitoring start (2026-09-20, no backfill); every response carries `status` + `coverage`, and an empty list means no shared funder observed within coverage. Params: limit (1-20), offset (0-100). - `GET /api/v1/wallet/{address}/trades` — Cursor-paginated raw `token_trades` rows. Query params: - `coverage` block: `in_scope` / `eligibility` say whether the wallet is inside the launchpad write-gate (an empty page outside it means not captured, not no activity). `coverage.size_floor`: trades stored from 2026-10-22T19:53:00Z have no size floor (`removed_at`). Before 2026-10-22T19:53:00Z (legacy policy) buys under 0.05 SOL (under $3.50 when paid in USDC/USDT) were not stored; sells that receive SOL were kept at any size. Live streams, prices and candles were never subject to it. - `limit` (1–500, default 100) - `cursor` — base64 of `:` from the previous response's `next_cursor`. Stable across DESC pagination because (block_time DESC, id DESC) is total-ordered (id is bigint generated always). - `action` — buy or sell - `token_mint` — filter to a single token - `since` / `until` — Unix epoch seconds. Default window = last 90 days. - Response: `trades[]` (tx_signature, token_mint, action, sol_amount, token_amount, block_time, traded_at), `next_cursor` (null if end), `has_more`, `filters` echo - `POST /api/v1/wallet/batch/classify` — **PRO+ (2026-07-10)** bulk **wallet reputation flags** for up to 100 addresses in one call. Body: `{ wallets: string[] }` (JSON array or comma-separated string). Per wallet: `address`, `is_sniper`, `is_bundler`, `is_dumper`, `is_kol`, `kol_name`, `bot_confidence` (string enum none/low/medium/high), `dump_cluster { dump_cohorts, runner_cohorts, total_cohorts, as_of } | null` — values identical to the single-wallet `flags` block on `GET /wallet/{address}`. Pure index lookups: ~10ms per 100-address batch; counts as 1 request against quota. Flags are pump.fun-pipeline scoped — `false` = not observed, not verified clean. **Cost-basis honesty.** Cost basis is only observable inside the data window (`token_trades` capture started 2026-04-12, ~38 days ago at launch). A wallet that bought a token 60 days ago and sells it today has the sell counted but no matching buy — overflow sells are silently discarded rather than fabricated into a realized PnL number. `notes.cost_basis_observable_from` in the response makes the cutoff visible per call. **Mints without current price.** Open positions for tokens that mc-tracker doesn't have a current price for (delisted, no recent swap, or never indexed) return `unrealized_sol: null` and `current_price_sol: null` rather than fabricated zero values. The cost basis is still reported correctly so the UI can show "open: 1000 tokens at $0.0015 cost basis · current: unknown". **Hard cap.** 50k trades per wallet keeps compute bounded. Truncation surfaces in `notes.truncated_trades`. Wallets above this cap are very rare and typically bots — tier rate limits handle abuse beyond the cap. ### Price Alert System (new v1.9.0, 2026-05-25) Token market-cap dip/recovery alerts, evaluated every 250 ms in memory. Set a drop % threshold on any tracked token; get notified via webhook or WebSocket when MC drops below baseline. Optional recovery tracking fires when MC bounces back. One-shot lifecycle: watching → dipped → recovered. 30-day auto-expiry. PRO: 5 concurrent alerts, ULTRA: 50, BUSINESS: 150. - `POST /api/v1/price-alerts` — Create an alert. Body: `{ token_mint, drop_pct (0.01–99.99), recovery_pct? (0.01–1000 — set it to also get the recovery fire; omit for a one-shot dip alert), name?, delivery_mode ("webhook"|"websocket"|"both", default webhook), webhook_url? (HTTPS) }`. Integer ids. Caps: PRO 5, ULTRA 50, BUSINESS 150. Returns alert ID + webhook_secret (if webhook). PRO+. - `GET /api/v1/price-alerts` — List your active alerts with status (watching/dipped/recovered/expired/cancelled). PRO+. - `GET /api/v1/price-alerts/{id}` — Single alert detail including baseline_mc, trigger history. PRO+. - `PATCH /api/v1/price-alerts/{id}` — Update drop_pct or delivery_mode on a watching alert. PRO+. - `DELETE /api/v1/price-alerts/{id}` — Cancel an alert (any status). PRO+. - `GET /api/v1/price-alerts/events` — Event history for your alerts (dip fires, recovery fires). Params: alert_id (integer), event_type (dip/recovery), since (ISO), limit (1–500). PRO+. - WebSocket channel: `price_alert:events` on `wss://madeonsol.com/ws/v1/stream` — pushed when alerts fire. PRO+. ### New v1.9.0 Endpoints (2026-05-25) Five additional endpoints shipped alongside the price alert system: - `GET /api/v1/kol/scouts/leaderboard` — Scout leaderboard: top KOLs ranked by scout score (from `mv_kol_scout_score`) and swarm attraction rate. Returns per-KOL: scout_tier, scout_score, n_first_touches_30d, avg_followers_4h, best_scout_token. ULTRA only. - `GET /api/v1/tokens/{mint}/kol-consensus` — KOL buy/sell consensus on a specific token: total KOL buyers, total KOL sellers, exit_rate (sellers/buyers), median_entry_mc, avg_entry_mc, first_kol_buy_at, last_kol_buy_at, top KOL names. PRO+. - `GET /api/v1/tokens/{mint}/peak-history` — ATH market cap history for a token: mc_at_bond, post-bond MC snapshots at 1h/4h/24h intervals, all-time peak MC with timestamp, current MC, drawdown_from_peak_pct. PRO+. - `GET /api/v1/kol/coordination/history` — Historical coordination alert fires. Params: limit (1–100, default 50), since (ISO datetime), min_score (0–100). Returns past cluster events with participating KOLs, scores, MC at trigger time. ULTRA only. - `GET /api/v1/deployer-hunter/{wallet}/trajectory?include=daily_snapshots` — Extended deployer profile with daily tier/bonding snapshots: per-day tier, cumulative deploys, cumulative bonds, bonding_rate, notable tokens. The only param is `include=daily_snapshots`. All tiers (daily_snapshots requires PRO+). - `GET /api/v1/deployer-hunter/{wallet}/history?limit=` — **PRO+ (2026-07-05)** a deployer's **daily reputation time-series** — the backtest primitive for "was this deployer elite *at the time* it launched token X?" without look-ahead bias (the live tier already bakes in every deploy since). `limit` 1–365 (default 90) days. Returns `{ is_deployer, wallet, snapshots[] }` — each snapshot `{ date, tier, is_tracked, total_deployed, total_bonded, bonding_rate, recent_bond_rate, avg_peak_mc, best_token_peak_mc }`. Always returns 200 — unindexed wallets come back as `{ is_deployer: false, wallet, snapshots: [] }`. - `GET /api/v1/deployer-hunter/{wallet}/as-of?date=YYYY-MM-DD` — **PRO+ (2026-09-02)** point-in-time deployer reputation: the snapshot that was current on `date` (default today, UTC) — the latest write-on-change row at or before it, so a backtest sees only what was knowable then. Returns `{ is_deployer, wallet, requested_date, as_of, snapshot, first_snapshot_date, note }`; `snapshot` is `null` when nothing existed yet at that date (never synthesized). `date` must be ≥ 2026-04-07 and not in the future. - `GET /api/v1/deployer-hunter/{wallet}/rewards` — **PRO+ (2026-09-02)** pump.fun creator-fee rewards, answered two ways that are never merged: `collected` (fees that actually reached the wallet — direct claims, social-handle claims, shareholder payouts on any token) vs `attributed` (every fee payout on tokens the wallet itself deployed, including fees redirected to others). A deployer whose attributed total dwarfs its collected total is redirecting fees elsewhere (launch tool, KOL, social handle). - `GET /api/v1/wallet/{address}/flags?as_of=&history=` — **PRO+ (2026-08-28)** point-in-time wallet flags: "what did you know about this wallet on date D". For every flag source — `deployer` (tier, is_tracked/is_blocked/is_flagged, bonds, instant_bonds, runner_rate), `alpha` (bot_confidence, leaderboard_eligible, bucketed win/bundle rate), `dump_cluster`, `kol`, `sniper`, `bundler` — the latest write-on-change snapshot at or before `as_of` (default now). `carried: true` = recorded earlier and unchanged; `null` = no snapshot at or before `as_of` (we knew nothing then). `flagged[]` lists the sources active at `as_of`. `history=true` adds the change series (≤ 200). Snapshots since 2026-08-28, daily 01:20 UTC. - `GET /api/v1/manifests?dataset=&limit=` — **any key (2026-08-28)** as-of dataset manifests: one row per dataset per night, measured on the standby's replica — `rows_24h`, `min_ts`/`max_ts`, `row_count_estimate`, `schema_hash` (a flip means the data's shape changed) and `fingerprint` (md5 of dataset|max_ts|rows_24h|estimate). Cite the fingerprint in a report and it names the exact dataset state. Default = latest per dataset (14 datasets); `?dataset=` walks one dataset's history. ### Velocity / Volume Enrichment (shipped 2026-05-07) Every call to `GET /api/v1/token/{mint}` and `POST /api/v1/token/batch` now returns four additional fields keyed by 5m/15m/1h/2h/4h windows: - `mc_change_pct` — market-cap % change over each window. Sign encodes direction; magnitude encodes velocity. A `5m > 15m > 1h > 2h > 4h` gradient signals an accelerating parabolic move; inversed signals a fading pump. - `volume_usd` — organic (non-MEV) USD volume traded inside each window. USD value captured at trade time (not recomputed). - `mev_volume_pct` — % of each window's volume tagged as sandwich / Jito-bundle MEV. **Unique to MadeOnSol.** Lets traders flag wash-pump patterns: a token pumping 50% with `mev_volume_pct.4h: 47%` is materially different from the same headline pump at 5%. - `history_age_seconds` — how far back our in-memory ring covers for this token (capped 4h05m). Window keys are only present when the token has been tracked at least that long; SDKs should branch on `history_age_seconds` rather than probing for missing keys. - Reorg-safe: sourced from CONFIRMED-commitment Yellowstone gRPC subscription (~1-3s lag from chain head), not shred-level. Cumulative counters never roll back. - Window choice (5m / 15m / 1h / 2h / 4h) maps to memecoin lifecycle. Skipped 6h/24h because most memecoins don't survive that long; the 1h-2h-4h gradient is where pumps separate from fades. - Same fields are pushed per mint on the `token:prices` WebSocket channel (event `token:price`, mint-scoped, PRO+) and embedded in `kol:trade`, `kol:coordination`, `deployer:alert`, `deployer:bond`, `wallet_tracker:event`, and `copytrade:signal` events. Both `GET /api/v1/token/{mint}` and `POST /api/v1/token/batch` also return three launch-cohort fields per token: - `liquidity_to_mc_ratio: number | null` — `liquidity_usd / market_cap_usd`. Structural thinness gauge: a very low ratio signals thin liquidity relative to market cap (easy to move price, harder to exit large positions). - `launch_cohort_sol: number | null` — total SOL spent by the first 20 buyers of the token. - `launch_cohort_size: number` — count of first-20 buyers tracked (0–20; 0 if no early-buyer data is available). ### First-Touch Scout Signal Backtested first-mover signal — every "first KOL buy on a token mint" event, surfaced as a queryable + pushable feed. Per-KOL scout score (`mv_kol_scout_score`) ranks wallets by how reliably their first-touches attract follow-on KOLs. 38d backtest on 491k buys / 72,549 events: top scouts (S-tier) attract ≥3 follow-on KOLs within 4h ~50% of the time vs ~14% baseline. Public leaderboard at https://madeonsol.com/kol/scouts. - `GET /api/v1/kol/first-touches` — Recent first-KOL-touch events. Filters: `min_scout_tier=S|A|B|C` (requires n_first_touches_30d ≥ 30 unless `min_n_touches` lowered), `min_kol_winrate_7d`, `strategy`, `token_age_max_min`, `min_first_buy_sol`, `mint_suffix` (e.g. "pump"), `since`/`before` cursors. Presets: `?preset=scout` (B+ tier on tokens <60min) and `?preset=fresh_launch`. Optional `?include=followers_4h` attaches retrospective follower counts for events ≥4h old. ULTRA exposes `first_kol.wallet`. **Each event includes `market_cap_usd_at_first_buy` + `price_usd_at_first_buy` (cap stamped on the exact tx that fired) and `market_cap_usd` + `last_price_usd` (current) — added 2026-05-06.** **Median lead time before second KOL is 12 seconds — for trading, use the WebSocket channel below rather than REST polling.** - `POST /api/v1/kol/first-touches/subscriptions` — Create a webhook subscription (HMAC-SHA256 signed). Body: `{ name?, filters?: { kol?, mint_suffix?, min_first_buy_sol?, min_scout_tier?, min_n_touches? }, delivery_mode: "websocket"|"webhook"|"both", webhook_url? }`. Returns `webhook_secret` once. ULTRA and BUSINESS — up to 10 (ULTRA) / 50 (BUSINESS) active subscriptions. - `GET|GET|PATCH|DELETE /api/v1/kol/first-touches/subscriptions[/{id}]` — Standard CRUD. Mirrors `coordination/alerts`. - WebSocket channel `kol:first_touches` on `wss://madeonsol.com/ws/v1/stream` — pushed as they happen (PRO+). Filterable at subscribe time on the same dimensions. ### Sniper API — ULTRA+ ShredPrism supplies early **instruction observations**, not execution proof. ULTRA, BUSINESS and ENTERPRISE require an active subscription across REST, WebSocket and webhooks; BASIC/PRO have no sniper access. Keyless `/api/x402/sniper/recent` is retired before new payment handling. Historical stored paid answers retain payer-authorized recovery only. - `POST /api/v1/stream/token` advertises `early_ws_url` and `early_stream.channels` when the product is activated and the caller has access. Use the returned stream token at `wss://madeonsol.com/ws/v1/early`. - Six channel families are available (see the ShredPrism section). Supported outer Pump/LaunchLab creates are decoded from mixed legacy/v0/v1 messages. Unknown wrappers, CPI-only creates and other launchpads remain explicit gaps; no all-market coverage or timing lead is guaranteed. - `GET /api/v1/sniper/recent` — **ULTRA+** stored catch-up, newest first. Filters: `since`, `deployer_tier`, `min_bond_rate`, `watchlist`, `limit` (1–200, default 50). - `GET /api/v1/sniper/by-deployer/{wallet}` — **ULTRA+** actions for one instruction actor; `limit` 1–200. - `GET /api/v1/sniper/watchlist`, `POST /api/v1/sniper/watchlist`, `DELETE /api/v1/sniper/watchlist/{wallet}` — **ULTRA+** custom watchlist, max 50 deployers. - Compatibility WS channel `sniper:deploys` and webhook event `sniper:deploy` are ULTRA+ and delivered through asynchronous persistence. Direct early delivery does not wait for that work or enrichment. Watchlist/reputation filters apply to compatibility delivery; the direct endpoint supports `mints`, `actors`, `launchpads`. Deduplicate by `event_id`, never mint alone: actions within one signature are distinct. New fields include `source`, `outer_instruction_index`, `observation_stage`, `execution_status`, `transaction_version`, `transaction_config`, `fee_payer`. The instruction actor can differ from the fee payer. The initial observation has unknown execution; linked outcome frames contain separate RPC evidence. `confirmed_on_chain` is true only after a matching successful confirmed/finalized outcome. The REST footprint stays null for ShredPrism actions without that proof. V1 configuration preserves encoded requests, not consumed compute/paid fees: `config_mask`, exact decimal-string `priority_fee_lamports`, nullable `compute_unit_limit`, `loaded_accounts_data_size_limit`, `heap_size`. Missing is never zero. Historical rows can lack version/config information. The direct endpoint has bounded process-local ring recovery, live-first delivery and explicit gaps; it does not promise durable recovery across restart. See `docs/early-stream.md` for controls, outcome identities and gap handling. Service: `services/early-stream`; migration 475 adds action-keyed storage independently of historical `sniper_deploys`. ### x402 Protocol (Pay-Per-Request with USDC) AI agents can access data via the x402 payment protocol — no API key, no signup. Pay with USDC on Solana per request. - Discovery endpoint (free): https://madeonsol.com/api/x402 - KOL Trade Feed: GET /api/x402/kol/feed — $0.005 USDC/req. Each trade includes `market_cap_usd_at_trade` and `price_usd_at_trade` — token MC and USD price at the exact moment the swap fired (real-time, sourced from our in-memory price tracker). - KOL Coordination: GET /api/x402/kol/coordination — $0.02 USDC/req - KOL Leaderboard: GET /api/x402/kol/leaderboard — $0.005 USDC/req. Each entry includes `median_hold_minutes_30d: number | null` and `percentile_early_entry_30d: number | null` (0–100 percentile of early-entry rate vs all tracked KOLs over 30 days). - Deployer Alerts: GET /api/x402/deployer-hunter/alerts — $0.01 USDC/req. x402 params: since, limit, offset. The deployer-tier filter (`?tier=elite|good|moderate|rising|cold`) is on the keyed REST route /api/v1/deployer-hunter/alerts only. - KOL Trending Tokens: GET /api/x402/kol/tokens/trending — $0.01 USDC/req. Tokens ranked by KOL buy volume (5m–12h windows); buy/sell volume, net flow, KOL count + names. - KOL Affinity Pairs: GET /api/x402/kol/pairs — $0.02 USDC/req. Which KOLs frequently co-trade the same tokens (shared token count, agreement rate, shared mints). - KOL Momentum Tokens: GET /api/x402/kol/tokens/hot — $0.01 USDC/req. Tokens with accelerating KOL buy interest (acceleration score, net flow, participating KOLs). - KOL Token Entry Order: GET /api/x402/kol/tokens/{mint}/entry-order — $0.01 USDC/req. Ranked KOL first-buyers for a token: seconds_after_first, each KOL's 7d/30d winrate, early-entry %, percentiles, strategy tag, first-buy tx. - KOL Wallet Compare: GET /api/x402/kol/compare — $0.02 USDC/req. Compare 2-5 KOL wallets side-by-side (winrate, ROI, profit factor, PnL, hold time, percentiles) + the tokens they overlap on in 30d. ?wallets=a,b,c - KOL Live Alert Feed: GET /api/x402/kol/alerts/recent — $0.01 USDC/req. Unified feed: consensus clusters, fresh-token buys by winning KOLs (<30min tokens), heating-up wallets. ?window=1h|6h|24h&types=... - Wallet Stats: GET /api/x402/wallet/{address} — $0.005 USDC/req. Universal 90d wallet stats + cross-product flags (is_kol, is_alpha_tracked + bot_confidence, is_deployer). Any Solana wallet. - Wallet PnL: GET /api/x402/wallet/{address}/pnl — $0.02 USDC/req. FIFO realized + unrealized SOL, profit factor, max drawdown, hold-time stats, daily curve, closed + open positions. - Wallet Positions: GET /api/x402/wallet/{address}/positions — $0.01 USDC/req. Open positions only, with live unrealized P&L from the market-cap tracker. - Wallet Trades: GET /api/x402/wallet/{address}/trades — $0.005 USDC/req. Cursor-paginated raw trades, filter by action / token_mint / since-until. - Token Risk Score: GET /api/x402/tokens/{mint}/risk — $0.02 USDC/req. Transparent 0–100 token risk score with named factors (liquidity depth + thinness, mint/freeze authority, Token-2022 transfer fee, bundled/sniped open, deployer track record, supply inflation). Risk evidence an agent can check before a trade, not a safety guarantee. - Buyer Quality: GET /api/x402/tokens/{mint}/buyer-quality — $0.02 USDC/req. Early-buyer quality score (dump-cluster exposure, recycled-wallet rate, smart-money presence) with the live, out-of-sample Signal Scorecard efficacy stat attached. - Token Snapshot: GET /api/x402/token/{mint} — $0.01 USDC/req. Live token snapshot: price (USD/SOL), VWAP, market cap, FDV, liquidity, liquidity-to-MC ratio, primary DEX/pool, token-2022 + transfer-fee flags, and KOL buyer activity. - Signal Scorecard: GET /api/x402/signals/{name}/performance — $0.01 USDC/req. Auditable, machine-readable signal reliability (hit rate vs base rate, lift, sample size, test window) so agents can verify a signal before trusting it. `?history=true` adds the daily drift series. Signals: dump_cluster_count, runner_rate, recycled_early_buyer_count, coordination_count, scout_first_touch. Keyed twins: GET /api/v1/signals (catalog) and GET /api/v1/signals/{name}/performance (any key). - Token Cap Table: GET /api/x402/tokens/{mint}/cap-table — $0.02 USDC/req. First early buyers enriched with historical win rates, PnL, bot confidence, KOL identity, and in-token exit status (realized_pnl_sol, first_sell_at, still_holding). - Token Top Traders: GET /api/x402/tokens/{mint}/top-traders — $0.02 USDC/req. Every wallet that traded a mint ranked by realized SOL PnL or ROI, enriched with reputation flags. - Token OHLCV Candles: GET /api/x402/tokens/{mint}/candles — $0.01 USDC/req. 1m–1d candles: OHLC, USD volume, trade count, market cap per bar. - Token Trade Flow: GET /api/x402/tokens/{mint}/flow — $0.01 USDC/req. Organic-vs-wash-volume read: unique wallets/buyers/sellers, buy/sell SOL flow, trades_per_wallet proxy. - Almost-Bonded Radar: GET /api/x402/tokens/almost-bonded — $0.01 USDC/req. Pre-bond pump.fun tokens ranked by bonding velocity + ETA, enriched with deployer tier. - Sniper keyless access is retired: /api/x402/sniper/recent refuses new purchases. Use /api/v1/sniper/recent with an active ULTRA/BUSINESS/ENTERPRISE key. - Deployer Trajectory: GET /api/x402/deployer-hunter/{wallet}/trajectory — $0.01 USDC/req. Deployer skill curve: streaks, rolling bond-rate windows, improvement trend, deploy cadence. - Signal Catalog (free): GET /api/x402/signals — catalog of available signals (name, methodology, performance_endpoint). - Total keyless catalog: 25 endpoints — the free discovery endpoint always carries the live list + prices. - Parameters: each x402 route accepts exactly the query parameters its 402 challenge declares (`accepts[].outputSchema.input.queryParams`; the free discovery endpoint lists them as `params` per endpoint). Any other query parameter is refused with HTTP 400 before payment is verified or settled, so it is never charged: a known REST-only parameter answers `param_not_supported_on_x402` with the `rest_route` that implements it, anything else answers `undeclared_parameter` with `unsupported_params` and `allowed_params`. Matching is case-sensitive, cache-busters are not exempt, and declared parameters with an invalid value keep their own 400. The same rule applies to the Robinhood Chain x402 routes below. ### x402 on Robinhood Chain (dual-accept: USDG or USDC) The same pay-per-call, wallet-is-the-key model is live for Robinhood Chain (EVM, chain id 4663) intelligence — the first KOL & deployer *intelligence* API on Robinhood Chain payable per-call in USDG via x402. Every RHC endpoint advertises two payment legs (x402 accepts[]): USDG on Robinhood Chain (native, EIP-3009 transferWithAuthorization, $0.04 flat minimum) OR USDC on Solana ($0.005–$0.02) — the agent pays with whichever it holds. x402 is not USDC-only: USDG (Paxos Global Dollar) implements EIP-3009, so it supports the gasless transferWithAuthorization x402 requires. Settlement runs through MadeOnSol's own Robinhood Chain node + a self-hosted, non-custodial facilitator (USDG moves payer→payTo directly; no reseller, no custody). - Discovery (free): https://madeonsol.com/api/x402/rhc — Landing: https://madeonsol.com/robinhood/x402 - 10 endpoints (Solana-USDC leg price in brackets; USDG leg floors at $0.04): GET /api/x402/rhc/kol/feed ($0.005), /api/x402/rhc/kol/hot-tokens ($0.01), /api/x402/rhc/kol/leaderboard ($0.005), /api/x402/rhc/tokens/{address} ($0.01), /api/x402/rhc/tokens/{address}/buyer-quality ($0.02), /api/x402/rhc/tokens/{address}/kol-consensus ($0.02), and — added 2026-08-16 because the keyless rail skipped what a trading agent actually pays for — /api/x402/rhc/tokens/{address}/risk ($0.02, EVM-native rug score + live sell-simulation), /api/x402/rhc/tokens/{address}/holders ($0.02, wei-exact holder census), /api/x402/rhc/wallet/{address}/pnl ($0.02, FIFO wallet PnL), /api/x402/rhc/deployer-hunter/alerts ($0.01, tracked-deployer launch alerts). Delegated in-process to the v1 handlers, so responses match the equivalent keyed /api/v1/rhc/* endpoints exactly. ### SDKs & Integrations Solana packages: madeonsol (TS), madeonsol (Rust), madeonsol-x402 (npm and PyPI), mcp-server-madeonsol, @madeonsol/plugin-madeonsol, solana-agent-kit-plugin-madeonsol; the current published versions are on https://madeonsol.com/mcp. All accept an `msk_` key; the x402 packages also run keyless. Package table + MCP client config: https://madeonsol.com/mcp - Official TypeScript SDK: `npm install madeonsol` - Official Rust SDK: `cargo add madeonsol` - x402 TypeScript: `npm install madeonsol-x402` - Python (LangChain + CrewAI): `pip install madeonsol-x402` - MCP Server (Claude, Cursor): `npx -y smithery mcp add madeonsol/solana-kol-intelligence` (one-line via Smithery, https://smithery.ai/servers/madeonsol/solana-kol-intelligence) — also listed on Glama (https://glama.ai/mcp/servers/LamboPoewert/mcp-server-madeonsol) — manual: `npm install -g mcp-server-madeonsol` - ElizaOS Plugin: `npm install @madeonsol/plugin-madeonsol` - Solana Agent Kit: `npm install solana-agent-kit-plugin-madeonsol` ### Terminal realtime helper (token intelligence snapshot + WebSocket updates, released 2026-10-10) - Token intelligence REST, live since 2026-10-10, PRO+ API key: GET /api/v1/tokens/{mint}/intelligence?include=… (Solana) and GET /api/v1/rhc/tokens/{address}/intelligence?include=… (Robinhood Chain). No default include; at most 5 modules and total cost 8 per read (snapshot 2, risk 2, buyer_quality 2, holders 3, holder_count 1, flow 3, kol 1, locks 1, top_traders 2); each read is one API call. Every module carries its own status (ready, partial_history, unverified, unavailable, timeout), reason, as_of and provenance. Solana holders is excluded from the composite (use /api/v1/tokens/{mint}/holders). - Helper: `watchTokenIntelligence()` in madeonsol-x402 4.3.0 (`MadeOnSolREST.watchTokenIntelligence(mint, options)`) and robinhood-chain-x402 0.21.0 (`RobinhoodChainX402.watchTokenIntelligence(address, options)`, key mode only). Options: stream (one shared client.stream()), subId (unique per panel), tier, include, includeKolBroadcast, minModuleRefreshMs (default 15 s), debounceMs (default 750 ms), onChange, onLive; RHC adds includeRhcFirehose (ULTRA+). - Sequence: named subscription on the shared socket, wait for the ACK naming that sub_id and every channel, then ONE include-scoped REST read; price ticks (token:prices / rhc:token_prices) are a live overlay that never rewrites REST data or triggers a read; risk, locks, KOL and one-minute candle events mark only their module stale and trigger a debounced, per-module throttled re-read; on reconnect a fresh snapshot after the re-ACK; a reported replay gap keeps `incomplete: true` until the caller reconciles and calls acknowledgeHistoricalRecovery(). dispose() drops only that panel's subscription. - Browser panels: both packages export createTerminalTokenView, terminalStreamPort, planTerminalWatch and TERMINAL_MODULE_COSTS; the page gets a stream token and the intelligence read from the integrator's own backend, so the msk_ key never reaches the browser. - Not pushed: holders and holder_count (snapshot only; Solana holder_count is the timestamped last complete census). Risk channels report input and verdict changes, not a recomputed score. One-minute candles are a coarse trigger, not trade-by-trade coverage. KOL channels are unscoped roster broadcasts (opt-in); rhc:dex_trades is ULTRA+ and not address-filtered by the server (opt-in). x402 pay-per-call does not grant WebSocket access. - Streams, not to be conflated: the main stream wss://madeonsol.com/ws/v1/stream has 33 channels (17 Solana + 16 RHC) and NO token:intelligence channel; wss://madeonsol.com/ws/v1/dex-stream is the separate ULTRA+ Solana DEX firehose; ShredPrism wss://madeonsol.com/ws/v1/early (ULTRA+) carries provisional pre-confirmation observations, and an observation is not a confirmed fill. The helper uses only the main stream. - Docs: https://madeonsol.com/solutions/trading-terminals#realtime-bridge · https://madeonsol.com/api-docs#terminal-helper ### Robinhood Chain SDKs (standalone, shipped 2026-07-21: robinhood-chain-x402, PyPI robinhood-chain, robinhood-chain-sdk (TS), Rust robinhood-chain, mcp-server-robinhood-chain, @madeonsol/plugin-robinhood-chain, solana-agent-kit-plugin-robinhood-chain; current published versions on https://madeonsol.com/mcp) A separate SDK family for the `/api/v1/rhc/*` EVM-native surface, independent of the Solana `madeonsol` packages. Same `msk_` Bearer auth; the x402 RHC packages run in key-mode only (the x402 payment rail stays Solana-native). Mirrors under github.com/madeonsol. - TypeScript (core): `npm install robinhood-chain-sdk` - Rust: `cargo add robinhood-chain` - Python: `pip install robinhood-chain` - x402 TypeScript (key mode + keyless USDG pay-per-call from any EVM wallet, `createKeylessClient(privateKey)`, needs `viem`): `npm install robinhood-chain-x402` - Python keyless x402: `pip install "robinhood-chain[x402]"` then `RobinhoodClient(private_key=...)` — 10 endpoints, from $0.04, wallet needs USDG on chain 4663 but no ETH - MCP Server (Claude, Cursor): `npm install -g mcp-server-robinhood-chain` - ElizaOS Plugin: `npm install @madeonsol/plugin-robinhood-chain` - Solana Agent Kit: `npm install solana-agent-kit-plugin-robinhood-chain` ## Frequently Asked Questions ### What is MadeOnSol? MadeOnSol is the most comprehensive directory of Solana tools, dApps, and projects. It helps users discover, compare, and evaluate 1,250+ tools across 32 categories with community reviews, live uptime monitoring, and real-time on-chain intelligence. ### Is MadeOnSol free? Yes, the tool directory, comparisons, blog, yields dashboard, and rankings are all free. Deployer Hunter and KOL Tracker basic features are free. Some advanced features require a free account. ### How are tools ranked? Tools are ranked by a combination of community upvotes, review scores, and health status. There are no paid placements in the organic rankings. Featured/sponsored listings are clearly labeled. ### What is Deployer Hunter? Deployer Hunter tracks Pump.fun token deployers with historically high bonding rates (the rate at which their tokens complete the bonding curve — ≈85 SOL — and graduate to PumpSwap). Since 97-99% of Pump.fun tokens never bond, deployers with high rates are statistically significant. ### What is KOL Tracker? KOL Tracker monitors 2,000+ curated KOL wallets (Solana + Robinhood Chain) in real-time, detecting every trade within seconds. It provides a live feed, PnL leaderboard, and wallet comparison tools. ### How often is data updated? Tool uptime health: checked every 6 hours. Deployer Hunter: real-time (new deploys detected within seconds). KOL Tracker: real-time (trades detected within seconds). Yields: updated hourly. Rankings: updated daily. ## Agent Skills - [Agent Skills index](https://madeonsol.com/skills/index.json): read-only skills that teach agents how to use the API safely - [MadeOnSol Solana intelligence skill](https://madeonsol.com/skills/madeonsol-solana-intelligence/SKILL.md) - [Robinhood Chain intelligence skill](https://madeonsol.com/skills/robinhood-chain-intelligence/SKILL.md) ## ShredPrism six-family early stream (ULTRA, BUSINESS, ENTERPRISE) Channels: early:deploys, early:locks, early:trades, early:liquidity, early:migrations, early:token_changes on wss://madeonsol.com/ws/v1/early, discovered through POST /api/v1/stream/token (early_ws_url, early_stream.channels). Supported outer instructions only; no full wallet/venue coverage, realized fills or execution guarantee. Not available to BASIC/PRO or keyless x402. Solana only. Custom wallets, KOL/dev/alpha filters, account-private saved lists (ULTRA 10 x 100, BUSINESS/ENTERPRISE 20 x 500), exact raw-u64 amount rules, token helpers, compact-v1. Managed TypeScript client: madeonsol-x402 4.1.0+ (earlyStream()). Python/MCP/plugins do not include the managed early client. Payload contract by family: early:deploys carries create instruction, mint, actor, fee_payer, launchpad, name/symbol; early:trades carries swap_intent, protocol, pool, direction/mode, input/output mints and requested/max/min/target raw bounds; early:liquidity carries PumpSwap create_pool/add/remove plus pool/mints/LP mint and instruction-specific raw targets/limits; early:migrations carries source_curve, destination_pool and destination_venue; early:locks carries protocol-specific sender/recipient/lock account/mint/raw amount/schedule; early:token_changes carries mint/burn/freeze/thaw/set_authority authority fields and raw amounts where applicable. Exact nullable/missing-field semantics and examples are in the contract below. Contract: https://madeonsol.com/docs/shredprism-stream.md Solution, coverage and benchmarks: https://madeonsol.com/solutions/shredprism-stream Customer benchmark by channel, 2026-10-08 (one client at OVH in Limburg, Germany, public endpoint, 10 minutes, compared with Kaldera transaction notifications at processed and at confirmed commitment, matched by signature and slot): against confirmed, early observations arrived first in 94.6% to 99% of matched pairs per channel, median lead +273 ms to +332 ms (trades, launches, Token-2022 token changes, liquidity). Against processed the medians were -7 ms to +16 ms (trades +16.4 ms, first in 62.7%), with long tails both ways; not an "always before processed" result. Migrations and locks were not sufficiently measured; SPL Token token changes were not measured (no reference). Method and data: https://madeonsol.com/solutions/shredprism-stream#benchmark-by-channel Local development benchmark summary: https://madeonsol.com/benchmarks/shredprism-local-2026-10-07.json Local decoder/loopback results are development measurements, not a customer head start. Earlier launch-only client-side benchmark (2026-10-08; the per-channel benchmark above supersedes it and does measure processed): https://madeonsol.com/benchmarks/shredprism-client-2026-10-08.json: one client in the Netherlands over the public endpoint, three 10-minute windows: 515 of 515 matched launches arrived before the confirmed MadeOnSol DEX firehose (Kaldera Yellowstone, confirmed), median lead 290 ms, p95 459 ms. Processed-commitment comparison not measured on the customer path. Launch timing only; other channels counted for delivery. Observed in this benchmark, not a guarantee. Outcome-capacity gaps concern the later execution-status follow-up; they do not mean the already-published early:observed signal was missed. Source/decode/queue/replay gaps are separate and may affect observations. ## Agent Intelligence Gateway (PRO, ULTRA, BUSINESS, ENTERPRISE) Six research tools for AI agents, on Solana and Robinhood Chain: discover_opportunities, evaluate_token, inspect_wallet, inspect_deployer, evaluate_signal, changes_since. Each answer carries per-source evidence and a status of available, partial or unavailable; missing coverage is reported, never filled in. - REST: POST https://madeonsol.com/api/v1/agent-gateway/actions with {"tool", "input"} and Authorization: Bearer msk_... (PRO or higher; one call counts once against your normal quota). - Hosted MCP (Streamable HTTP): https://madeonsol.com/api/agent-gateway/mcp, the same Bearer msk_ key. No MCP OAuth, so OAuth-only connectors cannot use it. - Local MCP: mcp-server-madeonsol 4.1.0+ (Solana) and mcp-server-robinhood-chain 0.15.0+ (RHC) add the six tools with MADEONSOL_AGENT_GATEWAY_ENABLED=on and a paid MADEONSOL_API_KEY. - Limits: evaluate_signal (Signal Scorecard) is Solana only and answers unsupported on Robinhood Chain; changes_since replays seven curated KOL and deployer event families (four Solana, three RHC) with a 72-hour journal, not every swap; inspect_wallet returns the newest 50 open and 50 closed positions with true totals. - x402: no composite Gateway prices are offered; keyless agents keep the existing per-endpoint x402 catalog. Product: https://madeonsol.com/agent-gateway Docs: https://madeonsol.com/agent-gateway/docs Manifest: https://madeonsol.com/agent-gateway/manifest.json Skill: https://madeonsol.com/skills/agent-intelligence-gateway/SKILL.md