MadeOnSolMade on Sol
Pricing
Try freeGet real-time feedsSign in
MadeOnSolMade on Sol

Solana and Robinhood Chain intelligence — KOL wallet tracking, deployer intelligence, all-DEX trade streams, and a developer API. Discover, compare, and build.

Product

  • Solana Data API
  • Robinhood Chain API
  • Robinhood Chain x402
  • MCP Servers & SDKs
  • x402 for AI Agents
  • Pricing
  • Enterprise / For Businesses

Solutions

  • Trading Bots
  • Wallet Tracking
  • Copy Trading
  • Token Scanners
  • Trading Terminals
  • DEX Data
  • Smart Money
  • Token Risk
  • AI Agents
  • View all solutions

Developers

  • API Docs
  • WebSocket Streaming
  • Changelog
  • API Status
  • Latency Benchmarks
  • Data Integrity
  • Data Dictionary
  • Methodology

Resources

  • All Tools
  • Compare Tools
  • Best Trading Bots
  • Best DEXs
  • Best Wallets
  • Best Analytics
  • Best DeFi
  • Best Snipers
  • Blog
  • Blog Archive
  • Signal Scorecard
  • Tool Uptime
  • Community
  • Submit a Tool
  • Advertise

Company

  • About
  • Contact
  • Security
  • Privacy
  • Terms
  • DPA
  • Disclaimer

© 2026 MadeOnSol

MadeOnSol — eenmanszaak, Hulshout, Belgium · KBO/BTW BE 1039.535.538 (art. 56bis, no VAT charged)

Runs on our own dedicated EU servers — self-hosted data stack, own Robinhood Chain node · security

Follow us on XPowered by:constant·k — Private Solana RPC Services
SolutionsOnchain Analytics

Solutions · Onchain analytics

Solana analytics API: query history, then stay live

MadeOnSol serves Solana analytics products over two paths that share field names: REST endpoints for history and intelligence (launchpad trade tapes, 1-minute candles, KOL trades, deployer outcomes, point-in-time reputation) and WebSocket channels or signed webhooks for the events that change that state.

Browse the endpoint catalog See what each dataset keeps
Deployers profiledElite → cold · of 1.2M+ indexed
98K
KOL trades capturedSolana · tracked KOL wallets · kept forever
5.53M
Solana WebSocket channels
16
Datasets with published retention
13

A dashboard needs yesterday's numbers and today's changes in the same shape. Load history and intelligence once, then apply each event to that state instead of re-scanning the chain.

Free API key · plans from €43

A Free key reads deployer outcome stats, leaderboards, token context and dataset manifests, and the KOL feed 5 minutes delayed. Trade history, candles, point-in-time endpoints and live channels from Pro; the per-trade DEX firehose on Ultra and Business; monthly Parquet exports on Business.

Four layers, one set of keys

One question per layer, the surface that answers it, and its plan from the route or channel gate.

  • History

    What happened before the dashboard opened?

    GET /tokens/{mint}/tradesPro

    history.postgres_fromhistory.archive_usedcoverage.eligibility

  • Intelligence

    How do launches by each kind of deployer end?

    GET /deployer-hunter/alert-statsFree

    tiers.elite.bond_ratebond_rate.total_bondedmultiplier.pct_10x

  • Live

    What changed since the last read?

    deployer:alerts channelPro

    deployer:alertdeployer:bondid

  • Provenance

    Which dataset state produced this number?

    GET /manifestsFree

    fingerprintschema_hashdata_as_of

The problem

An analytics product is two systems: a history you can query and a live feed that keeps it current. Built on raw chain data, that means decoding each launchpad and venue, attributing launches to deployers and trades to known traders, storing months of rows, and making the live numbers agree with the stored ones after every restart.

Show me

Query history, then stay live

One dashboard panel: launch outcomes by deployer tier over 30 days. REST gives the starting state, the stream moves it, a timer reconciles. Keys are the route's and the emitters' own; values are illustrative and bodies abridged.

  1. 1 · Load the state

    alert-stats counts every deploy and bond alert in the window and breaks them out by tier (elite, good, rising). It works on a Free key.

    GET /api/v1/deployer-hunter/alert-stats (abridged)
    // GET /api/v1/deployer-hunter/alert-stats?period=30d
    {
      "bond_rate": { "total_deploys": 3120, "total_bonded": 702, "rate": 22.5 },
      "tiers": {
        "elite":  { "deploys": 210, "bonded": 131, "bond_rate": 62.4, "avg_multiplier": 12.4, "total_with_mc": 81 },
        "good":   { "deploys": 288, "bonded": 122, "bond_rate": 42.4, "avg_multiplier": 9.8, "total_with_mc": 86 },
        "rising": { "deploys": 371, "bonded": 109, "bond_rate": 29.4, "avg_multiplier": 6.1, "total_with_mc": 79 }
      },
      "period": "30d",
      "sampled_rows": 452,
      "truncated": false
    }
  2. 2 · Apply the events

    Subscribe to deployer:alerts (from Pro). Each deployer:alert adds a deploy, each deployer:bond a bond, under the tier in the frame.

    TypeScript · madeonsol-x402
    import { MadeOnSolREST } from "madeonsol-x402";
    
    const rest = new MadeOnSolREST({ apiKey: process.env.MADEONSOL_API_KEY! });
    
    // 1 · Initial state: the last 30 days of launch outcomes by deployer tier
    let state = await rest.deployerAlertStats({ period: "30d" });
    
    // 2 · Stay live: one frame moves one counter
    const stream = rest.stream();
    stream.on("deployer:alert", (a) => {
      state.bond_rate.total_deploys += 1;
      const t = state.tiers[a.deployer_tier];
      if (t) t.deploys += 1;
    });
    stream.on("deployer:bond", (b) => {
      state.bond_rate.total_bonded += 1;
      const t = state.tiers[b.deployer_tier];
      if (t) t.bonded += 1;
    });
    stream.subscribe({ subId: "launch-outcomes", channels: ["deployer:alerts"] });
    
    // 3 · Reconcile: the window slides and deployers change tier
    setInterval(async () => {
      state = await rest.deployerAlertStats({ period: "30d" });
    }, 5 * 60_000);
  3. 3 · What arrives

    A launch by an elite deployer, then its bond 18 minutes later. Both frames carry a stable id, so a replayed frame never counts twice.

    Frames on /ws/v1/stream (abridged)
    [
      {
        "channel": "deployer:alerts",
        "sub_id": "launch-outcomes",
        "event": "deployer:alert",
        "id": "deployer:alert:918273",
        "seq": 402551,
        "data": {
          "alert_id": 918273,
          "alert_type": "new_deploy",
          "deployer_wallet": "7vfC...rXs2",
          "deployer_tier": "elite",
          "token_mint": "8vdc...pump",
          "token_symbol": "NEW",
          "launchpad": "pumpfun",
          "bonding_rate": 0.64,
          "total_bonded": 41,
          "total_deployed": 64,
          "market_cap_at_alert": 6200,
          "tx_signature": "3xQm...",
          "slot": 449476601
        },
        "ts": 1790330400000
      },
      {
        "channel": "deployer:alerts",
        "sub_id": "launch-outcomes",
        "event": "deployer:bond",
        "id": "deployer:bond:8vdc...pump",
        "seq": 402987,
        "data": {
          "deployer_wallet": "7vfC...rXs2",
          "deployer_tier": "elite",
          "token_mint": "8vdc...pump",
          "token_symbol": "NEW",
          "launchpad": "pumpfun",
          "time_to_bond_minutes": 18,
          "instant_bond": false,
          "bonding_rate": 0.65,
          "total_bonded": 42,
          "total_deployed": 64,
          "market_cap_at_alert": 69400
        },
        "ts": 1790331480000
      }
    ]

the tiers need not sum to the totals

Totals count every alert in the window. The tier rows count alerts under each deployer's current tier, so deployers that have since dropped out of the tracked tiers are in the totals only.

sampled_rows and truncated

The multiplier statistics are computed over every alert with a market cap of at least $500 unless a safety ceiling is hit, and truncated says whether it was.

Same calls in other clients

  • TypeScriptrest.deployerAlertStats({ period: "30d" })
  • TypeScriptrest.tokenTrades(mint, { since, until })
  • TypeScriptrest.deployerAsOf(wallet, { date })
  • Pythonclient.deployer_alert_stats(period="30d")
  • Pythonclient.token_trades(mint)
  • MCPmadeonsol_deployer_alert_stats

Keeping them in agreement

When the live numbers and the REST numbers differ

Events only add. The REST aggregate is recomputed from storage on each read. These are the cases where the two part ways, and the fix for each.

WhenWhat happens to your numbersWhat to do
A deployer:alert or deployer:bond frame arrivesOne deployer_alerts row was inserted just before the frame, so one counter moves by one: deploys for an alert, bonded for a bond, under the frame's deployer_tier.Count each id once. The SDK drops ids it saw recently; a counter that survives restarts should store the ids it applied.
A deployer changes tierREST counts each alert under the deployer's current tier; a frame keeps the tier it had when it was sent. The per-tier numbers drift apart while the totals still agree.Re-read REST on a timer. To see the change as it happens, the wallet:scores channel sends deployer:tier_changed for the deployer wallets you list.
The period window slidesAlerts older than the 7d or 30d window leave the REST count; events only ever add. "all" is bounded too: alerts are kept 365 days.Re-read REST at least as often as your dashboard's resolution.
You re-read RESTThe aggregate is cached for 60 seconds, so a fresh read can trail the stream by up to a minute.Keep applying frames that arrive after the read, and compare with a minute of slack.
The socket dropsOn reconnect the SDK resumes from the last frame your handlers finished. The server replays from memory or rebuilds up to 60 minutes and 2,000 rows per channel from storage; rebuilt deployer frames carry the deployer's current stats, and replay_end says whether recovery was complete.When replay_end reports complete: false or the SDK emits a gap, re-read REST instead of trusting the counters.

Streaming reference for resume, replay_end and gap reporting.

Try it

See the data before you model it

The public demo key on the API docs calls GET /api/v1/deployer-hunter/alerts with no signup (20 calls per hour per IP). Those alert rows, alert_type new_deploy and bonded, are what alert-stats counts and what the deployer:alerts channel pushes. A free key adds alert-stats itself, the leaderboards and GET /token/{mint}.

Call deployer alerts with the demo key Get a free API key Deployer endpoint reference

Beyond raw RPC

Questions an RPC response cannot answer on its own

An RPC node returns transactions and account state. The questions an analytics product asks need attribution, prices you can reproduce, coverage you can read and a record of what was known when.

How do launches from strong deployers end?

From RPC:
A create instruction, and later perhaps a migration. Nothing links them to the wallet's earlier launches.
From MadeOnSol:
Every alert carries the deployer's tier and record, and alert-stats returns bond rate and market-cap multiples per tier.

deployer_tierbonding_ratetime_to_bond_minutestiers.good.bond_rate

What price did this trade execute at?

From RPC:
Pre- and post-balances for every account in the transaction.
From MadeOnSol:
price_sol is the trade's own sol_amount divided by token_amount; the pool price sampled near that slot is a separate field, so averages built from the tape are not biased by a lagging mark.

price_solmarket_price_solsol_amounttoken_amount

Does zero mean no trading, or no data?

From RPC:
An empty result looks the same either way.
From MadeOnSol:
Trade responses carry a coverage block: where history starts, the capture scope, whether the mint is eligible, lapsed, excluded or unknown, and completeness: not_verified.

coverage.history_startcoverage.eligibilitycoverage.completeness

What was known about this deployer on that date?

From RPC:
Only the current state; any label you compute today already includes the launches that came after.
From MadeOnSol:
Write-on-change reputation snapshots answer as of a date, so a backtest sees the tier and bond rate that were current then.

snapshot.tiersnapshot.bonding_ratesnapshot.carriedfirst_snapshot_date

Where did this page of history come from?

From RPC:
Whatever your own archive still holds.
From MadeOnSol:
The trade tape splits a page between Postgres and the Parquet archive and says so: history.archive_months, history.truncated and an X-Read-Source header.

history.archive_monthshistory.truncatedX-Read-Source

Which data produced the number in my report?

From RPC:
Nothing to cite.
From MadeOnSol:
Every response has an X-Request-Id, and a nightly manifest per dataset records rows, time range, a schema hash and a fingerprint you can quote.

X-Request-Idfingerprintschema_hash

Choosing the surface

Which part of the API each product need maps to

Plans come from each route's own gate and the channel table. For every swap on a venue, see DEX Data; this page covers what sits around it. Endpoint catalog

Product needUseWherePlan
Initial dashboard stateREST aggregates and lists, read once per view and on a timerGET /deployer-hunter/alert-statsGET /kol/leaderboardGET /token/{mint}From Free
Live updates to that stateWebSocket channels, or signed webhooks when your backend cannot hold a socketdeployer:alertskol:tradestoken:candlesFrom Pro; webhooks from Pro
Every swap on the venues you chartThe DEX firehose, a separate WebSocket with server-side filtersdex:trades on /ws/v1/dex-streamUltra and Business
Wallet activityThe Wallet Tracker for a watchlist; the Universal Wallet API for any addressGET /wallet-tracker/tradesGET /wallet/{address}/tradeswallet_tracker:eventsFrom Pro; the channel from Ultra
Token contextOne call for price, liquidity, deployer and KOL activity; per-token flow and candlesGET /token/{mint}GET /tokens/{mint}/flowGET /tokens/{mint}/candlesFree for /token; Pro for flow and candles
Trader contextKOL records and alpha-wallet scores, keyed by walletGET /kol/leaderboardGET /alpha/leaderboardGET /wallet/{address}Free for the leaderboards; Pro for any address
Backtests without look-aheadPoint-in-time reputation and wallet flagsGET /deployer-hunter/{wallet}/as-ofGET /wallet/{address}/flags?as_of=From Pro
Whole closed months in your warehousePresigned links to zstd Parquet filesGET /exportsBusiness
Field and dataset definitionsThe data dictionary, and the nightly manifests behind it/data-dictionaryGET /manifestsNo key for the page; Free for manifests

Historical data

How far back each dataset goes

MadeOnSol keeps the datasets it models, each with a stated start and window. It is not an index of every Solana program: trade history covers launchpad tokens, and anything outside the table below needs another source. Data dictionary · How the archive is verified

DatasetFromWindow and scopeRead it withPlan
Launchpad trade tape2026-04-12No retention window. Scope: the pump.fun pipeline (pump.fun, LaunchLab/bonk, bags), while each mint is inside its capture window. Older closed months come from the Parquet archive through the same endpoint.GET /tokens/{mint}/tradesPro
1-minute candlesJune 2026No retention window, no earlier backfill: candles are built as trades arrive and cannot be rebuilt later. Pro reads the last 30 days; Ultra the full history plus buy/sell volume and liquidity.GET /tokens/{mint}/candlesPro
KOL tradesNo window since 2026-06-05No retention window since 2026-06-05; rows older than the 180-day window that applied before were already deleted.GET /kol/feedFree (5 min delayed)
Deployer alerts and bondsRolling 365 daysAlerts older than 365 days are pruned, so alert-stats with period=all covers that window.GET /deployer-hunter/alerts, /alert-statsFree (alerts 5 min delayed)
Deployer reputation as of a datePer deployer (first_snapshot_date)Write-on-change snapshots, kept with no window. One known gap: 2026-07-10 has no snapshot and folds into the next day.GET /deployer-hunter/{wallet}/as-of, /historyPro
Wallet flags as of a date2026-08-28Write-on-change, kept with no window. Nothing earlier: before that date only the current flags exist.GET /wallet/{address}/flags?as_of=Pro
Wallet Tracker eventsRolling 120 daysEvents of your watched wallets older than 120 days are pruned.GET /wallet-tracker/tradesPro
Monthly Parquet filesEvery fully archived closed monthtoken_trades, rhc_trades, token_ohlc_1m, rhc_ohlc_1m. The open month is never exported; read it over REST.GET /exportsBusiness

Bulk exports · Live correctness checks · Label definitions

Architecture

From stored history and live events to your dashboard

  1. 1 · Source

    Chain activity

    Transactions and program events

  2. 2 · MadeOnSol

    Data and intelligence layer

    • Launchpad trade history and candles
    • Deployer, KOL and wallet intelligence
    • Point-in-time snapshots and manifests
  3. 3 · Delivery

    • REST API/api/v1 history and aggregates
    • WebSocket streamsdeployer:alerts · kol:trades · token:candles
    • Webhooksdeployer:alert · deployer:bond · kol:trade
  4. 4 · Yours

    Your state store and reconcile job

    Keys and business logic stay server-side

  5. 5 · Users

    Your dashboard or research tool

Build outcomes

What analytics teams build

  • Launch outcome dashboards by deployer tier
  • Token research pages with trade history and candles
  • KOL and alpha-wallet leaderboards
  • Backtests on point-in-time reputation
  • Warehouse loads from monthly Parquet files
  • Reports that cite the dataset state behind each number

Showing MadeOnSol data to your own users requires a Business plan. See pricing

Keep going

Related

Solution

DEX Data

The per-trade firehose, when the dashboard needs every swap.

Solution

Smart Money

KOL and alpha-wallet records to rank and chart traders.

Solution

Token Risk

Risk factors and deployer history per token.

Product

On-chain datasets

Schemas and free samples of the packaged datasets.

Guide

Solana datasets for quant research

Citation-ready data for studies.

Guide

Backtest a copy-trade strategy

Priced KOL trades in a backtest.

FAQ

Questions analytics builders ask

Do I need my own Solana indexer to build an analytics product?+
Not for the data MadeOnSol models: launchpad trade tapes, 1-minute candles, deployer outcomes, KOL and alpha-wallet records and point-in-time reputation come from the API with named fields. For programs and tokens outside that coverage you still need your own indexer or another source; the token trade tape covers the pump.fun pipeline (pump.fun, LaunchLab/bonk, bags), not every Solana program. The data dictionary lists each dataset and its window.
When does a dashboard need a stream instead of polling REST?+
When its numbers must move between page loads. Load the state over REST, apply events from a WebSocket channel (from Pro) or signed webhooks (from Pro), and re-read REST on a timer to reconcile. A dashboard refreshed every few minutes can poll REST alone; on Free the KOL feed and deployer alerts are 5 minutes delayed.
How far back does MadeOnSol's historical data go?+
It differs per dataset, and each window is stated. The launchpad trade tape starts 2026-04-12 and has no retention window; older closed months are served from a Parquet archive through the same endpoint. 1-minute candles start in June 2026 (Pro reads the last 30 days, Ultra all of it). KOL trades are kept with no window since 2026-06-05, deployer alerts for 365 days and Wallet Tracker events for 120 days. There is no history of every Solana program.
Does token_trades contain every Solana DEX trade?+
No. token_trades, the table behind GET /api/v1/tokens/{mint}/trades, stores trades of mints from the pump.fun pipeline (pump.fun, LaunchLab/bonk, bags) since 2026-04-12, and only while each mint is inside its capture window: pump.fun mints are captured until they resolve or for 7 days after bonding, and a later revival re-enters only above the revival floor. Trades of other tokens are not stored. Every response carries a coverage block (history_start, scope, eligibility, completeness: "not_verified") so an empty page is not read as "no trading". For the live parsed-trade stream on the venues MadeOnSol decodes, see the DEX firehose.
Can one dashboard combine market, wallet, token and trader intelligence?+
Yes, because the responses share keys. Trades carry wallet_address and token_mint, so a token view can call GET /wallet/{address} for KOL, alpha-wallet and bot flags, a wallet view can call GET /token/{mint} for price, liquidity, deployer and KOL context, and GET /kol/leaderboard adds each tracked trader's record. Deployer alerts carry deployer_wallet, the key for GET /deployer-hunter/{wallet}. The endpoint catalog lists the plan for each.
Can I load whole months into a data warehouse?+
On Business: GET /api/v1/exports lists every fully archived closed month of token_trades, rhc_trades, token_ohlc_1m, rhc_ohlc_1m and returns presigned links to its zstd Parquet files, valid for about an hour. The open month is not exported, so read it over REST. The files are licensed for use in your own product, not for resale.
Can this work alongside an existing RPC provider?+
Yes. Use MadeOnSol for the modelled layer (parsed launchpad trades, candles, deployer and trader intelligence, point-in-time snapshots) and your RPC provider for raw account reads and any program MadeOnSol does not decode.
Can teams prototype first?+
Yes. A free key from the developer page reads alert-stats, the KOL and alpha leaderboards, GET /token/{mint} and the dataset manifests right away, with the KOL feed and deployer alerts 5 minutes delayed. Trade history, candles, point-in-time endpoints and live channels start on Pro.

Next step

Load the history once, then let the events keep it current.

Check how the data is kept and verified, look at it in the browser, then pick the plan that carries your history and channels.

  1. 1 · ProofData integrity Point-in-time data, request IDs, the archive.
  2. 2 · TryTry the API without signing up Demo key, deployer alerts included.
  3. 3 · DocsData dictionary Every dataset and its window.
  4. 4 · PlanCompare plans History and live channels from Pro.