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
  • Agent Intelligence Gateway
  • Pricing
  • Enterprise / For Businesses

Solutions

  • Trading Bots
  • Wallet Tracking
  • Copy Trading
  • Token Scanners
  • Trading Terminals
  • DEX Data
  • Smart Money
  • Token Risk
  • AI Agents
  • ShredPrism Stream
  • 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
Changelog

Releases · public log

What shipped.
When and why.

Every meaningful change to the MadeOnSol API, the official SDKs, and the underlying infrastructure. The three most recent ship-notes render in full; older entries collapse into the archive below.

Read the docs Follow @MadeOnSolx

Velocity of this product

Live numbers — generated from this log on every revalidation.

177
Releases logged

Since Apr 7

7
Months of history

Full archive below

17
API ships

Endpoints + protocols

4.3.0
Latest Solana SDK

madeonsol — TS · Python · Rust

Recent

The latest three.

PlatformOctober 10, 2026#

Sniper confirmed_at is now the first confirmation; finalized_at added

On GET /api/v1/sniper/recent, ShredPrism rows now report confirmed_at as the time we first observed a successful outcome at confirmed or finalized commitment. A later finalization no longer moves it: the median is about 0.5 seconds after the observation, where it was about 7.4 seconds before because the finalization replaced it. The new finalized_at field is the time we first observed a successful finalized outcome (median about 7.3 seconds). Both are our observation times, not consensus timestamps, and neither is a detection lead. confirmed_on_chain and execution_status stay the current status, so a later failed or reorged outcome is still visible there. Legacy deshred rows are unchanged and have finalized_at: null.

PlatformOctober 10, 2026#

Sniper feed now states which history it stores

GET /api/v1/sniper/recent now returns a history block on every response, so you can tell legacy rows from recent ShredPrism rows. Legacy rows (source: "deshred") end at 2026-10-06T21:45:53Z, when the feed moved to ShredPrism (history.sources[].newest_row_at). ShredPrism rows (source: "shredprism") are deleted 6 hours after they are stored (retention_hours, retained_from). That is how long we keep them, not what we detect: those launches were delivered live before they were removed. Between the two nothing is stored, history.gap.from and history.gap.to mark that window, and an empty result inside it does not mean no tokens were deployed.

PlatformOctober 10, 2026#

Fee-claims feed: actor filter answers fast

GET /api/v1/tokens/fee-claims?actor=… could time out with a 503 (it scanned the whole event history for the requested wallet). It now uses a dedicated index and answers in well under a second for a wallet with a typical history, alone or combined with type=.

Archive

174 earlier ship notes.

Click any row to expand its full release notes inline. Grouped by month, newest first.

October 2026

36 ships
Oct 10Platform

Trading terminal SDKs: one snapshot, then live updates over your existing WebSocket

Both official TypeScript SDKs now include watchTokenIntelligence() for trading terminals: MadeOnSolREST.watchTokenIntelligence(mint, options) in madeonsol-x402 4.3.0 and Robinho…

Platform+

Both official TypeScript SDKs now include watchTokenIntelligence() for trading terminals: MadeOnSolREST.watchTokenIntelligence(mint, options) in madeonsol-x402 4.3.0 and RobinhoodChainX402.watchTokenIntelligence(address, options) in robinhood-chain-x402 0.21.0 (API key mode, PRO and up). You pass one shared client.stream(), a unique subId per panel, your tier and the include modules. The helper subscribes first, waits for the server to acknowledge exactly that subscription, then makes one include-scoped intelligence read. After that, price ticks (token:prices, rhc:token_prices) are a live overlay that never triggers a REST read, and risk, lock, KOL and one-minute candle events mark only the affected module stale and coalesce a throttled re-read of that module (default 750 ms debounce, at most once per module every 15 seconds, at most 5 modules and cost 8 per read). Nothing is polled while the stream is quiet. After a reconnect it takes a fresh snapshot; a replay gap the stream reports stays visible as incomplete until you reconcile it yourself, because a new snapshot does not replay missed trades. dispose() removes only that panel's subscription. Each module keeps its own status, as_of and provenance. Not pushed: holders and holder_count (the count is the last complete census with its measurement time). KOL channels are roster broadcasts and are used only with includeKolBroadcast: true; the Robinhood Chain trade tape needs ULTRA and includeRhcFirehose: true because it is not filtered by token on the server. There is no token:intelligence channel, and x402 pay-per-call does not grant WebSocket access. For browser terminals that must not hold an API key, both SDKs also export createTerminalTokenView, terminalStreamPort and planTerminalWatch, so a page can use a stream token and a read through your own backend. Guide: /solutions/trading-terminals and API docs.

Oct 10Platform

Solana holder count on first paint, with its measurement time

Token intelligence has a new module, holder_count (PRO and up, cost 1): GET /api/v1/tokens/{mint}/intelligence?include=snapshot,risk,holder_count. It returns the holder count fr…

Platform+

Token intelligence has a new module, holder_count (PRO and up, cost 1): GET /api/v1/tokens/{mint}/intelligence?include=snapshot,risk,holder_count. It returns the holder count from the last complete holder census of that mint, with as_of (when it was measured), slot, age_seconds and freshness. The module is ready when the count is at most 15 minutes old, unverified with reason stale_measurement when it is older (the count and its time are still returned), and unavailable with reason not_measured when no complete census exists yet: unknown is never shown as zero. Only a full ledger census is used: a top-20 view or an incomplete scan never becomes a holder count. A count is recorded whenever a complete census runs for GET /api/v1/tokens/{mint}/holders; there is no background refresh yet, so a token nobody has looked up reports not_measured. The full holder list stays separate at GET /api/v1/tokens/{mint}/holders. On Robinhood Chain the count stays in the holders module (concentration.holder_count).

Oct 10Platform

Robinhood Chain trades survive long database outages, restarts and ingest backlogs

The Robinhood Chain trade ingester no longer discards trades it cannot handle in time. During a long database outage it keeps unwritten trades up to a fixed memory ceiling, wher…

Platform+

The Robinhood Chain trade ingester no longer discards trades it cannot handle in time. During a long database outage it keeps unwritten trades up to a fixed memory ceiling, where it previously started discarding the oldest ones once more than 50,000 were waiting. Anything it still has to let go of (past that ceiling, when a waiting queue is full, or still in memory when the process stops) is recorded on disk as a block range that is owed, and those blocks are read again from our own Robinhood Chain node as soon as the ingester is healthy. A restart now writes every waiting trade before it exits, where it previously wrote at most 2,000. Trades that arrive this way keep their original amounts, transaction hash, log index and block time. A trade recovered more than 10 minutes after it happened has no USD price or market cap (price_usd and mc_usd_at_trade are null), because we do not apply today's price to an old trade; when it was paid in ETH it carries its ETH execution price (price_native) computed from the trade itself. Recovered trades never change a token's current price, candles or market cap.

Oct 10Platform

Token intelligence: pick the panels, get a status for each

New for PRO and up: GET /api/v1/tokens/{mint}/intelligence (Solana) and GET /api/v1/rhc/tokens/{address}/intelligence (Robinhood Chain) return the token panels you name in inclu…

Platform+

New for PRO and up: GET /api/v1/tokens/{mint}/intelligence (Solana) and GET /api/v1/rhc/tokens/{address}/intelligence (Robinhood Chain) return the token panels you name in include (snapshot, risk, buyer_quality, holders, flow, kol, locks, top_traders; Solana holders is not served through this endpoint yet and answers unavailable, use the standalone holders route) in one call. Each module is the same data as its individual endpoint and carries its own status (ready, partial_history, unverified, unavailable or timeout), as_of, source and history coverage. One slow or failing module never blanks the others, and a missing module is never shown as zero. Trade-based modules say partial_history because per-token trade completeness is not yet verified. There is no default include: up to 5 modules (total cost 8) per request, counted as one API call. SDKs: tokenIntelligence(mint, { include }) on MadeOnSolREST (madeonsol-x402 4.2.0) and tokenIntelligence(address, { include }) on RobinhoodChainX402 (robinhood-chain-x402 0.20.0, API key mode).

Oct 9Platform

Solana candles: bounded reads, a hard time limit, and opt-in partial results

GET /api/v1/tokens/{mint}/candles (and the x402 candles route) could answer 503 after about 8 seconds for a large window on a busy token, for example tf=1h&limit=1500, when part…

Platform+

GET /api/v1/tokens/{mint}/candles (and the x402 candles route) could answer 503 after about 8 seconds for a large window on a busy token, for example tf=1h&limit=1500, when part of the window fell in closed months on cold storage. One database read covered up to 999 buckets of 1-minute data.

Candles are now read in smaller time windows that grow while reads are fast. A request starts no new database reads after about 4 seconds and stops after at most about 7 seconds. Windows that fit the budget, including all recently read data, return complete as before.

When the budget runs out, the default answer is still 503, now with error_kind: "read_budget_exhausted", a Retry-After header and covered_from (how far the read got). A retry usually completes because the windows already read are cached. Add partial=allow to receive 200 with the newest complete candles, truncated: true and covered_from instead; request the older part with to set to covered_from. Partial results are never sent without that parameter, so a client that does not check truncated cannot mistake an early stop for the end of the history. Returned candles are always complete buckets, with no gaps or duplicates at window boundaries.

Oct 9Platform

Token depth: concentrated pools report availability per size

On GET /api/v1/tokens/{mint}/depth, Meteora DLMM and Raydium CLMM pools could be listed with depth_available: true even when none of the requested sizes could be quoted, and a o…

Platform+

On GET /api/v1/tokens/{mint}/depth, Meteora DLMM and Raydium CLMM pools could be listed with depth_available: true even when none of the requested sizes could be quoted, and a one-sided Meteora DLMM pair reported to_move_price as 0 SOL for 1%, 5% and 10%.

Now every quote on a concentrated pool carries available. A size that the pool's liquidity cannot fill keeps its status (for example exceeds_loaded_bins), has no numbers, and for Meteora DLMM adds fillable_up_to_sol, the SOL the pool can absorb. A pool where no requested size can be filled moves to unsupported_pools with dlmm_insufficient_liquidity_in_loaded_bins or clmm_insufficient_liquidity_in_loaded_ticks. to_move_price is a cost or null, never 0. The DLMM quotes we do serve were checked against the official Meteora SDK on the affected pools: identical tokens out and total fee. Meteora DLMM fees can legitimately be above 5% (dynamic fee, capped at 10% by the program).

Oct 9Platform

Agent Intelligence Gateway: six research tools for AI agents

AI agents can now ask MadeOnSol six structured research questions on Solana and Robinhood Chain: discover_opportunities, evaluate_token, inspect_wallet, inspect_deployer, evalua…

Platform+

AI agents can now ask MadeOnSol six structured research questions on Solana and Robinhood Chain: discover_opportunities, evaluate_token, inspect_wallet, inspect_deployer, evaluate_signal and changes_since. Each answer combines the existing API sources behind it and lists every source in evidence, with a status of available, partial or unavailable. Missing coverage is reported, never filled in.

Access is part of PRO, ULTRA, BUSINESS and ENTERPRISE. Call POST /api/v1/agent-gateway/actions with {"tool", "input"} and your msk_ key, or connect an MCP client to the hosted endpoint https://madeonsol.com/api/agent-gateway/mcp (Streamable HTTP, Authorization: Bearer msk_...). One Gateway call counts once against your normal daily quota. The hosted endpoint does not implement MCP OAuth, so connectors that only support OAuth cannot use it yet. The local MCP servers mcp-server-madeonsol 4.1.0 and mcp-server-robinhood-chain 0.15.0 add the same six tools when you set MADEONSOL_AGENT_GATEWAY_ENABLED=on; without it their tool list is unchanged.

Limits you can check: evaluate_signal (the Signal Scorecard) is Solana only and answers unsupported on Robinhood Chain. changes_since replays seven curated KOL and deployer event families (four on Solana, three on Robinhood Chain) from a 72-hour journal with signed cursors; it is not a feed of every swap or price change. inspect_wallet returns the newest 50 open and 50 closed positions with the true totals in positions_bounded; summary figures cover all positions and the full lists stay at /wallet/{address}/pnl. No x402 pay-per-call price is offered for the composite tools; keyless agents keep the existing per-endpoint x402 catalog.

Product page: /agent-gateway. Contract and examples: /agent-gateway/docs.

Oct 8Platform

ShredPrism customer benchmark by channel, against processed and confirmed

We published a dated customer-side benchmark of the ULTRA+ early stream for each channel, measured on 8 October 2026 from 20:04 to 20:14 UTC by one client at OVH in Limburg, Ger…

Platform+

We published a dated customer-side benchmark of the ULTRA+ early stream for each channel, measured on 8 October 2026 from 20:04 to 20:14 UTC by one client at OVH in Limburg, Germany, outside our network. The client used the public endpoint (wss://madeonsol.com/ws/v1/early) with a normal stream token and, on the same machine, Kaldera transaction notifications at processed and at confirmed commitment. Early observations (not outcomes) were matched to the reference by signature and slot, every receipt stamped on one monotonic clock.

Against confirmed notifications the early observation arrived first in 94.6% to 99% of matched pairs per channel, with median leads of +273 ms to +332 ms for trades, launches, Token-2022 token changes and liquidity. Against processed notifications the medians were between -7 ms and +16 ms (trades +16.4 ms, first in 62.7%), with long tails in both directions, so this is not an "always before processed" result. Migrations and locks had too few events in ten minutes to be timed, and token changes on the original SPL Token program were not measured because no matching reference feed is available.

The full table, the method, the client health during the run and a downloadable data set with SHA-256 are on the ShredPrism solution page. It is dated evidence from one client and one location, not an SLA.

Oct 8Platform

Early stream: outcome_source now names the status stream

early:outcome frames on the ULTRA+ early stream (wss://madeonsol.com/ws/v1/early) report where their execution evidence came from in outcome_source. Since the outcomes of early:…

Platform+

early:outcome frames on the ULTRA+ early stream (wss://madeonsol.com/ws/v1/early) report where their execution evidence came from in outcome_source. Since the outcomes of early:locks, early:trades, early:liquidity, early:migrations and early:token_changes are pushed by a finalized-status stream (see the entry below), those outcomes now carry outcome_source: "kaldera_status_stream". Outcomes found by a status lookup keep "kaldera_rpc": all early:deploys outcomes and the fallback for the other channels (for example token changes on the original SPL Token program). null still means no evidence was seen.

This adds a value to the field. A client that validates frames strictly against the published schema should accept kaldera_status_stream; the AsyncAPI document and the TypeScript types list it, and treat any unknown value as a valid source. Between 18:59 and the time of this entry these stream outcomes were labelled kaldera_rpc.

Oct 8Platform

Early stream: execution outcomes arrive when the chain finalizes

On 2026-10-08 the ULTRA+ early stream (wss://madeonsol.com/ws/v1/early) stopped resolving execution outcomes for early:trades and early:token_changes for several minutes at a ti…

Platform+

On 2026-10-08 the ULTRA+ early stream (wss://madeonsol.com/ws/v1/early) stopped resolving execution outcomes for early:trades and early:token_changes for several minutes at a time. Observations kept arriving in real time, but their follow-up early:outcome frames came back as resolution_status: "unresolved" with reason: "outcome_timeout", and some were replaced by early:gap frames with reason outcome_byte_capacity. The transactions themselves had executed normally. The cause was on our side: outcomes were found by checking transaction status on a fixed schedule, and that schedule fell behind during RPC slowdowns.

For early:locks, early:trades, early:liquidity, early:migrations and early:token_changes, the final execution status is now pushed to us as soon as the chain finalizes the transaction, instead of being checked on a schedule. A finalized outcome now typically arrives about 13 to 20 seconds after its observation (previously the first check ran 15 seconds after the observation and then every 10 seconds).

What did not change: the early:outcome frame and its fields (resolution_status, execution_status, commitment, error, reason, last_observed_outcome), one final outcome per observation for these five channels, unresolved after 120 seconds when no final status was seen (reason finalization_timeout or outcome_timeout), and a missing status is reported as unknown, never as failed. Observations are never held back for an outcome. early:deploys outcomes are unchanged and stay progressive (processed, confirmed, finalized).

Limitation: token changes on the original SPL Token program are resolved through a budgeted fallback, so their outcomes can arrive later or end unresolved more often under heavy load. Token-2022 token changes are covered by the pushed status.

While we fixed this, the five channels other than early:deploys were paused between 17:38 and 18:59 UTC on 8 October (with a three-minute trial at 18:05): POST /api/v1/stream/token listed only early:deploys and other subscriptions were refused. Launch observations and outcomes continued throughout. All six channels have been available again since 18:59 UTC, and the new outcome path was validated live before this entry was published: in a nine-minute sample every observation in all six channels received a finalized outcome.

Oct 8Platform

Fixed: signed-in users were logged out after brief connection problems

On 8 October some signed-in users on madeonsol.com were logged out and had to sign in again, in particular between about 17:20 and 18:20 UTC. When the website briefly could not …

Platform+

On 8 October some signed-in users on madeonsol.com were logged out and had to sign in again, in particular between about 17:20 and 18:20 UTC. When the website briefly could not reach our authentication service, it treated the failed check as an invalid session and removed the session cookies, although the session itself was still valid. The website now removes a session only when the authentication service explicitly rejects it. A network error, timeout or server error keeps you signed in, and the next page load checks again. API keys, WebSocket streams and webhooks were not affected.

Oct 8Platform

Deployer activity timeline: developer transfers and realtime dev trades documented

GET /api/v1/deployer-hunter/{wallet}/activity (PRO and above) serves the persisted realtime developer events next to the stored trade tape. The types filter and the event type a…

Platform+

GET /api/v1/deployer-hunter/{wallet}/activity (PRO and above) serves the persisted realtime developer events next to the stored trade tape. The types filter and the event type accept dev_token_transfer_out and dev_token_transfer_in alongside dev_buy and dev_sell, and coverage.families.dev_transfers reports that family (30 days online). Realtime rows carry actor_wallet, actor_role, token_amount_raw, supply_pct and feed: "realtime"; transfers add direction, counterparty, counterparty_class and counterparty_count. A developer buy or sell below the ordinary trade persistence floor can now appear as a realtime row. The OpenAPI spec, the TypeScript SDK types and the MCP tool description now list these fields and types.

Transfer detection is the union of the original bounded developer-wallet watch and the broad SPL Token and Token-2022 source for every developer we hold a creator record for (see the 6 October entry). transfer_watch_coverage describes the old watch only. Rows recovered after a delivery gap carry recovered: true and recovered_at; they are history only and were never sent on WebSocket or webhook. Their time_basis says which clock at uses: chain for a row rebuilt from a confirmed block, ingest for a row replayed with its original receive time.

Limitations: tokens without a creator record are not classified, source gaps can make a window incomplete, and an empty family is not evidence that nothing happened. A dated audit on 8 October found 214 of 228 developer buys, 133 of 152 developer sells, 1,321 of 1,321 outbound transfers in a sample dominated by token sprays, and 5 of 5 inbound transfers (too few for a percentage claim). These are sample measurements, not a guarantee.

Oct 8Platform

ShredPrism wallet and token streams for ULTRA and above

Since 2026-10-08, 06:03 UTC, the early endpoint (wss://madeonsol.com/ws/v1/early) serves six signal families instead of launches only. POST /api/v1/stream/token lists them in ea…

Platform+

Since 2026-10-08, 06:03 UTC, the early endpoint (wss://madeonsol.com/ws/v1/early) serves six signal families instead of launches only. POST /api/v1/stream/token lists them in early_stream.channels for ULTRA, BUSINESS and ENTERPRISE keys.

  • Six channels: early:deploys (launches), early:locks, early:trades (wallet trade intent), early:liquidity, early:migrations and early:token_changes. Each covers the supported outer instructions listed in the stream documentation, not every program or CPI.
  • Wallet filters: follow your own wallets, or the KOL, developer and alpha rosters (wallet_labels), and pick directions: ["buy"] or ["sell"].
  • Private saved wallet lists: account-private named lists attached with wallet_list. ULTRA: 10 lists of up to 100 wallets. BUSINESS and ENTERPRISE: 20 lists of up to 500. Managed over the WebSocket or the SDK; there is no dashboard editor.
  • Exact amount rules: up to four amounts rules on raw u64 instruction arguments (for example requested_input_raw of at least 1 SOL). These are requested limits, not executed fills, and not USD.
  • Token following and compact frames: follow known mints, and opt in to format: "compact-v1" for smaller frames (full JSON stays the default).
  • TypeScript client: madeonsol-x402 4.1.0 adds earlyStream() with reconnect, a safe checkpoint per subscription, bounded replay and explicit gap reporting, plus walletTrades() and followTokens() helpers. The Python package, MCP server and agent plugins do not include this client.

Coverage, pricing and dated benchmarks are published with raw results and methodology, in three separate categories. In a client-side benchmark on 2026-10-08 (one client in the Netherlands over the public endpoint, three 10-minute windows) all 515 matched launches arrived before the confirmed DEX firehose, with a median lead of 290 ms; a processed-commitment comparison was not measured on the customer path. The local development measurements of decoding and delivery are not a customer head start.

Limitations: an observation is provisional instruction intent and its execution outcome arrives as a separate frame. Observations are never held back for an outcome. Launch outcomes stay progressive (processed, confirmed, finalized); the five new families send one final outcome per observation, usually 15 to 25 seconds later, or unresolved after 120 seconds. Coverage is partial. Replay is bounded and process-local, never durable history, and the five new families have no REST or webhook history feed. MadeOnSol provides data, not trade execution. BASIC, PRO and keyless x402 have no access.

Oct 7Platform

Pricing reflects your current plan

The plan cards on Pricing and Solana Data API now show your current subscription and mark the lower plans that are already included in it. Paid customers no longer see Pro marke…

Platform+

The plan cards on Pricing and Solana Data API now show your current subscription and mark the lower plans that are already included in it. Paid customers no longer see Pro marked as recommended or purchase buttons for lower plans; higher plans remain available as upgrades, and Enterprise includes every self-service plan. While your account details load, or if they cannot be loaded, the cards stay neutral and show no recommendation or checkout button.

Oct 7Platform

Early stream: no more spurious lookup gap frames

The ULTRA+ early stream (/ws/v1/early, channel early:deploys) sent early:gap frames with reasons lookup_completion_timeout, lookup_capacity and lookup_timeout many times per sec…

Platform+

The ULTRA+ early stream (/ws/v1/early, channel early:deploys) sent early:gap frames with reasons lookup_completion_timeout, lookup_capacity and lookup_timeout many times per second. They did not mean a deploy was missed: every create observation is built only from keys that are always inside the transaction itself (program, mint, creator and fee payer), so address lookup tables never held one back. The service now waits for a lookup table only when a decoded field could depend on it, which for deploys is never. Deploy coverage and latency are unchanged and the spurious gap frames are gone, so a resume replays deploys instead of hundreds of gap frames. A gap frame now again means a real gap such as a source reconnect or a dropped batch.

Oct 6Platform

Sniper deploys now come from ShredPrism, with a dedicated early stream for ULTRA and above

Since 6 October 2026, 21:45 UTC, the Solana sniper feed is built from ShredPrism, the earliest data our provider offers (transaction entries as the leader produces them, before …

Platform+

Since 6 October 2026, 21:45 UTC, the Solana sniper feed is built from ShredPrism, the earliest data our provider offers (transaction entries as the leader produces them, before execution results). It powers GET /api/v1/sniper/recent, GET /api/v1/sniper/by-deployer/{wallet}, the sniper:deploys WebSocket channel and sniper webhooks. Rows from the new source carry source: "shredprism".

New early endpoint. ULTRA, BUSINESS and ENTERPRISE stream tokens (POST /api/v1/stream/token) now include early_ws_url (wss://madeonsol.com/ws/v1/early) and an early_stream block. Connect with the same stream token (preferably Authorization: Bearer) and subscribe to early:deploys. Each event is one recognized launch instruction: pump.fun and LaunchLab create variants, with separate creator and fee payer fields, one event per launch when a transaction contains several, an event_id built from the signature and instruction index for deduplication, transaction_version (legacy, 0 or 1) and the v1 transaction config where present (missing values are null, never guessed). The first message is the observation (observation_stage: "observed", execution_status: "unknown"); the execution result follows as a separate outcome message (succeeded or failed). An observation is intent, not proof: it can fail or never land.

Tier change. Sniper data (REST, WebSocket, webhooks and the early endpoint) now requires ULTRA, BUSINESS or ENTERPRISE. PRO and BASIC keys receive 403 tier_required on the REST routes, channels_rejected for sniper:deploys, and close code 4001 on the early endpoint. Webhook deliveries and buffered WebSocket frames recheck your current subscription before each send.

x402. The keyless /api/x402/sniper/recent endpoint is retired: it answers 410 x402_endpoint_retired without a payment challenge and charges nothing. Use an ULTRA or higher API key on /api/v1/sniper/recent.

Limitations. Only early:deploys is available; locks, liquidity, migrations, trades and token changes are not part of this release. Recovery on the early endpoint is bounded and process-local: after a server restart missed events are reported as an explicit gap, not replayed from history. The stream currently runs from one ShredPrism region (Frankfurt); during short host load peaks a small share of batches (about 0.6 % in our first measurements) is dropped and reported as a gap. Updated SDK types follow in the next SDK releases.

Oct 6Platform

Developer token transfers now covered for every known developer, not only 1,000 wallets

dev_token_transfer_out and dev_token_transfer_in events on dev:activity (WebSocket ULTRA and above, webhooks PRO and above) now come from a dedicated stream of every executed SP…

Platform+

dev_token_transfer_out and dev_token_transfer_in events on dev:activity (WebSocket ULTRA and above, webhooks PRO and above) now come from a dedicated stream of every executed SPL Token and Token-2022 transaction, matched against all developers we have a creator record for (about 1.4 million). Before, transfers were watched for at most 1,000 developer wallets at a time, about 1.3 % of eligible developers. The event shape, ids and tier projection are unchanged, and a transfer seen by both sources is delivered once.

When it was live. Live delivery ran from 17:56 to 19:08 UTC on 6 October, was paused while we fixed an unrelated throughput problem in our trade stream, and has been live again since 20:30 UTC, apart from the interruptions below. Between 19:08 and 20:30 UTC transfers of developers outside the old 1,000 were not delivered in real time. For 20:04 to 20:30 UTC they were recorded and have since been added to our stored event history (not redelivered on the WebSocket or by webhook). For 19:08 to 20:04 UTC they were not recorded. On 7 October from 02:05 to 04:52 UTC the stream stopped itself on a memory limit and transfers of developers outside the old 1,000 were not recorded either; a fix for that limit has been live since 05:07 UTC. Shorter interruptions (about a minute, for example at 05:08 UTC on 7 October) are recorded as gaps.

What we measured: on 40 random blocks every developer transfer we found independently was delivered (54 of 54), including developers outside the old 1,000, Token-2022 tokens and outbound transfers. In a delivery check after the restart, 25 of 25 events from developers outside the old 1,000 were identical on the WebSocket, in storage and on the REST activity endpoint, with no duplicates across a reconnect and replay.

Limitations. One region (Frankfurt) feeds this stream. Every published frame is kept on disk for 72 hours, so an interruption of the live consumer can be added to stored history later, but it is not redelivered on the WebSocket or by webhook. A transfer inside a transaction that also swaps on a DEX is left to the trade path and is not a transfer event. Several recipients of the same developer, token and direction in one transaction are one event (the largest recipient as counterparty, the total amount). Until 7 October 05:08 UTC, a developer moving tokens within about a minute of creating a token, before we recorded the creator, could be missed live (about 1 % of events in our checks; those were added to stored history afterwards from the 72-hour record). Since then such transfers are held and the creator is checked again before they are classified, instead of being dropped as not from a developer. The transfer_watch_coverage field on the dev_subscribed acknowledgement still describes only the older 1,000-wallet watch. A missing transfer event is therefore still not proof that no transfer happened.

Oct 6SDK

TypeScript SDKs: stream startup fix and types for every field the API serves

madeonsol 4.3.0 and robinhood-chain-sdk 0.16.0 (npm, released 2026-10-06) bring the stream startup fix already shipped in the x402 clients: calling connect() or subscribe() agai…

SDK+

madeonsol 4.3.0 and robinhood-chain-sdk 0.16.0 (npm, released 2026-10-06) bring the stream startup fix already shipped in the x402 clients: calling connect() or subscribe() again while the WebSocket handshake is still pending reuses the connecting socket instead of opening a second one and requesting a second stream token, channels requested during the handshake are sent once it opens, and close() during the handshake leaves no socket behind.

Both SDKs also now type the response fields the API already returns, so they are visible to TypeScript instead of arriving untyped:

  • madeonsol: copy-trade identity v2 on CopyTradeSignal (economic_action_id, source_actor, co_actors, identity_version); LP security on TokenSummary (lp_secured_pct, lp_secured_basis, lp_locked_until); launchpad and venue_source on almost-bonded tokens; ranks_completeness on the cap table; pool_selection and per-pool model_detail, pool_account, fee_basis, bins_window, ticks_window on token depth; label_coverage, rule_version and evidence_horizon on batch classify; the proven-holding fields on wallet PnL and positions (holding_check, position_basis, holding_status, holding_unverified_reason, cost_basis_status, holding); wallet_coverage on wallet funding.
  • robinhood-chain-sdk: pair_status on /rhc/trades rows (absent never means attributed), history_coverage on token holders, wallet_coverage on wallet funding.

Every new field is optional and the wire format is unchanged; nothing breaks for existing code. Upgrade the package to get the fix and the types.

Oct 6Platform

x402 clients: reliable stream connections during startup

madeonsol-x402 3.2.1 and robinhood-chain-x402 0.19.1 (npm, released 2026-10-06) fix a stream startup race. Calling connect() or subscribe() again while the WebSocket handshake w…

Platform+

madeonsol-x402 3.2.1 and robinhood-chain-x402 0.19.1 (npm, released 2026-10-06) fix a stream startup race. Calling connect() or subscribe() again while the WebSocket handshake was still pending opened a second socket and requested a second stream token. The stream client now reuses the connecting socket: channels requested during the handshake are sent once it opens, and close() during the handshake leaves no socket behind, before or after the handshake completes. No server change and no change to the stream wire format; upgrade the package to get the fix. The standalone TypeScript SDKs got the same fix in madeonsol 4.3.0 and robinhood-chain-sdk 0.16.0 (entry above).

Oct 5Platform

Copy-trade: one signal per independent trade action

Solana copy-trade rules now fire one signal per independent trade action instead of one per transaction. A followed wallet that makes seven separate buys in one transaction now …

Platform+

Solana copy-trade rules now fire one signal per independent trade action instead of one per transaction. A followed wallet that makes seven separate buys in one transaction now produces seven signals (it produced one before). A routed swap through several pools is still a single action and a single signal. When several wallets act in one transaction, each signal names the wallet that made that trade (source_wallet), and a rule that follows a wallet which is not the first tracked wallet in the transaction now receives its trade (it was missed before).

Webhook and WebSocket signals carry a new economic_action_id (solana:mainnet:<tx_signature>:<instruction path>) and co_actors (other followed wallets in the same action). Several signals can now share one tx_signature: deduplicate on economic_action_id, not on tx_signature. Rule filters (min_trade_sol, only_action, market-cap band) and proportional sizing apply to each action's own size, so a transaction of several small buys no longer passes a min_trade_sol that only the whole transaction would meet. Robinhood Chain copy-trade is unchanged.

GET /api/v1/copytrade/signals returns the same fields (economic_action_id, source_actor, co_actors, identity_version). Live since 2026-10-05, 20:12 UTC.

Oct 5Platform

Meteora DAMM v2 depth only from a verified pool

GET /api/v1/tokens/{mint}/depth now quotes a Meteora DAMM v2 pool only after reading its pool account live and checking that it belongs to the DAMM v2 program, has the expected …

Platform+

GET /api/v1/tokens/{mint}/depth now quotes a Meteora DAMM v2 pool only after reading its pool account live and checking that it belongs to the DAMM v2 program, has the expected layout, holds the pool's token vault, and covers the full price range (where the constant-product formula is exact). Such pools carry model_detail: "meteora_damm_v2_full_range" and pool_account. Every other DAMM v2 pool is listed in unsupported_pools with a reason instead of an estimate: damm_v2_pool_unknown (pool account not identified yet), damm_v2_single_range (a narrower price range, concentrated liquidity, no depth model yet), damm_v2_pool_unavailable, damm_v2_pool_not_found, damm_v2_pool_wrong_owner, damm_v2_unknown_layout, damm_v2_pool_vault_mismatch. The fee used for these quotes is still the venue default, not the pool's own fee schedule. Live since 2026-10-05, 20:15 UTC; pool accounts are proven as pools trade (774 in the first 17 minutes), so more DAMM v2 pools gain depth over time.

Oct 5Platform

Pool ids corrected on Meteora DAMM v2 and other non-Raydium pools

GET /api/v1/tokens/{mint}/pools returns amm_id per pool. On some pools that do not trade on Raydium (Meteora DAMM v2, PumpSwap, Meteora DLMM, Orca, launch curves) this field hel…

Platform+

GET /api/v1/tokens/{mint}/pools returns amm_id per pool. On some pools that do not trade on Raydium (Meteora DAMM v2, PumpSwap, Meteora DLMM, Orca, launch curves) this field held the id of an unrelated Raydium pool, for example the SOL/USDC Raydium CLMM pool, picked up from a routed swap before 2026-09-16. amm_id is now set only on Raydium pools and is null on every other venue. Pools first seen after 2026-09-16 were not affected. Corrected on 2026-10-05: 971 stored values cleared on active DAMM v2 pools, and every pool row our price tracker writes from now on.

Oct 5Platform

Token screener: lp_secured_pct (burned plus locked LP)

GET /api/v1/tokens now returns lp_secured_pct on every token: the share of the primary pool's LP that is burned or locked in a lock the sender cannot cancel, from 0 to 100. It s…

Platform+

GET /api/v1/tokens now returns lp_secured_pct on every token: the share of the primary pool's LP that is burned or locked in a lock the sender cannot cancel, from 0 to 100. It sits next to lp_burnt_pct, which keeps its burn-only meaning.

  • lp_secured_basis says what backs it: permanent (burned LP and/or permanent locks such as Raydium LP-Lock), temporary (only time-limited locks such as Streamflow), or mixed (both).
  • lp_locked_until is the earliest end of a counted temporary lock. Permanent locks have no date.
  • Sender-cancelable locks and expired locks are never counted.
  • null means unknown: no LP evidence yet, or a concentrated / position-NFT pool (Raydium CLMM, Orca Whirlpool, Meteora DLMM / DAMM v2). It is never reported as 0 when we do not know.
  • Coverage: Solana constant-product pools (Raydium AMM v4, Raydium CPMM, PumpSwap). Example: a Raydium CPMM pool whose LP is in a non-cancelable Streamflow lock reports lp_secured_pct 99.9986, basis temporary, while its lp_burnt_pct stays 0.

Limits today: the field is live on every token, but LP evidence has so far been computed for a first batch of tokens only, so most tokens read null (unknown) for now. A null never means "not secured".

Oct 5Platform

Developer trade history now reaches archived months

GET /api/v1/deployer-hunter/{wallet}/activity now returns the developer's own trades (dev_trades: the wallet trading a token it deployed) from archived months as well as from th…

Platform+

GET /api/v1/deployer-hunter/{wallet}/activity now returns the developer's own trades (dev_trades: the wallet trading a token it deployed) from archived months as well as from the months still in the live database, for ULTRA and BUSINESS windows. Archived months are served from a dedicated developer-sorted copy of the trade archive, so these reads stay within the endpoint's normal latency (measured 0.3 to 0.8 seconds). coverage.families.dev_trades.archive.served tells you whether the archive part of your window was served; when it was not, complete is false and archive_required_before marks the boundary, exactly as before. PRO windows are unchanged. Months covered: April 2026 onward.

Oct 5Platform

The developer's buy inside the launch transaction is now a dev:activity event

When a pump.fun developer buys their own token in the same transaction that creates it, that buy is now delivered as a dev_buy on dev:activity (WebSocket and webhooks) and appea…

Platform+

When a pump.fun developer buys their own token in the same transaction that creates it, that buy is now delivered as a dev_buy on dev:activity (WebSocket and webhooks) and appears in the developer timeline. Before, these creator buys were missed for part of new launches. Measured after the change: 286 of 286 new pump.fun launches with a creator buy produced the event.

Oct 5Platform

Robinhood Chain developer buys and sells, live on WebSocket and webhooks

When the recorded developer of a Robinhood Chain token buys or sells that token, you now get an event within seconds of the block.

Platform+

When the recorded developer of a Robinhood Chain token buys or sells that token, you now get an event within seconds of the block.

  • WebSocket: new channel rhc:dev_activity on the standard stream, ULTRA and above.
  • Webhooks: new event rhc:dev_activity, PRO and above. The payload is projected per tier exactly like Solana dev:activity.
  • Payload: the same shape as Solana dev:activity, with chain: "robinhood", signature = transaction hash, slot = block number and block_time = chain time. quote_amount is the ETH value of the trade and token_amount_raw the raw token amount.
  • Who counts as the developer: the wallet we recorded as the token's deployer. provenance.attribution is creator when we saw the launchpad creation, and pool_creator when we only know who created the first pool (a weaker signal you can filter out).
  • Filters: types (dev_buy, dev_sell), addresses (token), deployers, action.
  • Deduplication: dedupe on id. Several swap legs of one transaction are one event.

Limits, stated plainly:

  • Buys and sells only. A developer moving tokens to another wallet is not delivered, and no event does not mean no transfer happened.
  • Different wallets are not linked. A developer trading from a wallet other than the recorded deployer is not attributed.
  • Late events are marked. A token we had not seen recently is resolved after the trade. The event then arrives a little later and is marked provenance.late_classified: true.
  • Replay is limited. A reconnect gets the events still in memory. Older events are not replayed, though the trades themselves stay available through the trade endpoints.
Oct 5Platform

Stored trade history now includes the first seconds of new Meteora DBC launches

Since 5 October 2026, 15:07 UTC, /tokens/{mint}/trades and the other stored-trade endpoints keep the earliest trades of a new launchpad token, including the trades made before w…

Platform+

Since 5 October 2026, 15:07 UTC, /tokens/{mint}/trades and the other stored-trade endpoints keep the earliest trades of a new launchpad token, including the trades made before we finished recognising the launch.

Why it matters. Meteora DBC tokens (for example bags launches) often trade within seconds of being created. Our launch recognition used to refresh only every 10 minutes, so on a measured interval before this change only 29 percent of trades in new Meteora DBC tokens were stored. Trades of a token that is not yet recognised are now held briefly in memory and written as soon as the token is recognised, with their original receive time as block_time and their executed price.

Measured after the change, against an independent read of the blocks: 1,209 of 1,211 trades stored on a new Meteora DBC launch from its first trades (440 of 441 for Meteora DBC tokens), and 1,060 of 1,060 on a random interval.

Limits. Held trades are kept for up to 90 seconds and up to 400 per token before recognition; in our sample no recognised token came close to that limit. The store-size rules (coverage.size_floor) are unchanged. A token that migrates from its curve to a new pool was not part of the measurement.

Oct 5Platform

Realtime developer activity: dev sells, buys and token transfers as they happen

Since 5 October 2026, 03:24 UTC, when a token's developer sells, buys or moves their own token, we publish it as it happens: dev_sell, dev_buy, dev_token_transfer_out and dev_to…

Platform+

Since 5 October 2026, 03:24 UTC, when a token's developer sells, buys or moves their own token, we publish it as it happens: dev_sell, dev_buy, dev_token_transfer_out and dev_token_transfer_in. A transfer is never reported as a sell.

Where. Ultra and Business: the dev:activity channel on the DEX stream WebSocket (wss://madeonsol.com/ws/v1/dex-stream). Subscribe with {"type":"dev_subscribe","sub_id":"devs","filters":{"token_mints":[],"deployers":[],"types":[]}}; every filter is optional and replay serves recent events from an in-memory buffer with the same ids. The raw event is sent first, the moment the transaction reaches us (measured p99 about 1.7 ms from first arrival to the WebSocket), and a dev:activity_enrichment frame with the same id follows with price, market cap and holdings before and after. That second frame may never arrive; the first never waits for it. Pro and above: the dev:activity webhook event (POST /api/v1/webhooks, filters types, token_mints, deployers).

What each plan sees. Pro gets the developer's own events with the raw facts (wallets, counterparty, amounts, share of supply) and no identity fields. Ultra and Business additionally get identity fields and events from other wallets of the same developer, only where that link is proven. Deduplicate on id (dx1:<signature>:<mint>:<type>:<actor>): it is the same across both of our regions, reconnects and replay.

Coverage. Every token we hold a creator record for is covered, whatever its age: a developer who has been dormant for weeks is classified on their first trade. The developer does not need to be ranked in Deployer Hunter, and you do not register wallets. Measured over one hour against our stored creator trades: 2,196 of 2,197 developer sells detected (99.95 %), and no false sells.

Limitations. The developer's buy inside the token's own create transaction is not a dev_buy event; it is reported on the new-deploy event as before. Transfer coverage is partial: we watch up to 1,000 developer wallets at a time, the most recently active ones (about 1.3 % of eligible developers), and the dev_subscribed acknowledgement reports the current transfer_watch_coverage. A missing transfer event is therefore not evidence that no transfer happened. Tokens with no creator record are not classified. Events are stored for 90 days (buys and sells) and 30 days (transfers). The deployer activity timeline (GET /api/v1/deployer-hunter/{wallet}/activity) keeps serving the developer's own buys and sells from our stored trade history; realtime transfer events are not on that endpoint yet.

Oct 5Platform

DEX stream: swaps paid in USDC or USDT are sized correctly

Some swaps are paid in USDC or USDT instead of SOL, for example pump.fun trades through its USDC route (about 50,000 a day since 2 October). We sized every swap by the SOL it mo…

Platform+

Some swaps are paid in USDC or USDT instead of SOL, for example pump.fun trades through its USDC route (about 50,000 a day since 2 October). We sized every swap by the SOL it moved, and these move almost none, only about 0.0015 SOL of account rent. So about 92 % of them were marked dust: true and hidden from subscribers using the default min_sol of 0.05, even large ones.

Since 5 October 2026, 03:26 UTC, a USDC- or USDT-paid swap on dex:trades is sized by its stable leg, converted at a current SOL/USD price: sol_amount is the SOL equivalent, and dust, min_sol and max_sol use it. Example from production: a 13.59 USDC trade now reads sol_amount 0.1122 at SOL $121.07 and is not dust.

New fields, additive. sol_amount_basis is native_sol, stable_quote_equivalent or stable_quote_unconverted. stable_quote is null for a SOL trade, otherwise {mint, amount, usd_amount, sol_usd, sol_usd_observed_at, sol_usd_age_ms, status}. When no SOL/USD price from the last 5 minutes is available, the basis is stable_quote_unconverted and sol_amount is 0 (size unknown, read stable_quote.usd_amount), never the rent amount.

Unchanged. Swaps paid in SOL, swaps quoted in any other token, prices, market caps and candles. Stored trade history already sized these swaps by their stable leg, with the same conversion.

Oct 4Platform

Copy-trade rules can follow any wallet, on Solana and Robinhood Chain

Copy-trade rules can now follow any wallet, not only wallets in our KOL roster. On Robinhood Chain (/api/v1/rhc/copytrade/subscriptions) since 4 October 2026, 20:17 UTC, and on …

Platform+

Copy-trade rules can now follow any wallet, not only wallets in our KOL roster. On Robinhood Chain (/api/v1/rhc/copytrade/subscriptions) since 4 October 2026, 20:17 UTC, and on Solana (/api/v1/copytrade/subscriptions) since 20:29 UTC, a rule fires on its source wallet's trades whether or not that wallet is a tracked KOL. Being a KOL is now extra context on the signal (a name and a track record), never a condition for it.

Existing rules start firing without any change on your side: you do not need to edit their wallet list. A rule that lists wallets we did not track (previously reported as no_tracked_sources, or with an untracked_source_wallets warning on Robinhood Chain) now fires on those wallets' new trades. Trades made before the change are not replayed.

What the rule responses say now. Every rule carries source_admission: "any_wallet", and operational_state is eligible for any valid source wallet. The only states that are not eligible describe our side, not your wallets: monitoring_pending (you just changed the rule and our matcher has not loaded it yet, normally a few seconds), monitoring_unavailable (with monitoring_reasons; the matcher or the trade stream is unavailable, and rules do not fire from it until it is back) and source_capacity_unavailable. The untracked-wallet warning is no longer attached. source_wallets_tracked and source_wallets_untracked are still filled but deprecated: they only tell you which of your wallets are KOLs.

What did not change. Signals still fire only on realtime trades: a trade older than 10 seconds on Solana, or 5 seconds on Robinhood Chain, by chain time never becomes a signal. Each trade produces at most one signal per rule, also when the source is a KOL and the trade reaches us by two paths. Filters, sizing modes, delivery (the signals endpoint, webhooks and WebSocket channels) and the plan limits (Pro 3 rules × 5 wallets, Ultra 20 × 50, Business 100 × 250, counted per chain) are unchanged, and copy-trade source wallets do not count against your Wallet Tracker quota.

Chain details. On Solana, a followed wallet's swap must clear the same size floor as KOL trades (0.05 SOL, or $3.50 when paid in USDC or USDT; USDC and USDT amounts are converted to SOL for sizing). A swap by a non-KOL wallet that is paid in another quote token (for example PUMP or a tokenized stock) does not produce a signal yet. For a non-KOL source, kol_name is null. On Robinhood Chain, the trader of a smart-account (ERC-4337) transaction is the account that submitted the operation, and signals gain kol_wallet_id, which is null for a non-KOL source.

Market cap on Solana signals from any wallet. GET /api/v1/copytrade/signals now returns market_cap_usd_at_trade and price_usd_at_trade for signals from non-KOL wallets too. They are recorded on the signal when it fires. Until this fix those two fields were null for a non-KOL source, and min_mc_usd / max_mc_usd left those signals out of the list. A signal whose market cap was unknown when it fired is still left out when you set either bound. Rule-level market-cap bands were not affected.

Market-cap filter applied before limit (5 October 2026). min_mc_usd / max_mc_usd on GET /api/v1/copytrade/signals used to be applied after limit, so a filtered request could return fewer signals than limit while more matching signals existed. The filter now runs first: limit=N returns up to N matching signals. Responses also carry next_cursor (pass it back as cursor for the next page), has_more and, when a market-cap bound is set, a scan block whose scan_truncated: true means more matches may exist past next_cursor.

Oct 4API

Deployer activity timeline: `GET /api/v1/deployer-hunter/{wallet}/activity`

A new Pro-and-above endpoint returns one newest-first timeline of what a token deployer did, built from data we already hold: launch, dev_buy and dev_sell (the deployer trading …

API+

A new Pro-and-above endpoint returns one newest-first timeline of what a token deployer did, built from data we already hold: launch, dev_buy and dev_sell (the deployer trading their own token), creator_transferred (with the raw from and to), fee_claim, funding_in and capital_out. The time window applies to each event's own time, not to the token's launch: a token launched 60 days ago and sold by its deployer yesterday shows up in a 30-day window.

Plan limits. Pro: a 30-day window and up to 100 events per page. Ultra: 365 days and 100 per page. Business: no window limit and up to 500 per page. A larger limit or an earlier since is clamped, and the response says so (pagination.limit_capped, plan.history.effective.clamped).

Limitations, stated in the response. dev_buy and dev_sell come from our stored trade history, so they follow its size floor (buys under 0.05 SOL, or under $3.50 when paid in USDC or USDT, are not stored). Trade months that have moved to our long-term archive are not read by this endpoint yet: when your window reaches past the live database, coverage.families.dev_trades.complete is false, complete_from names the first fully covered moment and coverage.status is partial. Ultra and Business windows therefore do not yet give complete trade history for the oldest months. The identity block (which other wallets belong to the same deployer) is not released: on Ultra and Business it reads identity.status: "not_available".

Clients. madeonsol-x402 3.2.0 adds rest.deployerActivity(wallet, opts), and mcp-server-madeonsol 3.6.0 adds the madeonsol_deployer_activity tool.

Oct 4Platform

Stored trade history keeps older tokens and covers more Meteora DBC and LaunchLab launches

Two coverage changes to the stored Solana trade history behind GET /api/v1/tokens/{mint}/trades, GET /api/v1/wallet/{address}/trades, wallet PnL and positions, buyer quality and…

Platform+

Two coverage changes to the stored Solana trade history behind GET /api/v1/tokens/{mint}/trades, GET /api/v1/wallet/{address}/trades, wallet PnL and positions, buyer quality and the other trade-derived endpoints.

No more capture window for tokens we track. Since 3 October 2026, 16:23 UTC, trades on tokens from our launch pipeline are stored for as long as the token trades. Before, we stopped storing a token's trades some time after launch, after it was resolved as dead, or when an old pump.fun curve fell below our revival threshold, so a token that came back to life later had a gap.

More launchpad tokens. Since 4 October 2026, 13:00 UTC, trades are also stored for tokens whose launch on Meteora DBC (for example bags) or Raydium LaunchLab (for example bonk) we saw on chain, even when the token never entered our launch pipeline. Tokens used as a quote currency or tokenized stocks are only treated as launchpad tokens when we saw their launch.

Same rules as before. The size floor is unchanged (buys under 0.05 SOL, or under $3.50 in USDC or USDT, are not stored). Both changes apply from their start time onward: earlier trades on these tokens are not backfilled. Live streams, prices, market caps and candles already included these trades and are unchanged.

The coverage block follows the live settings. eligibility is now resolved against the capture settings in force, not a fixed copy of them. An older, resolved pump.fun token now reads eligible with eligibility_basis: "pipeline_known" instead of lapsed, and a proven Meteora DBC or LaunchLab launch reads eligible with eligibility_basis: "launchpad_proven". When we cannot confirm the current settings, the answer narrows to unknown with eligibility_basis: "capture_state_unavailable"; it never claims more than we store.

Oct 2Platform

Token locks: who runs the locker, explorer evidence, time to unlock

Every row on GET /api/v1/tokens/{mint}/locks, GET /api/v1/tokens/locks, GET /api/v1/rhc/tokens/locks and GET /api/v1/rhc/tokens/{address}/locks now carries five more fields. No …

Platform+

Every row on GET /api/v1/tokens/{mint}/locks, GET /api/v1/tokens/locks, GET /api/v1/rhc/tokens/locks and GET /api/v1/rhc/tokens/{address}/locks now carries five more fields. No existing field changed.

provider says who runs the lock contract and how sure we are: identity is verified (a known provider deployment), compatible (the contract emits the same events as a known provider, named in compatible_with, but its operator is not identified) or unverified. On Solana, Streamflow, Jupiter Lock and Bonfida are identified by their program id. On Robinhood Chain, identity is decided by the locker contract address, never by the event shape, because forks copy event shapes exactly: the HoodLock vault and vesting contracts, Sablier Lockup v4 and Titan Locker V2.1 are verified; every other locker, including PinkLock-, Team Finance- and UNCX-shaped contracts, is compatible and gets no provider id, website or link. lock_url points to the lock's own page on the provider's site only where that page format is proven (today: the HoodLock vault). Otherwise it is null; we do not guess one.

explorer links the lock account or locker contract and the creation transaction on Solana Explorer or Robinhood Chain Blockscout, so every row can be checked independently of us and of the provider.

price_usd is the token price behind the *_usd fields. seconds_until_end (0 once completed, null when there is no end date, or for a cancelled or closed Solana lock) and seconds_until_next_unlock save the date arithmetic.

Unchanged limits, now stated on every surface. Robinhood Chain locks are a create-only record: withdrawals and cancels are not observable there, so withdrawn_raw stays null (unknown, not zero) and the coverage block says withdrawals_tracked: false and cancels_tracked: false. LP locks carry LP-token or liquidity units (amount_unit), so they never get a USD value, a price or a percent of supply. Solana coverage is token and vesting locks; Solana LP locks are not included.

Oct 2Platform

Robinhood Chain wallets: holdings checked against the chain, and the holder census refuses a read that does not add up

Robinhood Chain holdings are now verified on-chain. Wallet positions on Robinhood Chain are built from DEX trades (first in, first out), so a token sent away by a plain transfer…

Platform+

Robinhood Chain holdings are now verified on-chain. Wallet positions on Robinhood Chain are built from DEX trades (first in, first out), so a token sent away by a plain transfer used to stay "held" forever, and the profile could say a wallet still held tokens it had long moved out. GET /api/v1/rhc/wallet/{address}, GET /api/v1/rhc/wallet/{address}/positions and the wallet scanner now read the current balance of every open position from our own Robinhood Chain node in one batch. Each position carries current_onchain_balance and a holding_status: HELD, PARTIALLY_REDUCED, TRANSFERRED_OR_DISPOSED (balance zero), EXTERNAL_INFLOW (more than was bought on a DEX; the excess has no cost basis and never counts as trading profit) or BALANCE_UNVERIFIED (the read failed or the token is non-standard: it gets no value and is never assumed held). A new holdings block (summary.holdings on /positions) gives the counts per status and verified_value_eth, the value of proven balances only. The existing fields (held_value_eth, open_positions, still_holding, token_amount, current_value_eth) keep their trade-based meaning, and /pnl is unchanged.

Contract addresses. A contract cannot sign a transaction, so a trading bot contract never appears as a wallet in our data, and its profile used to say "no Robinhood Chain activity". The 404 for such an address now carries address_type: "contract", the number of swaps it made as the trader in the last hour, and a note. Its activity is not merged into any wallet.

Holder census refuses a read that does not add up. GET /api/v1/tokens/{mint}/holders reads every token account of a mint. On fast-trading tokens that read can catch balances from different moments, and once it summed to 128.6 % of the supply, which produced a top-20 share of 122 %. A census whose balances add up to more than the mint's supply is now refused, and the response falls back to the top-20 view with holder_count: null and source.census_fallback_reason: "census_inconsistent_sum_exceeds_supply". source.note now names the actual reason for any fallback instead of always saying the provider refused.

Robinhood Chain copy-trade: can this rule fire? Every rule response now carries operational_state: eligible when at least one source wallet is a tracked Robinhood Chain KOL wallet, no_tracked_sources when none is (the rule is kept but can never fire), or unknown when we could not read the tracked set. It is separate from is_active, which stays your on/off switch.

Wallet scanner pages. Wallet results on /wallet and /robinhood/wallet now share one layout: identity, headline performance, intelligence, behavior, positions, recent activity, funding, then coverage. When one of our data sources fails, the page says so instead of showing "no recorded activity" or "no dataset flags". The shared-funders section now follows the API's tier split (Ultra and above). derived.biggest_miss on GET /api/v1/wallet/{address} was empty for busy wallets because the lookup URL grew too long; it is fixed.

Oct 1Platform

June trade history moves to the archive tier; wallet history over archived months is being fixed

Token history: unchanged for you. June 2026 Solana trades were moved out of our live database into the long-term archive, after the archive copy was checked row for row (108,752…

Platform+

Token history: unchanged for you. June 2026 Solana trades were moved out of our live database into the long-term archive, after the archive copy was checked row for row (108,752,540 trades, stored with two independent storage providers). GET /api/v1/tokens/{mint}/trades still returns June: archived rows come back on the same cursor and in the same order as recent ones, and a page that spans the end of June and the start of July is merged without gaps or duplicates. The response's history block shows which months came from the archive. Plan limits are unchanged: archived history is available on the same plans as before.

Wallet history over archived months: known limitation, fix in progress. Our first check after the move found that GET /api/v1/wallet/{address}/trades cannot reliably return trades from archived months (April to June 2026) for active wallets. The archive is laid out for token lookups, and a wallet query has to read too much of it to answer in time. When that happens the response does not pretend the history is empty: it returns history.truncated: true and history.archive_available: false. The default 90-day window is not affected. We are adding a second archive copy organised by wallet, so wallet lookups become as fast as token lookups. We are not moving June back into the live database to hide the problem. Until the fix ships, older months may come back incomplete; the response flags this.

September archive. September's Solana trades, Solana 1-minute candles and Robinhood Chain 1-minute candles are archived and verified with both storage providers. The Robinhood Chain trade archive for September failed on a database session timeout; that is fixed and the export is being redone. It is not marked complete until both providers verify it.

In review (not live yet): a fix that stops the daily safety-net job that fills missing peak market caps from failing when it collides with live price updates (it failed once, on 1 October; live prices were not affected), and a monitoring fix for schedules written as minute lists.

Oct 1Platform

Solana wallet profile: a failed lookup is flagged, not shown as empty

GET /api/v1/wallet/{address} combines a 90-day aggregate with several enrichment lookups. When one of them failed under load (for example a database timeout), its block came bac…

Platform+

GET /api/v1/wallet/{address} combines a 90-day aggregate with several enrichment lookups. When one of them failed under load (for example a database timeout), its block came back null or [], which looked exactly like a wallet with no data. Now stats_unavailable: true means the 90-day aggregate failed (stats: null is then unknown, not an inactive wallet), and enrichment_unavailable: true with degraded_fields names the blocks that failed (top_tokens, trading_style, deployer_breakdown, recent_trades, biggest_miss). Their values are unknown; retry later. Both fields are absent on a fully measured response.

September 2026

37 ships
Sep 30Platform

Trade tapes disclose their size floor

The stored trade history behind GET /api/v1/tokens/{mint}/trades, GET /api/v1/wallet/{address}/trades and POST /api/v1/tokens/batch/buyer-quality does not keep the smallest buys…

Platform+

The stored trade history behind GET /api/v1/tokens/{mint}/trades, GET /api/v1/wallet/{address}/trades and POST /api/v1/tokens/batch/buyer-quality does not keep the smallest buys: buys under 0.05 SOL (under $3.50 when paid in USDC or USDT) are not stored, while sells that receive SOL are kept at any size. This was stated for the live firehose but on no REST response. The coverage block now carries size_floor (min_sol, min_stable_usd, applies_to), and the API docs, data dictionary and FAQs say the same. Nothing about what is stored changed. Live streams, prices, market caps and candles are not built from this table and are not subject to the floor. KOL trades use the same values, on buys and sells.

Sep 30Platform

x402: a paid answer that never arrived can be recovered without paying again

Until now, if you paid for an x402 call and the response was lost on the way (a timeout, a dropped connection, a crashed client), the payment was spent and re-sending the proof …

Platform+

Until now, if you paid for an x402 call and the response was lost on the way (a timeout, a dropped connection, a crashed client), the payment was spent and re-sending the proof returned 409 replay_detected. You paid again to get the data.

Recovery. The first answer to every redeemed payment is now stored before it is sent. To get it back, re-send the same payment proof to the same URL with a PAYMENT-RECOVERY header signed by the paying wallet (ed25519 on Solana, EIP-191 on Robinhood Chain). The server returns the stored bytes unchanged, with X-Paid-Result-Sha256. A recovery never settles, signs or charges anything. If the original request failed after the payment was taken, the recovery runs it once and labels the answer as deferred. Stored answers are kept for 7 days.

What stays strict. A proof recovers only the request it paid for: another URL or other parameters return 409 payment_context_mismatch, a signature from another key returns 401, and changed payment terms return 402. Clients that do not send PAYMENT-RECOVERY still get 409 replay_detected, now with a code field.

Clients. Recovery is built in, bounded (8 attempts in 10 minutes by default, then resume()), and never spends budget on a new payment unless the server has confirmed the first one was not paid: madeonsol-x402 2.8.0, mcp-server-madeonsol 3.2.0, solana-agent-kit-plugin-madeonsol 2.2.0, robinhood-chain-x402 0.17.0 and robinhood-chain 0.16.0 on PyPI. Payment errors are a typed X402PaymentError, and the last paid result's provenance is available as lastPaidResult (Python: last_paid_result). The PyPI madeonsol-x402 client does not have recovery yet.

Sep 30Platform

Candles: no split bucket at page seams, the newest window on x402, and the Solana PRO window measured from now

Page seams. GET /api/v1/tokens/{mint}/candles, GET /api/v1/rhc/tokens/{address}/candles and the x402 candles route fetch long ranges in several pages. Page boundaries did not fa…

Platform+

Page seams. GET /api/v1/tokens/{mint}/candles, GET /api/v1/rhc/tokens/{address}/candles and the x402 candles route fetch long ranges in several pages. Page boundaries did not fall on the candle grid, so a response that needed more than one page could contain one candle built from only part of its bucket. Pages are now cut on the grid and a bucket is never split.

x402 returns the newest candles. A request such as 24 hours of tf=1m with limit=200 returned candles from about 7 hours earlier instead of the newest 200. It now returns the newest ones.

Solana PRO and x402 history window. The 30-day window is now counted back from the current time. It used to be counted back from to, so moving to into the past reached any 30-day slice of the full history. A request that lies entirely outside the window returns 200 with no candles and history_outside_plan: true (PRO also gets the usual upgrade hint); a partial overlap is clamped with history_clamped: true. history_floor shows where the window starts and is null on Ultra and above, which keep the full history. Robinhood Chain candles are unchanged: full history on PRO and above.

New fields on all three routes: truncated (the page budget ran out before limit or from was reached) and covered_from (the oldest time actually searched). No existing field changed. The docs now list the Solana limit as 1 to 1500, matching the API.

Sep 30Platform

Liquidity depth for PumpSwap pools that had no recent account update

GET /api/v1/tokens/{mint}/depth returned pumpswap_virtual_reserve_unknown for about 1,600 active PumpSwap pools whose virtual reserve was known from validated swap events but wh…

Platform+

GET /api/v1/tokens/{mint}/depth returned pumpswap_virtual_reserve_unknown for about 1,600 active PumpSwap pools whose virtual reserve was known from validated swap events but whose pool account had not changed since we started recording it. Depth now uses that validated event value when no decoded account value exists. A decoded account value still always takes precedence.

Sep 29Platform

Paying with SOL failed for part of 29 September

On 29 September, until 18:56 UTC, new SOL subscription orders could not be created and /api/sol-price returned 502: both outside price sources we used for the SOL/USD rate stopp…

Platform+

On 29 September, until 18:56 UTC, new SOL subscription orders could not be created and /api/sol-price returned 502: both outside price sources we used for the SOL/USD rate stopped answering (one removed its endpoint, the other rate-limited us). USDC and card payments were not affected.

SOL/USD now comes first from our own price feed, the same one behind every market cap on the site, refreshed every 10 seconds. Outside sources are only a fallback. A rate older than 120 seconds is never used: the order fails instead of being priced on a stale rate. /api/sol-price now also returns source and age_s next to price. We also added two monitors that check, around the clock and without charging anyone, that a SOL price is available and that a SOL order can be built, so a failure like this alerts us within minutes.

Sep 28Platform

Prices and market caps: no more pump.fun price spikes, and no dead pools after a restart

pump.fun spikes. For a moment after some small bot round-trips on a pump.fun curve, the price was computed from the trader's whole SOL change, which includes the rent for a new …

Platform+

pump.fun spikes. For a moment after some small bot round-trips on a pump.fun curve, the price was computed from the trader's whole SOL change, which includes the rent for a new token account. That could put the price about 1,500 times too high for around a second: enough to reach candle highs, the market cap stored on trades and, in some cases, a token's peak market cap. Since 28 September pump.fun curve prices come from the trade event and the curve's own state, and a price above what the curve can reach is refused. In the first 26,749 candles after the fix, no wick was 50 times or more above the candle. Candles and peak market caps recorded before 28 September are not corrected yet.

After a restart (29 September). Our price service restarts four times a day. After a restart it could pick a dead or outdated pool as a token's price source, for example a June pool quoting $61.86 for a token trading at $0.335, and a few minutes after each restart it wrote candles with no trades from long-inactive Meteora pools. Raydium CPMM pools now keep their price authority across restarts, graduated LaunchLab curves are no longer eligible, a pool account update without a swap no longer counts as recent trading, and the fallback no longer takes any pool just because it is the freshest.

Sep 26SDK

SDK and MCP correctness releases

SDK+
  • Keyless x402 clients fail fast on routes x402 cannot serve. madeonsol-x402 2.7.0 (npm) and madeonsol-x402 1.36.0 (PyPI): in keyless mode, peak history, KOL consensus, token bundle, the scout leaderboard and coordination history now raise KeylessNotAvailableError before any request or payment. Those routes are not priced for x402 and answered 404; with an API key they work as before.
  • Descriptions match the API. mcp-server-madeonsol 3.1.1, solana-agent-kit-plugin-madeonsol 2.1.1 and @madeonsol/plugin-madeonsol 1.28.1: token risk is described as risk evidence for your own policy, not a verdict, and the deployer profile names the real fields (is_deployer, deployer.total_tokens_deployed).
  • Keyless MCP setup on /mcp lists the payment policy the server has required since 3.0.0 (X402_PAY_TO, X402_FEE_PAYER, X402_MAX_AMOUNT_ATOMIC, X402_MAX_TOTAL_AMOUNT_ATOMIC, SVM_RPC_URL).
Sep 26Platform

Copy-trade signals fire only on realtime trades, and KOL trades missed during an outage are recovered

Freshness gate. A copy-trade signal now fires only while the source trade is realtime: at most 10 seconds old on Solana and 5 seconds on Robinhood Chain, measured by chain time.…

Platform+

Freshness gate. A copy-trade signal now fires only while the source trade is realtime: at most 10 seconds old on Solana and 5 seconds on Robinhood Chain, measured by chain time. An older trade, or one whose age cannot be established, produces no signal row, no webhook and no WebSocket frame. Until now a delayed source trade could still trigger a copy-trade: during an ingest backlog early on 26 September, some signals fired 60 to 390 seconds after the trade they copied. Across 14 days of normal operation the oldest source trade that fired was 9 seconds, so this changes nothing on a healthy day. The limit applies to Solana and Robinhood Chain copy-trade rules alike.

chain_time_estimate on kol:trade. The live kol:trade event carries a new nullable ISO field, chain_time_estimate: the block time of the nearest block at or before the trade's slot. It does not depend on how long our ingest took, so you can use it to judge a trade's age yourself.

Recovered KOL trades. When our KOL trade collector restarts or loses its connection, the KOL wallet trades it missed are now fetched again from the provider's replay and added to the KOL trade history. They keep their on-chain block time. Market cap and price at trade stay empty, because we do not reconstruct historical prices, and they never trigger a signal, an alert or a first-touch event. What the replay no longer covers is recorded internally as a gap. Gaps in the all-DEX trade tape are recorded too, but not refilled: the provider's replay of the full DEX feed proved incomplete, so we do not present it as recovered.

Sep 26Platform

Sniper feed: `detection_confirmed` works again

detection_confirmed on /api/v1/sniper/recent, /api/v1/sniper/by-deployer/{wallet} and the x402 sniper feed means that the deploy transaction was independently observed from both…

Platform+

detection_confirmed on /api/v1/sniper/recent, /api/v1/sniper/by-deployer/{wallet} and the x402 sniper feed means that the deploy transaction was independently observed from both of our Kaldera regions. It had not been set on any new detection since 2 September. The second region's copy of a transaction was always discarded before it could mark the row, and the rare true values before that date came from the same mint being recorded twice, not from two regions seeing the same transaction.

Since 26 September 14:30 UTC the flag is set again, with the documented meaning: only the same transaction signature delivered by the other region counts, and a repeat from the same region never does. In the first measurements every new detection was confirmed, typically within 75 milliseconds of the first copy. The first copy is still published and stored immediately; confirmation never delays a detection. Rows detected between 2 and 26 September stay false, because no record exists of whether the second region saw them.

Sep 26Platform

Complete 1-minute candles around our scheduled restarts

Our market-cap and candle service restarts four times a day. Until now the minute just before each restart was lost from the 1-minute candles (/tokens/{mint}/candles, token:cand…

Platform+

Our market-cap and candle service restarts four times a day. Until now the minute just before each restart was lost from the 1-minute candles (/tokens/{mint}/candles, token:candles): a few thousand tokens' candles for that minute were never written. Open candles are now written when the service stops. Price updates that arrive during the next start-up, about 8 seconds, are held and applied instead of being dropped. They update prices, market caps and volume; they are not added to that minute's candle trade count, to avoid placing them in the wrong minute.

Sep 25Platform

Copy-trade and webhook correctness, Business limits, and updated SDKs

Platform+
  • Business copy-trade rules take 250 source wallets, as sold. Creating or updating a rule was capped at 50 for every tier. Pro stays at 5 and Ultra at 50; Enterprise has at least the Business limits everywhere (webhooks, watchlist, streams, sniper). GET /api/v1/me adds features.copytrade_wallets_per_rule with the limit and your usage.
  • Solana copy-trade rules name untracked wallets. Responses list source_wallets_tracked, source_wallets_untracked and warnings[], the same as on Robinhood Chain. Only tracked KOL wallets can trigger a signal. Untracked wallets are still accepted.
  • Wallet-tracker webhooks (wallet_tracker:event) now apply the min_sol, action and conditions filters; before, they were accepted but not applied. Other filter names are rejected with 400 instead of being ignored.
  • Rule webhooks: setting webhook_url with a PATCH now creates a signing secret when the rule had none, for all rule types. A malformed signature no longer causes a 500, and an invalid market-cap band on PATCH returns 400 instead of 500. Test-fires send a payload that matches each event type's contract.
  • Endpoint tiers in the docs. The endpoint catalog listed 24 routes at the wrong tier: 11 shown as Ultra are available on Pro (including /webhooks) and 13 shown as Ultra are available on the free tier. The catalog is now derived from each route's access check. The webhook signature examples in the docs, blog and READMEs were corrected at the same time.
  • SDKs: madeonsol-x402 2.6.0 (npm) and 1.35.0 (PyPI), mcp-server-madeonsol 3.1.0, solana-agent-kit-plugin-madeonsol 2.1.0 and @madeonsol/plugin-madeonsol 1.28.0. Wallet-tracker responses are typed as events / next_cursor / next_cursor_slot (the old trades field never existed at runtime), with the order and before_slot parameters and only buy / sell as actions. Copy-trade gains the market-cap band on create, update and signals. The MCP server accepts 250 source wallets. The Solana Agent Kit and ElizaOS plugins now send subscription_id when you ask for one rule's signals; they used to send rule_id, which the API ignores, so every rule's signals came back. rule_id still works as an alias. None of these releases is breaking.
Sep 24Platform

Wallet tracker: no duplicate events when a provider region replays late

On 24 September one of our two data-provider regions delivered 20 to 25 minutes of already-processed transactions again, as if they were live. The wallet tracker stored 216 dupl…

Platform+

On 24 September one of our two data-provider regions delivered 20 to 25 minutes of already-processed transactions again, as if they were live. The wallet tracker stored 216 duplicate events for 6 subscribers between 13:29 and 13:34 UTC. Each event now has a durable identity (transaction, subscriber, wallet), checked in the database before it is stored or pushed, so a late copy from any region is dropped however long after the original it arrives.

Sep 24Platform

Solutions pages

New pages at /solutions show how to build common products on the API, with the endpoints, streams and code each one needs: trading bots, wallet tracking, DEX data, copy trading,…

Platform+

New pages at /solutions show how to build common products on the API, with the endpoints, streams and code each one needs: trading bots, wallet tracking, DEX data, copy trading, Telegram bots, trading terminals, token scanners, token risk and smart money.

Sep 23Platform

Live candles, risk-input changes and wallet-score changes on the WebSocket stream

Six new channels on wss://madeonsol.com/ws/v1/stream, all PRO+ and all scoped to the tokens or wallets you name: there is no firehose. Each channel has its own per-connection ca…

Platform+

Six new channels on wss://madeonsol.com/ws/v1/stream, all PRO+ and all scoped to the tokens or wallets you name: there is no firehose. Each channel has its own per-connection cap of 25 (PRO), 100 (ULTRA) or 250 (BUSINESS) tokens or wallets, separate from token:prices: 25 price mints, 25 candle mints and 25 risk mints fit on one PRO socket. A subscribe over the cap is refused, never truncated. Existing channels are unchanged.

Live candles: token:candles (Solana, filters.mints) and rhc:token_candles (Robinhood Chain, filters.addresses). Each closed 1-minute candle as it is stored (open, high, low and close price and market cap, volume, buy and sell counts), usually 10 to 25 seconds after the minute ends, with the id candle:<chain>:<token>:<bucket start>. On Robinhood Chain a stored candle that is rewritten later is sent again as rhc:candle_revised with a revision number. filters.updates: true adds the minute in progress, at most once per token per second. Minutes with no trades and no price move are not sent. In-progress updates are not replayed after a reconnect and there is no snapshot of the open minute on subscribe; closed candles are.

Risk inputs: token:risk (Solana, filters.mints) and rhc:token_risk (Robinhood Chain, filters.addresses). Solana: risk:authority_changed when a mint or freeze authority is revoked or a Token-2022 transfer fee changes, and risk:supply_inflated the first time a mint's supply drift crosses 0.5 % or 5 %. Robinhood Chain: rhc:risk_verdict_changed when a recheck stores a different contract-risk verdict, with the fields before and after. That recheck runs as a sweep, so the change happened somewhere between previous_checked_at and checked_at, which today is days to weeks apart, not within 24 hours. On subscribe you get the current inputs per token as a snapshot frame. These are changes to the inputs of the risk score, not a risk-band stream: the band moves with price, and GET /api/v1/tokens/{mint}/risk computes it.

Wallet scores: wallet:scores (Solana) and rhc:wallet_scores (Robinhood Chain), both scoped by filters.wallets. Deployer tier changes, including an unranked wallet entering a ranked tier, and KOL state changes (cold, heating up, strategy tag). Every frame carries source and computed_at: most of these values are recomputed on a schedule, so a frame says the recompute at that time found a new value, not that it changed at that moment.

Closed candles, risk events and score events resume after a reconnect like the other channels, from storage when needed (up to 60 minutes). Wire contracts and limits are in the API docs; the channel table is on /streaming.

Sep 23Platform

Liquidity events on Solana and Robinhood Chain, lock lifecycle events

Three opt-in additions to the WebSocket streams. A subscription that does not ask for them receives exactly the same frames as before.

Platform+

Three opt-in additions to the WebSocket streams. A subscription that does not ask for them receives exactly the same frames as before.

Solana: dex:liquidity on the DEX firehose (ULTRA). Add liquidity: true (alongside trades) or liquidity: "only" to a wss://madeonsol.com/ws/v1/dex-stream subscribe. Each liquidity instruction arrives as one dex:liquidity frame: action pool_created, add or remove, a stable id of <signature>:<instruction>[.<inner>], the pool, each token's raw amount and direction, the pool's vault balances before and after, share_of_reserves on constant-product pools, and material: true for a removal of 25 % or more of the reserves. Filters: token, wallet, pool, dex, program, actions, min_share_of_reserves, material_only. Limits, stated plainly: only instructions verified against a real transaction are emitted (the subscribe ack lists them), so some recognised deposit and withdrawal variants and every fee claim are not; concentrated pools (Raydium CLMM, Orca Whirlpool, Meteora DLMM) report depth as unknown because tick and bin ranges are not decoded; Meteora DAMM v1, Raydium LaunchLab and Moonshot are not covered; there is no USD value (min_usd is rejected); replay comes from the in-memory buffer only.

Robinhood Chain: rhc:lp_events (ULTRA). Every liquidity add, removal and pool creation on the Uniswap v2/v3/v4 pools we track, id rhc:lp_event:<tx_hash>:<log_index>. v3/v4 events say whether the position was in range of the current price and what share of the active liquidity moved (active_share), v2 events the share of reserves; material: true marks a removal of 25 % or more. When the pool's price tick was not yet known, the in-range and share fields are null rather than guessed. provider is usually the router or position manager, not the wallet behind it, and v4 events carry no token amounts (the protocol does not emit them). Filters: addresses, pools, dexes, actions, material_only, min_share. Resume rebuilds it from storage. The REST feed /api/v1/rhc/lp-events gains an optional action parameter (add, pool_created or all; the default is still removals only) and the same depth fields.

Lock lifecycle (PRO+). Subscribe token:locks or rhc:token_locks with filters.lifecycle: true. On Solana you then also receive claims, cancels, closes, top-ups and schedule changes, plus token:unlock_upcoming (the next unlock within 24 hours) and token:unlock_available (the unlock time has passed: the tokens are claimable per the schedule, which does not mean they were claimed). Streamflow's keeper-cranked automatic withdrawals, about 90 % of claims, are hidden unless you set include_automatic_claims: true. On Robinhood Chain only the unlock schedule is available: no locker there publishes a verifiable release or cancel event, so claims, extensions and cancels are not observable. Every event is deduplicated on the server, and nothing is sent for history after a restart.

Sep 22Platform

Named subscriptions: several independent subscriptions on one WebSocket

One socket can now hold several subscriptions, each with its own channels and filters. Until now a connection had one filter object for every channel it held, so a bot that want…

Platform+

One socket can now hold several subscriptions, each with its own channels and filters. Until now a connection had one filter object for every channel it held, so a bot that wanted KOL buys above 1 SOL and every deployer alert needed two connections. Everything is backwards-compatible: a subscribe without sub_id is the connection's default subscription, exactly as before.

Wire. {"type":"subscribe","sub_id":"kol-buys","channels":["kol:trades"],"filters":{"action":"buy","min_sol":1}} opens a named subscription (sub_id: 1 to 64 characters of A-Z a-z 0-9 _ . -) and is acked with subscribed {sub_id, channels, filters, seq, instance}. update {sub_id, filters} replaces that subscription's filters, unsubscribe {sub_id} removes it, and list answers subscriptions {list, count, max}. Refusals are warning frames that name the sub_id and one of invalid_sub_id, too_many_subscriptions, unknown_sub_id, invalid_filters, channels_rejected, replay_in_progress; nothing is dropped silently.

Delivery. A frame delivered under a named subscription carries sub_id. An event that matches several subscriptions is delivered once per matching subscription, each copy stamped with its sub_id, so dedupe by sub_id plus id. Filters of one subscription never affect another; tier gates, user scoping and plan-downgrade revocation apply per subscription, and channels_revoked names the subscription.

Caps. The number of subscriptions per connection, the default one included: Pro 5, Ultra 10, Business 20. token:prices mints stay capped per connection across all subscriptions (25 / 100 / 250).

Resume. Resume works per subscription: a subscribe with sub_id and resume replays only that subscription's channels through its own filters. A client holding several subscriptions re-sends each of them with the same cursor on reconnect; the server serves the replays one after another (the acks that wait say resume.queued: true) and holds live frames until the last replay_end. Commit the cursor after the last one, at the smallest last_seq / last_ts across them. The cursor itself stays per connection.

SDKs. subscribe({ subId, channels, filters }), updateSubscription(subId, filters), unsubscribe(subId), getSubscriptions() and listSubscriptions() in madeonsol-x402 2.3.0, madeonsol 2.29.0, robinhood-chain-x402 0.14.0 and robinhood-chain-sdk 0.10.0; subscribe(channels, filters, sub_id=...), update_subscription, unsubscribe("sub-id"), get_subscriptions() and list_subscriptions() in madeonsol-x402 1.32.0 and robinhood-chain 0.13.0 on PyPI. Every client dedupes per (sub_id, id), resumes each subscription and commits once all replays have ended, and warns once (named_subscriptions_unsupported) when a server ignores sub_id. The plain subscribe(channels, filters) API is unchanged.

Sep 22API

DEX firehose: per-pool swap legs, opt-in

The all-DEX firehose (wss://madeonsol.com/ws/v1/dex-stream, ULTRA and above) can now describe a transaction the way the chain executed it: pool by pool. Nothing changes unless y…

API+

The all-DEX firehose (wss://madeonsol.com/ws/v1/dex-stream, ULTRA and above) can now describe a transaction the way the chain executed it: pool by pool. Nothing changes unless you ask for it: the existing dex:trades frame is produced by the same code and stays byte-identical.

How to get it. Add legs: true to a subscribe (or legs: "only" if you do not want the legacy frame). Every transaction that matches your filters then arrives as one dex:route followed by one dex:leg per decoded pool swap, and then the usual dex:trades frame, exactly once per transaction.

What a leg is. One DEX instruction hitting one pool: program, venue, pool (with pool_kind saying whether it is the pool-state account or the vault authority), pool_authority, vault_in / vault_out, token_in (what the pool received, that is what the trader paid into this leg) and token_out (what the pool paid out), each with amount_raw as an exact integer string, decimals and amount_ui, plus side (buy or sell against SOL / USDC / USDT / USD1, null for token-to-token), amount_basis (whether the amounts came from the transfers nested under the instruction or from the account's balance change), and is_route_member. The id is stable: leg_id is <signature>:<instruction_index> for an outer instruction and <signature>:<instruction_index>.<inner_index> for an inner one, identical live, on replay and across our two ingest regions. Dedupe legs by leg_id.

What a route is. The whole path: hop_count, leg_ids, shape (single, chain when each leg feeds the next, split when one swap is spread over several pools or instructions, parallel for unrelated swaps in one transaction, mixed), the program the transaction entered through, and signer_net, the wallet's net change per mint, which is what the legacy frame approximates.

Honest about coverage. A route that touched a DEX we do not decode says decoded_complete: false and names the program in undecoded_program_ids; the subscribed ack of a legs subscription lists coverage.decodable_programs. Decoded today: pump.fun, PumpSwap, Raydium AMM v4 / CPMM / CLMM, Orca Whirlpool, Meteora DBC / DAMM / DLMM, LaunchLab and Moonshot; Jupiter v6 and the Raydium route program are routers whose inner legs are decoded. On a sample of 429 real trades at build time, 97.4 percent of routes were complete and every incomplete one was an unlisted DEX. Liquidity deposits and withdrawals are never reported as a leg; they are listed on the route as liquidity_actions.

What does not change. Volume, candles, prices and every REST aggregate keep counting one trade per transaction as before; legs are a second view of the same transaction, not a second trade. Replay emits the same frames with the same ids, marked replay: true; replay_done is unchanged.

Sep 22Platform

Robinhood Chain price ticks on the stream, and richer RHC trade payloads

rhc:token_prices, a tenth Robinhood Chain channel (PRO+). Subscribe with filters.addresses (25 addresses per connection on PRO, 100 on ULTRA, 250 on BUSINESS; a subscribe above …

Platform+

rhc:token_prices, a tenth Robinhood Chain channel (PRO+). Subscribe with filters.addresses (25 addresses per connection on PRO, 100 on ULTRA, 250 on BUSINESS; a subscribe above the cap is rejected, never truncated) and receive, for every address, first one snapshot: true frame with the current price row, then rhc:token_price ticks derived from the RHC trade feed at most once per address per 250 ms with the latest value. Every tick carries price_usd, market_cap_usd, liquidity_usd, source_pool, source_dex, observed_at (block time), price_age_ms, price_source and a quality of fresh, stale or unreliable with a quality_reason (no_price, dust_trade, curve_live, state_quote_fallback, low_liquidity, price_age, mc_ceiling). A stale or unreliable price is only ever delivered with its flag. Like token:prices, it is a state stream: no seq or id, not replayed; a resume gets a fresh snapshot.

Enriched rhc:dex_trade and rhc:dex_trade_unattributed payloads (additive). Every existing field keeps its name. New: amount_in_raw / amount_out_raw as exact decimal strings (uint256 never fits a float; do not parse them as numbers), token_amount_raw / quote_amount_raw, token and quote identity blocks with address, symbol and decimals (per-leg token_in_meta / token_out_meta on the unattributed channel), metadata_status (known / pending / unknown), price_status (fresh / stale / none) with price_source and price_observed_at, mc_status (why mc_usd is null), and side (buy / sell only when a canonical quote defines the token, else null with side_reason). A trade by a tracked KOL appears on both rhc:kol_trades and rhc:dex_trades with the same tx_hash + log_index and different event ids; a trade is on exactly one of rhc:dex_trades / rhc:dex_trades_unattributed. The durable backfill after a restart rebuilds the same keys and lists what it cannot (liquidity_usd, quote.usd, quote.observed_at) in missing.

SDKs. npm robinhood-chain-x402 0.14.0 and robinhood-chain-sdk 0.10.0 add the channel, the rhc:token_price event and the RhcDexTradeEvent, RhcDexTradeUnattributedEvent and RhcTokenPriceTick types; PyPI robinhood-chain 0.13.0 adds the channel and event name. @madeonsol/plugin-robinhood-chain 0.11.0 and mcp-server-robinhood-chain 0.12.0 carry the same types and descriptions.

Sep 22Platform

WebSocket recovery: resume after a disconnect or a server restart, and what was not recovered

A stream client can now pick up where it left off, including after we restart the stream service, and the server tells you exactly what it could and could not recover. Everythin…

Platform+

A stream client can now pick up where it left off, including after we restart the stream service, and the server tells you exactly what it could and could not recover. Everything new is opt-in: existing clients keep working unchanged.

Resume. Keep a cursor {instance, seq, ts} from the last frame your handler finished processing and send it on the next subscribe as resume: {instance, seq, ts}. The subscribed ack echoes it with accepted: true. If the server is the same instance and your cursor is still in its in-memory buffer (the last 20,000 frames, about 6 to 8 minutes), the missed frames are re-sent from memory. Otherwise, for example after a server restart, each channel is rebuilt from storage from your cursor's time: up to 60 minutes back, 2,000 rows per channel and 20,000 rows in total (the Robinhood Chain DEX trade channels 10 minutes and 10,000 rows). Rebuilt frames carry seq: null and mode: "durable", plus partial: true and a missing list where a field is not stored. token:graduations and rhc:new_tokens have no stored source, so a resume re-sends only what is still in memory and reports the rest as a gap. token:prices gets one current price per watched mint.

Honest replay reports. Every resume, and every legacy replay_since_seq / replay_since_ts request, is now bracketed by replay_start and replay_end even when there is nothing to replay. replay_end reports sent, matched, complete and a reason, overall and per channel (backpressure, instance_changed, ring_truncated, window_exceeded, row_cap, source_busy, source_error, late_ingest_possible, not_reconstructable) plus retryable and, where it applies, retry_after_ms and resume_ts_hint; the existing count field stays. Save your cursor only when a recovery completes: on complete: true commit last_seq / last_ts; on a retryable incomplete recovery keep the old cursor and resume again (duplicates are dropped by id; a resume_ts_hint is only sent when every incomplete channel a retry could still fill hit the row cap, otherwise you resume from the cursor you already had; a permanently missing channel does not block it). Our SDKs do this for you. Rows that are written to storage late are not skipped, and a channel that cannot rule that out says so instead of reporting complete. When many clients resume at once, a resume can be told source_busy with a retry time. Frames that arrive live during a replay are held and delivered right after replay_end, without duplicates. The legacy fields still replay from memory only, but now say replay_truncated: true with a reason when your cursor is too old or from before a restart, instead of replaying nothing without a word.

What a gap says, and who decides. When a recovery cannot be completed, the report names the channels, the reason, whether it is permanent, the server's bounds and the RANGE that may be incomplete. It never states how many events are missing, because that cannot be known: backfill the range from REST if you need certainty. Our SDKs retry a retryable recovery on the same socket (up to five times per connection, with the counter reset on every reconnect; after that the gap says exhausted: true, the cursor stays put and the next reconnect resumes), and on a gap that can never be filled they report it first and then move the cursor past it. That last step is the client library's own decision, not your approval; set onUnrecoverableGap: "stop" and the stream keeps the cursor, stops delivering and reports fatal instead, so you decide.

Bounded, and it says so. A row is stamped when it is written, not when it commits, so a row with a lower id can appear after a read has passed it. The server now only lets your cursor advance across rows whose write had already finished, holds it a few seconds behind the present and re-scans the last minute on your next resume; frames are still delivered as they are read. Each channel reports its scheme and its bound in replay_end.channels.<channel>.watermark (with watermark_safe_ts overall). This is bounded recovery, not a completeness guarantee: a write that commits more than about 65 seconds after it was stamped can be missed, or about 6 minutes while a long-running transaction has the hold-back capped (holdback_capped_ms, which the channel's guarantee then says), and the Robinhood Chain DEX trade channels are bounded by the producer's 600 second freshness rule, so a trade that was already older than that when it was ingested is not recoverable this way at all.

Stable ids, at-least-once. The same event now has the same id whether it is delivered live, re-sent from memory or rebuilt from storage. Delivery is at-least-once: dedupe by id. Gaps in seq are normal and are not a sign of loss (seq is one counter per server process, shared by all channels and all customers). Frames can only be lost across a disconnect or a slow-consumer close (4008), and a resume reports what was not recovered.

Other stream changes. If our own event bus connection drops, the missed events are re-read from storage and delivered with replayed: true, recovered: "bus". After a plan downgrade, channels above your new plan are dropped with a warning frame code: "channels_revoked". Revoking or rotating your API key now also revokes the stream token: open sockets close with 4001 within about a minute and you mint a new token with the new key. On the DEX firehose, replay_done is always sent and reports sent, requested, matched, complete and order; add replay_order: "asc" to receive replayed trades oldest-first. The firehose replay now waits for your socket, so live trades for that subscription can arrive interleaved with replayed ones (still marked replay: true) before replay_done. A copy-trade or coordination signal counts as delivered only once it was really written to one of your sockets; one that was queued for a socket still replaying and then dropped records delivery_error: "ws_replay_dropped". A replay that the socket cannot absorb now ends with complete: false and a 4008 close instead of piling up.

SDKs. The clients resume automatically, dedupe by id, retry a retryable recovery, report gaps as ranges and handle close codes; onUnrecoverableGap: "stop" (on_unrecoverable_gap in Python) turns off the automatic advance past a permanent gap. npm: madeonsol-x402 2.2.0, madeonsol 2.28.0, robinhood-chain-x402 0.13.0, robinhood-chain-sdk 0.9.0 and @madeonsol/plugin-robinhood-chain 0.10.1 on npm. PyPI: madeonsol-x402 1.31.0 and robinhood-chain 0.12.0.

pip install -U "madeonsol-x402[stream]"
pip install -U "robinhood-chain[stream]"

Older client versions keep working against the new server; they just do not resume automatically.

RHC price alert evaluation block. POST /api/v1/rhc/price-alerts still said the alert was polled every 15 seconds. RHC price alerts have been event-driven off the chain trade feed since 2026-09-15, with price-table polls and a trade-tape replay as safety nets, and land within a few seconds (still not sub-second like the Solana alerts). The response now reads mode: "event_driven" with trigger: "rhc:dex_trade" and fallback_poll_seconds: { fast: 5, slow: 60 }. The interval_seconds and note fields are still there, so existing parsers keep working; interval_seconds is now 5 (the fast fallback poll) instead of 15.

Documentation corrections.

  • The stream has 22 channels: 13 Solana and 9 Robinhood Chain. rhc:token_locks (one event per token lock or vesting contract created on Robinhood Chain, PRO and up; withdrawals are not tracked) was missing from several lists, and rhc:new_tokens was missing from the OpenAPI description.
  • kol:coordination and rhc:kol:coordination deliver only the fires of your own coordination alert rules. Some lists described them as broadcast channels.
  • token:price ticks carry no seq or id.
  • Subscribe filters apply to the whole connection. One filter object covers every channel on the socket, so action: "buy" also drops deployer alerts. Use a second connection for channels that need different filters.
  • The stream token does not expire (since 2026-08-27). Reference text that still described a 24-hour expiry has been corrected.
Sep 22Platform

Clearer plan pages: what the free tier is for, and what paying changes

The pricing page, homepage, navigation and developer dashboard now state the difference between the plans in the same words everywhere.

Platform+

The pricing page, homepage, navigation and developer dashboard now state the difference between the plans in the same words everywhere.

Free is an evaluation tier. On a free API key the live feeds are delayed 5 minutes: the KOL trade feed, KOL first touches, token KOL activity and entry order, deployer alerts and recent bonds on Solana, and the KOL feed, first touches, coordination, deployer alerts, recent bonds and the KOL activity on token detail on Robinhood Chain. Scores, leaderboards, wallet PnL, holder data and token search are not delayed on any tier. The delay itself has not changed; it has applied since 2026-08-31.

Paid plans have no intentional delay. Pro removes the 5-minute delay and adds webhooks, WebSocket streams and the rule engines. Ultra adds the DEX trade firehose, a higher burst rate, more WebSocket connections and deeper wallet intelligence such as linked-wallet clustering. Ultra is not only for teams: a single developer whose bot needs the firehose or the extra throughput is exactly who it is for. Business adds the embed license for one product of your own. Enterprise covers redistribution, white-label and contractual terms. Prices, quotas and license terms are unchanged.

Smaller changes. The pricing page leads with the plans and moves the database statistics, demo and trust information below them. After a successful call on a delayed feed in the developer dashboard, a short note says the data is 5 minutes behind and links straight to Pro checkout. The dashboard's "Run a sample call" button now returns the same delayed data as your free key would, instead of real-time rows. The delay_note text in delayed API responses was reworded; the delay, delay_seconds, as_of and upgrade fields and the X-Data-Delay header are unchanged. Signed-in paying customers no longer see free-tier prompts in the navigation or on the plan pages.

Sep 21Platform

Data-path audit: honest risk scores, complete aggregates and filters that page correctly

We audited how the Solana and Robinhood Chain APIs turn stored data into answers, and fixed the places where a missing or failed read could look like a clean result, where a sam…

Platform+

We audited how the Solana and Robinhood Chain APIs turn stored data into answers, and fixed the places where a missing or failed read could look like a clean result, where a sample was presented as a total, or where a filter quietly dropped matches. Some of these changes move numbers you may already rely on, so they are listed plainly below.

Risk score v2 (score_version: "v2"). One loader now serves the single, batch and x402 risk endpoints, so identical evidence gives an identical score on every transport. Batch and x402 previously scored without the supply-inflation input and could differ from the single endpoint.

  • A token-supply burn no longer earns the LP-burn credit. We do not observe LP-token custody for Solana pools, so every token without verified LP evidence now gets the same 8 points on the lp_burn factor, burned supply or not. This removes an unjustified credit. It is not a penalty for burning supply. The new fields token_supply_burn_detected and lp_burn_status report the two separately.
  • Every response carries an assessment: status is complete or incomplete, with unknown_inputs, not_assessed and an explanation per input. An incomplete assessment never reads safe.
  • Missing required creator information never yields safe, and that includes well-known tokens. A launchpad token whose creator we did not record, a failed creator lookup, or a creator with too little history is an unknown input. Creator reputation is only treated as not applicable for a token with no launchpad origin at all, and such a token can only read safe when its liquidity and liquidity-to-market-cap factors are healthy and its liquidity was observed within the last 6 hours. That window is a policy threshold, not proof of safety.
  • An unknown transfer fee is now a warning rather than "no transfer fee".
  • When a score-critical input cannot be read, the endpoint answers a retryable 503 (risk_inputs_unavailable) instead of a score computed without it. On the keyless x402 endpoint this check now runs before your payment is settled, so in that case you are not charged (charged: false).

Complete aggregates instead of samples. KOL activity on token endpoints, KOL entry order, entry market cap on the leaderboards, deployer market cap at alert, wallet overlap in compare and 24-hour volume in /token/batch are now computed over their full window in the database. Previously some of them were drawn from the newest 200 to 5,000 rows, so their values will change. Leaderboards and trending lists now say which fixed universe they rank (universe).

Filters and pagination. Filtered feeds, token lists and alert lists now keep scanning until they have enough matches (within a stated budget) and report has_more and a scan block honestly, instead of filtering one over-fetched page. The KOL feed and first-touch endpoints (Solana and Robinhood Chain) accept a strict cursor and return next_cursor, so no row is skipped when several share a timestamp. The existing before, after, since and offset parameters keep working.

Deprecated lp_burned filter. /tokens?lp_burned=true matches only verified LP burns and lp_burned=false only verified unburned pools. A token with unknown LP status matches neither, which today means both return nothing. Responses that use it carry a deprecations entry. Use supply_burn=true|false for the old supply-burn meaning.

Fields that can now be null. Where a read failed or was never observed, fields such as is_token_2022, transfer_fee_bps, burn_detected, is_blacklisted, launch_cohort_size, the KOL activity figures and price_is_stale are now null rather than false or 0. Buyer-quality confidence gains the value insufficient_data. last_trade_at on the token endpoints is now the newest trade seen by any of our pipelines.

SDKs. The typed clients describe the new fields: madeonsol-x402 2.1.0, robinhood-chain-x402 0.12.0, @madeonsol/plugin-madeonsol 1.27.0 and @madeonsol/plugin-robinhood-chain 0.10.0, with description updates in mcp-server-madeonsol 3.0.1 and solana-agent-kit-plugin-madeonsol 2.0.1. Existing installs keep working against the API; upgrade to get the types. @madeonsol/plugin-madeonsol 1.27.0 also fixes the ElizaOS GET_KOL_LEADERBOARD action, which in 1.26.0 and earlier threw an error when the plugin was configured with an API key.

The full field-by-field list is in the API docs and the OpenAPI spec.

Sep 21Platform

Keyless SDKs now require a spending policy (breaking)

New major versions of the pay-per-call (x402) clients are on npm: madeonsol-x402 2.0.0, mcp-server-madeonsol 3.0.0, solana-agent-kit-plugin-madeonsol 2.0.0 and robinhood-chain-x…

Platform+

New major versions of the pay-per-call (x402) clients are on npm: madeonsol-x402 2.0.0, mcp-server-madeonsol 3.0.0, solana-agent-kit-plugin-madeonsol 2.0.0 and robinhood-chain-x402 0.11.0. The Python robinhood-chain package shipped the same change as 0.11.0.

When one of these clients pays from your own wallet, it now needs an explicit payment policy before it will sign anything: the merchant address you trust, the most it may pay per request, and a total budget for the lifetime of the client. A payment request that names a different recipient, asset, network or a higher amount is refused before your wallet is asked to sign. On Solana you also set the trusted fee payer and your own RPC endpoint.

If you call the API with an API key, nothing changes and no new settings are needed. If you use keyless payments, installed copies keep running their current version until you upgrade. After upgrading, a client without a policy stops at startup instead of paying without a limit. The package READMEs have complete examples, and the MCP server and Solana Agent Kit plugin read the policy from X402_PAY_TO, X402_FEE_PAYER, X402_MAX_AMOUNT_ATOMIC, X402_MAX_TOTAL_AMOUNT_ATOMIC and SVM_RPC_URL.

Sep 20Platform

Funding intelligence now appears on wallet and deployer pages

The funding block that shipped on the API this morning is now rendered directly in the product. Open any tracked wallet or deployer and you will see where it was funded from: th…

Platform+

The funding block that shipped on the API this morning is now rendered directly in the product. Open any tracked wallet or deployer and you will see where it was funded from: the source address, the amount, the asset and when it arrived, alongside a plain statement of how much of that wallet's history we actually cover.

Pro accounts see the direct funding facts. Ultra and above additionally see the relationship view, meaning how many other tracked wallets and deployers share the same funding source. Free accounts see an upgrade prompt rather than the data, and that prompt is deliberately identical on every wallet, so it never reveals which addresses we hold evidence for.

Two presentation rules worth stating, because they are the whole point. An unlabelled funder is shown in exactly the same weight and colour as a named one, with no warning styling, because most funders are unknown and that is ordinary rather than suspicious. And a wallet with nothing observed says so plainly, including that this is not evidence the wallet was never funded.

Sep 20Platform

Realtime pipeline: the market-cap read stall is gone and copy-trade signals stopped hitting their timeout

The price engine used to run its headline sweep as one long synchronous pass. On a map of roughly 187,000 tokens that blocked the process event loop for most of a second at a ti…

Platform+

The price engine used to run its headline sweep as one long synchronous pass. On a map of roughly 187,000 tokens that blocked the process event loop for most of a second at a time, which every other consumer in that process then waited behind. The sweep is now cooperative: it yields every 20 ms and resumes where it left off, visiting every token exactly once per pass as before.

Measured on production against the same probe and sample size as the baseline:

  • internal market-cap reads: 27.9 percent of samples took longer than 250 ms, now 0 percent, with the worst sample falling from 1,423 ms to 136 ms
  • copy-trade signals reaching the 240 ms velocity timeout: 46.3 percent of 890 signals before, 0 percent after

Alongside this, wallet tracking now hands over between provider regions without dropping events, and any gap it cannot replay is recorded explicitly instead of passing silently. We also added correctness monitoring across the realtime stack, so a stalled loop or a frozen cursor is reported as a fault rather than hiding behind a healthy looking heartbeat.

Separately we measured the public WebSocket path end to end from outside our own network, as a customer sees it. Over a five minute window on wss://madeonsol.com/ws/v1/stream every published event arrived, in order, with no duplicates and none unaccounted for, at a median of 22 ms from publication to client receipt.

Sep 20Platform

Wallet funding evidence is live on the API, with Pro and Ultra seeing different depths

GET /api/v1/wallet/{address}/funding and GET /api/v1/rhc/wallet/{address}/funding now return a direct_funding block answering "where did this wallet's money come from": the sour…

Platform+

GET /api/v1/wallet/{address}/funding and GET /api/v1/rhc/wallet/{address}/funding now return a direct_funding block answering "where did this wallet's money come from": the source address, the amount, the asset, when it arrived, how many transfers it covers, and, where we hold a label for the sender, who that sender is. Native and token funding are reported separately, because they are often different sources and answer different questions. Solana token funding is reported as not observable rather than as absent, since inbound SPL transfers reference a wallet's associated token account and are not in our collector's subscription at all.

Pro and Ultra now differ. Pro receives the direct facts above, plus the full list of distinct sources observed funding the wallet. Ultra and above additionally receive the relationship counts: how many other tracked wallets share a given funder, and how many of those are token deployers. Those counts are a product of the whole tracked corpus rather than a fact about the wallet you asked for, which is why they sit a tier higher. Business and Enterprise keep the Ultra depth. The base endpoint itself has not moved: it is Pro, as it was.

The source list ships with its own count. Previously a Pro response carried source_count with no way to inspect it. The list of sources is now returned alongside it, so the number refers to something you can actually read.

Honest wording when there is nothing to show. A wallet with no observed funding used to receive a coverage sentence describing funding that was not there. It now says plainly that no funding has been observed since we began tracking that wallet, and that this is not evidence the wallet was never funded. Coverage remains forward looking: we never claim a wallet's first funder unless we resolved its history back to its origin, and while we cannot, the field is named earliest_observed_funding_at rather than first_funded_at, and the origin-claim fields are absent rather than null.

Sep 13Platform

A site-wide stall root-caused and fixed: large `/holders` censuses were blocking the whole API

Every unexplained 502/504 burst on the active slot over the last two days — 13 to 37 seconds where it answered nothing at all, not even a 401 — traced back to the same cause: a …

Platform+

Every unexplained 502/504 burst on the active slot over the last two days — 13 to 37 seconds where it answered nothing at all, not even a 401 — traced back to the same cause: a /tokens/{mint}/holders census on a mint with 200k-500k token accounts. The census used web3.js's getProgramAccounts, which validates and decodes the entire response, builds a PublicKey and buffer per account, and base58-encodes every holder, all synchronously on the Node process's single thread. For a mint with hundreds of thousands of holders that ran long enough to block every other request in flight, including the health checks that would otherwise have caught it sooner.

The census now decodes the raw JSON-RPC response itself: pubkeys stay as the strings the RPC already sent, owners are aggregated by their raw bytes instead of a decoded key, and base58 is computed only for the top 100 holders returned in the response. A 40,000-account mint that used to take a meaningful slice of a second now decodes in about 130ms. Censuses above 100,000 accounts are cached for 30 minutes instead of the usual 60 seconds, since they are also the most expensive to run twice.

What you saw: occasional 502/504 responses from any endpoint, not just /holders, clustered a few seconds after a large-mint holders request, self-resolving within 30-40 seconds.

Sep 13Platform

Robinhood Chain reads fail over to a standby replica when hood is unreachable

RHC market data (/api/v1/rhc/, the robinhood/* pages, the RHC x402 endpoints) is served from a dedicated Postgres on hood, the box also running the chain's ingestion. If hood is…

Platform+

RHC market data (/api/v1/rhc/*, the robinhood/** pages, the RHC x402 endpoints) is served from a dedicated Postgres on hood, the box also running the chain's ingestion. If hood is slow or down, reads now retry against a physical replica on our standby box instead of failing outright: a connection error, an HTTP 502-504, or three timeouts inside 30 seconds sends the next read there, gated on the replica actually being caught up (in recovery, not paused, no more than 5 seconds behind). Writes never fail over. hood remains the only place RHC data is written, and is not itself made more available by this — this only changes what a read does when hood can't answer.

Sep 12Platform

Prices keep moving after graduation on PUMP- and xStock-quoted pools, and router trades land on the right venue

Two more gaps in the same family as the curve fix below, both closed tonight.

Platform+

Two more gaps in the same family as the curve fix below, both closed tonight.

Post-graduation pools with an exotic quote are priced now. A token whose bonding curve is quoted in PUMP, a tokenized stock or another non-SOL token graduates into a pool that keeps that quote (Raydium CPMM in the xStock, PumpSwap in PUMP). Until today the trade parser only paired a pool against SOL, USDC, USDT or USD1, so every swap on such a pool was dropped and the token's price and market cap froze at the graduation value. A pool whose only counter-asset is a single non-SOL token is now paired with that token as its quote, and each swap is priced through the quote token's own tracked price. Roughly one in five forwarded swaps was affected. If the quote token itself cannot be priced, the swap is counted and skipped rather than written as a wrong number.

Multi-hop router trades are attributed per leg. Titan, Flash and Jupiter routes that go SOL to an intermediate token to the target used to look like two pools of the same token in one transaction and were skipped as ambiguous. Pairing is now scoped to the instruction that executed each leg: the venue on a trade is the program that ran that leg, not the first DEX in the transaction; an aggregator-tagged route that hit exactly one real pool is priced instead of dropped (about 25,000 trades an hour); and a transaction that genuinely trades one token in two pools produces one price update per pool, with pool-side amounts on each.

What you see in the API: /token/{mint}, /tokens screener rows, /tokens/{mint}/candles, the token:prices stream and the surge and revival alerts stop lagging their own tape on these tokens. The share of tracked tokens whose stored price disagreed with trades executed on it fell from about 17 % to under 7 % over the evening, the first time it has been under our 8 % alert line since 2026-09-05.

Sep 12Platform

Market caps fixed for pump.fun tokens whose bonding curve is quoted in USDC, PUMP, WXMR, xStocks or DOGE

pump.fun started launching bonding curves that are quoted in a token other than SOL: USDC, PUMP, WXMR, tokenized stocks, DOGE, cbBTC. The curve account stores the quote mint in …

Platform+

pump.fun started launching bonding curves that are quoted in a token other than SOL: USDC, PUMP, WXMR, tokenized stocks, DOGE, cbBTC. The curve account stores the quote mint in a new field and keeps the quote in a vault owned by the curve. Our price engine still read every curve's reserves as lamports, so the price and market cap of such a token were off by a constant factor that depends on the quote token: 188× too high on a WXMR curve, 10× too low on a USDC curve, 28× too high on a PUMP curve. About one in eighteen pump.fun launches over the last two weeks was affected (29,850 curves), and a handful of completed curves produced market caps in the quadrillions.

Fixed today: the curve parser reads the quote mint, the price is computed in the quote token and converted through the quote token's own tracked price, liquidity is the real quote raised (not the account's rent), and a curve whose quote we cannot price now shows no price instead of a wrong one. Every affected token was recomputed from its on-chain curve state; the API, token pages, screener, surge and reversal alerts and the OHLC feed all serve the corrected numbers. Candle history from before the fix still contains the old values for the affected tokens.

Regression guards: a nightly drift check compares stored prices on these curves against executed trades, and the health check reports how many non-SOL curve updates were priced.

Same day, second pass. A separate class of bad numbers surfaced once the curves were right: drained AMM vaults (a pool holding five raw token units against 0.8 SOL) being elected as a token's price source, which produced headline market caps in the billions to quadrillions for a few hundred dead tokens. Every price source now has to pass a sanity test before it can set a headline (an implied FDV above 1 trillion dollars, or above 10,000 times the pool's own liquidity for anything over 10 million, is rejected), and the affected headlines were re-anchored on the executed-trade tape. Candle history for the affected tokens was cleaned the same way: any candle more than 5× away from trades executed in the same hour was removed, so charts no longer show the spike.

Trades paid in another token now reach the trade tape. A direct buy or sell on a WXMR-, PUMP- or tokenized-stock-quoted curve has no SOL leg, so it used to be dropped as dust. The tape parser now recognises the quote leg and converts it to a SOL equivalent through the quote token's own tracked price, the same way USDC-paid trades were already handled.

So this cannot sit unnoticed again, three detectors went live: every program and contract we decode (16 Solana programs, 8 Robinhood Chain contracts) is fingerprinted every five minutes and any upgrade raises an alert within the hour; every instruction name and discriminator seen on the firehose is catalogued and a new one on a known program raises an alert; and a nightly check compares stored prices against executed trades per venue, so a unit error on any single venue shows up the next morning.

Sep 10Platform

Agentic infrastructure audit: a real bug fixed, 22 endpoints closed across MCP/ElizaOS/Solana Agent Kit/x402, `agents.json` added

We audited every agent-facing surface (2 MCP servers, 2 ElizaOS plugins, 2 Solana Agent Kit plugins, 2 x402 SDKs) against the full REST API, endpoint by endpoint, on both chains…

Platform+

We audited every agent-facing surface (2 MCP servers, 2 ElizaOS plugins, 2 Solana Agent Kit plugins, 2 x402 SDKs) against the full REST API, endpoint by endpoint, on both chains — not by reading source, but by calling tools/list and introspecting the built packages at runtime, since a grep-based count turned out to be wrong twice in the course of doing this.

A real bug, not just a gap. solana-agent-kit-plugin-madeonsol's 1.25.0 release registered deployerAsOf/deployerRewards as actions, but never wired the underlying functions into agent.methods or the package's exports — both were silently undefined for any caller using the direct-method surface. The Robinhood Chain sibling package had the identical bug for five different methods (tokenTopTraders, tokenFlow, tokenPeakHistory, tokenRisk, tokenHolders) — present in the package, unreachable through the plugin object. Both fixed; both packages now carry an offline test that would have caught this on day one.

22 endpoints, previously covered on some agent surfaces but not others, added everywhere they were missing: tokenTopTraders (existed on the REST API and x402, missing from every agent tool), the deshred sniper-deploy feed and its watchlist management (sniper_recent, sniper_by_deployer, watchlist list/add/remove — absent from ElizaOS and Solana Agent Kit entirely), two webhook/watchlist update endpoints, and — on Robinhood Chain — tokens/{address}/early-buyers (reachable from zero agent surfaces despite existing on the REST API) plus 10 RHC reads that MCP/ElizaOS/Solana Agent Kit already had but the x402 SDK didn't (KOL coordination, first-touches, six deployer-hunter sub-routes, two batch lookups).

agents.json — a machine-readable manifest of every MCP server, agent-framework plugin, SDK, and x402 payment rail — added alongside the existing llms.txt, matching the discovery-file convention agent builders now expect. The MCP servers & SDKs page is linked from the main nav for the first time and its package/tool counts were corrected (mcp-server-madeonsol now serves 104 tools, verified live via tools/list — an internal doc had been undercounting for a while).

Published: the TypeScript madeonsol 2.27.0 package (released 2026-09-02) already carried every one of these endpoints and was not republished; madeonsol-x402 1.30.0 (npm — the PyPI release of 1.30.0 is still pending; PyPI latest is 1.29.0), mcp-server-madeonsol 1.27.0, @madeonsol/plugin-madeonsol 1.26.0, solana-agent-kit-plugin-madeonsol 1.26.0, robinhood-chain-x402 0.10.0, mcp-server-robinhood-chain 0.9.0, @madeonsol/plugin-robinhood-chain 0.9.0, solana-agent-kit-plugin-robinhood-chain 0.9.0.

Sep 8API

Enterprise tier, and `POST /api/v1/wallet-list/score`: score your own list of wallets on real trading performance

Enterprise is now a real API tier, not only a contact form. It is hand-sold (no checkout; talk to us), starts at a floor of 1,000,000 calls/day and 6,000/min, negotiated per con…

API+

Enterprise is now a real API tier, not only a contact form. It is hand-sold (no checkout; talk to us), starts at a floor of 1,000,000 calls/day and 6,000/min, negotiated per contract, and inherits every Business-gated route. GET /api/v1/me labels the account "Enterprise" and reports the Business per-feature limits as its floor.

POST /api/v1/wallet-list/score (Enterprise only) is the first endpoint built for it. Send up to 200 Solana wallet addresses (a JSON array or a comma-separated string) and get each one scored on its own closed trades, not on whether it happens to be in our KOL or alpha lists:

  • score 0-100: half win rate on closed positions, half profit factor (capped at 5×). null when the wallet has no closed positions, and null is never "scored zero".
  • pnl: realized / unrealized / total SOL, wins and losses, win rate, profit factor, average and median hold, max drawdown, tokens traded, best and worst realized position. Same FIFO cost-basis engine and same cache as GET /wallet/{address}/pnl, so the two can never disagree on a wallet.
  • reputation: is_sniper, is_bundler, is_dumper, is_kol + kol_name, bot_confidence. Cheap indexed lookups, always filled for every wallet in the request.
  • status per wallet: scored, no_trades, or not_computed. PnL is the expensive half, so at most 25 wallets we have never computed before are scored inline per request; already-cached wallets are free and uncapped. A not_computed wallet says so in message: resubmit it, or warm it with /wallet/{address}/pnl.
  • The envelope reports scored, cached, computed_now, no_trades, not_computed, the two caps, and score_methodology in plain words.
Sep 8API

Webhooks: filter on any payload field with `conditions`, plus two Robinhood Chain firehose channels

Custom webhook conditions (Ultra and Business). Every webhook filter so far was a named field we had to add by hand (min_sol, kol_name, deployer_tier, ...). filters.conditions i…

API+

Custom webhook conditions (Ultra and Business). Every webhook filter so far was a named field we had to add by hand (min_sol, kol_name, deployer_tier, ...). filters.conditions is the general version: up to 10 { field, op, value } triples, ANDed together and evaluated against the event payload on top of the named filters. Operators are eq, neq, gt, gte, lt, lte, in and contains, matched to the field's type (numbers take the comparisons, strings take in / contains, booleans take eq / neq). field must be a documented payload field of one of the webhook's subscribed event types, with one level of nesting allowed (triggering_trade.sol_amount on kol:coordination); an unknown field or a mismatched operator is a 400 that names the problem, so a filter can never silently match nothing. Setting conditions on a Pro webhook is a 403 tier_required; the named filters stay available on Pro. The full list of filterable fields per event is in the webhooks section of the API docs.

rhc:dex_trades_unattributed (Ultra+) is the complement to rhc:dex_trades. The firehose only broadcasts swaps where one side of the pool can be called "the token"; swaps on pools where neither side is (a WETH/USDG pair, a pure quote-to-quote arb) were fully recorded in the REST tape but never streamed. They now flow on this channel as raw legs: token_in, token_out, amount_in, amount_out, no symbol or decimals enrichment and no buy/sell verdict. Subscribe to both channels for every swap on the chain.

rhc:new_tokens (Ultra+) fires once per token, the moment its symbol, name and decimals first resolve on-chain, before its first trade reaches rhc:dex_trades. A firehose consumer can now learn a token's decimals before it has to parse an amount for it.

Both rhc:dex_trades and rhc:dex_trades_unattributed frames also carry liquidity_usd, the pool's TVL at broadcast time (null for a pool we have not verified yet).

Sep 7Platform

LaunchLab tokens whose curve is quoted in a tokenized stock, ZEC, DOGE or another non-SOL token are priced from the curve itself

A new LaunchLab-based launchpad live since 2026-09-05 mints 3,000 to 5,000 tokens a day whose bonding curves are quoted in something other than SOL: tokenized stocks (SPYx, NVDA…

Platform+

A new LaunchLab-based launchpad live since 2026-09-05 mints 3,000 to 5,000 tokens a day whose bonding curves are quoted in something other than SOL: tokenized stocks (SPYx, NVDAx), ZEC, DOGE, xBTC, xSOL and others. Our trade parser skipped every swap whose quote was not in its SOL/stablecoin list, so the only price such a token ever had was the deployer's own buy in the create transaction, which on an exotic-quote curve is about 100× too low, and it never moved. Two days in, a quarter of the tokens with recent trades had a stored price that disagreed with those trades.

Now the price comes from the curve account itself: every time the pool's reserves change we read the virtual reserves and decimals from the account, compute the price in the quote token, and convert through that token's own tracked price (fresh within 5 minutes, from a liquid canonical pool). last_trade_time is stamped on every reserve move, so these tokens no longer look dormant. A curve whose quote we cannot price honestly shows no price rather than the wrong one. On the deployer side, a LaunchLab create quoted in a ...pump-suffixed token is no longer mistaken for a pump.fun launch, which had been producing phantom bonding-curve pools.

Rolled out in shadow mode first (compute and count, write nothing), verified against the tape, and switched on the same evening. A nightly check now compares the stored price of on-curve LaunchLab tokens against executed trades so a regression here shows up the next morning.

Sep 7Platform

`/wallet/{address}/trades` serves history from the archive, so an old `since` no longer returns an empty page

Closed months older than the newest three move from Postgres to a Parquet archive, and /tokens/{mint}/trades and the three Robinhood Chain tape routes already read across that b…

Platform+

Closed months older than the newest three move from Postgres to a Parquet archive, and /tokens/{mint}/trades and the three Robinhood Chain tape routes already read across that boundary. The wallet tape did not: an explicit since below the Postgres floor returned trades: [] with has_more: false, indistinguishable from a wallet that never traded. Found by a storage check that read a wallet with 9,690 archived trades as empty.

The wallet route now does the same split as the mint route: rows at or after history.postgres_from (Unix seconds) come from Postgres, older rows from the archive, in one order behind one cursor. The response carries the same history block (postgres_from, archive_used, archive_months, archive_available, truncated, note) and the same X-Read-Source header (core, core+archive or archive). If the archive did not answer, history.truncated is true and the coverage block says the probe was inconclusive, so an empty page is never mistaken for the end of the tape. The default 90-day window sits above the floor, so a call without since is unchanged and costs no archive round trip. An archive page over a whole month costs about 50 ms.

Sep 5Platform

Fixes from reading what paying customers actually send: a KOL roster, wrong-chain and wrong-kind addresses diagnosed, cursors that survive a raw `+`, and two silent data gaps closed

We read 30 days of paid-tier request logs — every 400 and 404 — and fixed what they showed instead of what we assumed.

Platform+

We read 30 days of paid-tier request logs — every 400 and 404 — and fixed what they showed instead of what we assumed.

GET /api/v1/kol/wallets (all tiers) — the tracked KOL roster: wallet, name, X handle, strategy tag, follower counts, tracked-since, with active=, q= and strategy= filters. Every /kol/* route is keyed on a wallet address and until today there was no way to list the set; customers guessed /kol/wallets, /kol/list, /kol/roster and /kol/search, all 404, or scraped addresses out of the feed. Roster only — performance stays in /kol/leaderboard and /kol/{wallet}.

Aliases for the URLs people guess: /token/trending and /token/hot (→ /kol/tokens/trending|hot), /rhc/tokens/hot and /rhc/tokens/trending (→ /rhc/kol/hot-tokens). Same handlers, every parameter passes through.

Wrong chain, said plainly. Multi-chain clients point one code path at both chains, so 0x… addresses landed on Solana routes 27,000+ times from two customers alone. Those now return 400 evm_address_on_solana_route with rhc_endpoint — the exact /api/v1/rhc/… twin to call instead — on the token, risk, deployer-hunter, wallet and KOL routes.

Wrong kind of address, resolved instead of refused. Of the ~3,000 distinct addresses customers sent to /tokens/{mint}/risk that we answered "not tracked", 1,096 were PumpSwap pool accounts and 688 were wallets; only about one in seven was a token mint we had genuinely never seen. The risk route now recognises what it was given: a PumpSwap pool is decoded on-chain to its mint and answered for the mint with resolved_from set; a wallet gets 400 wallet_not_mint pointing at /wallet/{address}; a token account names its mint; an address that does not exist on mainnet says so (404 not_on_chain, checked live) instead of implying a coverage gap on our side; Raydium, Meteora and Orca pool accounts are named by DEX. A real untracked mint still gets not_tracked.

Cursors pasted with a raw +. Our feeds hand back next_since like 2026-09-05T16:53:30+00:00. Pasted into a URL without encoding, the + arrives as a space and every date parser rejected it — one poller sat on the same cursor for 245 consecutive 400s because its cursor could never advance. since, before, until, from, to and after on every /api/v1 GET now answer that exact shape with a 308 to the correctly-encoded URL, which every HTTP client follows.

Robinhood Chain holder pages beyond 10,000. GET /rhc/tokens/{address}/holders gains next_after / ?after= keyset paging — walk the entire holder set of any token in O(page) per request; the offset cap stays. Proven identical to offset paging on the 1.6M-holder token, including tie order.

Two silent data gaps, closed. /kol/coordination (Solana) returned first_buy_at, last_buy_at and market_cap_usd_at_first_buy as null on 60 % of tokens: the route pulled every trade row through a layer that clamps at 1,000 rows, so tokens past the clamp lost their timing. It is aggregated in the database now and a monitor case fails the moment a returned token has null timing. Its Robinhood Chain sibling /rhc/kol/coordination had the mirror-image bug — paging capped at 12,000 buys while the 24h window held 50,000, so 24h/7d answers quietly covered only the newest ~6 hours; one SQL statement now covers the full window in ~0.4 s, guarded by a case asserting a wider window never reports fewer KOLs than a narrower one. Also: /rhc/tokens?sort=newest&since= was strict on a block-second timestamp and dropped sibling launches sharing that second when you fed next_since back; it is inclusive now. And /tokens/unlocks went from ~535 ms to ~60–150 ms via a precomputed next-unlock column.

Sep 2Platform

OpenAPI response schemas for every operation, plus site-wide SEO/AI-citation cleanup

Every operation in the OpenAPI spec now carries a real JSON response schema — the 57% that previously answered with a bare "OK" (including the two flagship endpoints, /tokens/{m…

Platform+

Every operation in the OpenAPI spec now carries a real JSON response schema — the 57% that previously answered with a bare "OK" (including the two flagship endpoints, /tokens/{mint}/risk and /deployer-hunter/alerts) are backfilled from the actual route handler code, not guessed. /manifests got its own Meta tag; /status is explicitly marked no-auth (security: []) in the spec, matching reality.

Alongside that: canonical tags and live Dataset structured data on /benchmarks and /data-integrity, a corrected site-wide Organization schema description, llms.txt/llms-full.txt brought current (endpoint list, webhook event count, SDK versions), the MCP server's glama.json tool catalog synced from 58 to the full 98 live tools, priorityCount on the tools/categories directory grids for LCP, and meta descriptions trimmed to the ~160-char budget site-wide (homepage, pricing, api-docs, the alternatives-page template — which also picked up a correct "a"/"an" instead of always "a" — and the blog excerpt builder, now cutting at a word boundary instead of mid-word).

Sep 2Platform

Deployer reputation as-of a date, and creator-fee rewards per deployer

Two Deployer Hunter endpoints, both PRO+, both built on data we were already collecting.

Platform+

Two Deployer Hunter endpoints, both PRO+, both built on data we were already collecting.

GET /api/v1/deployer-hunter/{wallet}/as-of?date=YYYY-MM-DD — the deployer's reputation exactly as it stood on that date: tier, tracked flag, deploy and bond counts, bonding rates, peak-MC stats. It returns the latest snapshot at or before date, never anything later, so a backtest sees only what was knowable then. Snapshots are written on change, so snapshot_date can be earlier than the date you asked for — both are in the response and carried: true says so. If we had no snapshot yet, you get as_of: false and snapshot: null; we do not fabricate a zero row. Snapshots run from 2026-04-07. /history is still the whole series; /wallet/{address}/flags?as_of= covers every flag source since 2026-08-28.

GET /api/v1/deployer-hunter/{wallet}/rewards — pump.fun creator fees for a wallet, answered two ways that are deliberately kept apart. Collected is what actually reached the wallet: direct vault claims, social-handle claims, and shareholder payouts on any token. Attributed is every fee distribution on the tokens the wallet deployed, whoever received it, split into to_self and to_others with a redirected_pct. When attributed dwarfs collected, the deployer is routing its fees somewhere else — a launch tool, a KOL, a social handle — and that gap is the point. Amounts are summed per quote (SOL and USDC separately) and combined only in USD; top_tokens and top_recipients show where the money went, with social-handle PDAs labelled.

The honest edges: direct vault claims carry no mint and are kept 90 days, so that rail is a rolling window; shareholder payouts and social claims exist since 2026-08-17; a token on the default config (100% to the creator) pays through direct claims, so attributed only covers tokens whose fees were ever split. All of it is in the response's coverage block.

August 2026

15 ships
Aug 31Platform

API free tier: live feeds now delayed 5 minutes

The free tier now serves the live-feed endpoints on a 5-minute delay: the KOL feeds (Solana + Robinhood Chain), deployer alerts and recent bonds/graduations, first-touches, RHC …

Platform+

The free tier now serves the live-feed endpoints on a 5-minute delay: the KOL feeds (Solana + Robinhood Chain), deployer alerts and recent bonds/graduations, first-touches, RHC coordination, per-token KOL flow and entry order, and the embedded KOL tape on /rhc/tokens/{address}. Everything else on Free is unchanged and stays real-time — full response shape, real wallets, full tx signatures, 200 calls/day, no card: scores, leaderboards, wallet PnL, buyer quality, holder data, and search.

Delayed responses say so in-band — top-level delay: "5m", as_of (the cutoff timestamp), delay_note, an upgrade link, and an X-Data-Delay: 300 header — so nothing is silently stale. The public demo key behaves like the free tier. PRO and up are real-time on everything, and so is x402 pay-per-call — an agent paying per request never sees the delay.

Why, honestly: the free tier was serving the exact real-time tape the paid tiers sell, and a handful of accounts polled it around the clock as a production feed. Five minutes changes nothing for evaluating the data or building an integration — and everything for freeloading a trading signal. If you're building live, Pro is €43/mo or pay per call with x402.

GET /api/v1/tokens/surges and the token:surges WebSocket channel (webhook events token:surge / token:revival) — PRO+.

Surge. A token under 30 minutes old whose market cap is running against its launch market cap. Three tiers, each fires once per mint and independently: early (≤10 min, ≥$12k, ≥3× launch MC), strong (≤30 min, ≥$30k, ≥6× launch and ≥2× the lowest sample of the last three minutes — it is climbing now, not merely high), breakout (≤2 min, ≥$45k, ≥8× launch). The launch multiple is the half that does not move with the SOL price; the dollar floor keeps micro-launches out. A tier only fires when the level has held — on the current tick and on a sample at least ten seconds older, and never before the token is twenty seconds old — because a same-slot bundle can mark a fresh token to $475k in one tick with no buys behind it, and that is a spike, not a surge.

Revival. A token with no trade candle for 24 hours or more that starts trading again — confirmed by the tape (≥5 buys, ≥$500 of buy volume, market cap ≥1.5× where it went quiet; or ≥20 buys / ≥$5k regardless), never by the price move alone. One dust buy into an empty pool marks a market cap up 300%; that is not a revival and it will not fire. Dormancy is measured on 1-minute candles across every DEX we price, so a graduated Raydium or Meteora token counts, not only pump.fun curves.

The honest half. On pump.fun, "reached $50k in two minutes" is very often a bundled launch, and a feed that only says pumped turns its readers into the exit liquidity. So every fire carries what we could measure in the same instant: the burst tape (buys, sells, volume; unique buyers where our wallet-level coverage exists — null where it does not, never an inferred zero), tracked-KOL involvement, the first-20 early-buyer cohort (how many bought in the same block, how many have already sold, how many are known sniper wallets), the deployer's reputation, and a risk_flags[] array with documented thresholds — bundled_launch, few_buyers, wash_pattern, thin_liquidity, cold_deployer, sniper_heavy, early_buyers_exiting, sell_pressure, no_prior_price, mint_authority_active, transfer_fee. Filter them out server-side with ?exclude_flags= or ?only_clean=1; the same filters work on the WebSocket subscribe and on webhooks.

Does it work? Every fire older than an hour carries its outcome (market cap, peak and low one hour after), and ?stats=1 prints the hit-rate per tier — out-of-sample by construction, because the fire is written down before the outcome exists. Judge the tiers on that, not on the names.

Thresholds are echoed in the response's definitions block straight from the engine, so the docs cannot drift from what fires. SDKs (same day): bare madeonsol 2.26.0 · Rust madeonsol 0.27.0 · madeonsol-x402 1.28.0 (npm + PyPI) · mcp-server-madeonsol 1.25.0 · @madeonsol/plugin-madeonsol 1.24.0 · solana-agent-kit-plugin-madeonsol 1.24.0 — tokensSurges() / tokens_surges(), a typed TokenSurgeEvent, and token:surges in the channel unions. Additive only.

Aug 27Platform

WebSocket stream tokens no longer expire

Your stream token from POST /api/v1/stream/token is now permanent: the same value on every call, no 24-hour lifetime, no in-band rotation, nothing to refresh. It stops working i…

Platform+

Your stream token from POST /api/v1/stream/token is now permanent: the same value on every call, no 24-hour lifetime, no in-band rotation, nothing to refresh. It stops working in exactly two cases — your subscription lapses, or you ask for a new one with {"rotate": true} (the old value then keeps working for 60 s so sibling processes and in-flight reconnects survive). expires_at and next_refresh_at are still in the response for compatibility and are always null.

Why: the 24 h lifetime had been there since the first stream service in April with no recorded reason, and every WebSocket incident since was scaffolding around it — the reconnect storm in May, the 60 s grace, the "sticky while >6 h" rule, the server-side rotation and token_refresh frame in June, and this week a customer whose bot kept its boot-time token, was rotated out from under it, and reconnected into 4001 for hours. None of our own SDKs handled the refresh frame either. The token only unlocks feeds your permanent API key already unlocks, so a daily rotation protected nothing worth that failure mode.

What to do: nothing, unless you had code that waited for token_refresh or scheduled a re-mint before expires_at — you can delete it. Reconnect with the token you have; treat a 4001 as a real "mint again" signal, not a timer. Prefer Authorization: Bearer <token> on the handshake; ?token= still works and is now masked in our access logs.

Aug 20Platform

Robinhood Chain: who bought first, and whether they stayed

GET /api/v1/rhc/tokens/{address}/early-buyers — the first 20 buyers of a token, in order, joined to what happened next: realized ETH, trade count, average entry market cap, and …

Platform+

GET /api/v1/rhc/tokens/{address}/early-buyers — the first 20 buyers of a token, in order, joined to what happened next: realized ETH, trade count, average entry market cap, and whether they still hold any.

The ranking itself is not new — rhc_early_buyers has covered 437,226 tokens for months and is recomputed daily. It was only ever read as a per-wallet count inside the wallet profile ("early buyer of N tokens"). The per-token list, which is the thing anyone actually asks for, was never exposed. Solana has had /kol/tokens/{mint}/entry-order; Robinhood Chain had nothing.

Three things are stated in the response rather than left for you to discover:

  • realized_eth is a profit only when position is closed. It is sold_eth - bought_eth, so an early buyer who is still holding shows a negative number — they have spent and not yet sold. Every row carries position (closed / open / unknown), because publishing the figure alone would systematically mislabel the winners as losers.
  • still_holding is only as exact as the fold behind it. It comes from the same ERC-20 Transfer replay as /holders, so the response carries holdings_verified — true only when that token reconciles against on-chain totalSupply().
  • Ranks are as of computed_at, not live. A token that began trading since the last sweep returns an empty list with a stated reason, never as an assertion that it had no early buyers.

Enrichment is additive: if the PnL or holdings join fails, those fields go null rather than taking down the ranking, which always exists. PRO+.

  • Also today, quietly faster: /tokens/search no longer computes match tiers whose rows cannot be returned (?q=pump 1,568 ms → 92 ms, ?q=bonk 507 ms → 17 ms) and now has a deterministic tie-break, so repeated searches return the same order. /rhc/tokens/{address}/risk dropped from a 504 ms median to 91 ms — and now finds a liquidity pool for ~49% more tokens, because it was matching only one side of the pair. RHC holder concentration and growth are single-pass (~3.8× and ~1.9× on the largest tokens). A full sweep of 117 route + filter combinations puts the API at an 18 ms median, 78 ms p90.
Aug 17Platform

SDKs: token locks, unlock calendar and pump.fun fee sharing in all 7 Solana packages; equities + liquidity removals in all 7 Robinhood Chain packages

The locks, unlock-calendar, fee-sharing and fee-claims endpoints — plus the two Robinhood Chain surfaces from the day before — now have typed bindings. Fourteen packages publish…

Platform+

The locks, unlock-calendar, fee-sharing and fee-claims endpoints — plus the two Robinhood Chain surfaces from the day before — now have typed bindings. Fourteen packages published today. (Still keyed-only, no SDK method yet: /tokens/search, POST /wallet/batch/trades, the token:prices channel and WS seq/replay — next SDK release.)

Solana — five methods + two stream channels. madeonsol 2.25.0 (npm — client.token.locks(mint), locksFeed(), unlocks(), feeShares(mint), feeClaims(), typed TokenLocksResponse / TokenUnlocksResponse / TokenFeeSharesResponse / TokenFeeClaimsResponse), madeonsol 0.26.0 (crates.io — client.token().locks(mint, &params), locks_feed, unlocks, fee_shares, fee_claims, ~30 new serde types), madeonsol-x402 1.27.0 (npm — keyed rest.tokenLocks(mint), tokenLocksFeed(), tokenUnlocks(), tokenFeeShares(mint), tokenFeeClaims()), madeonsol-x402 1.27.0 (PyPI — rest.token_locks(mint), token_locks_feed(), token_unlocks(), token_fee_shares(mint), token_fee_claims() + LangChain/CrewAI tools), mcp-server-madeonsol 1.24.0 (madeonsol_token_locks, madeonsol_token_locks_feed, madeonsol_token_unlocks, madeonsol_token_fee_shares, madeonsol_token_fee_claims), @madeonsol/plugin-madeonsol 1.23.0 and solana-agent-kit-plugin-madeonsol 1.23.0 (matching actions + tools). The token:locks and token:fee_claims WebSocket channels are in every stream client's channel union, and — one thing worth knowing — the frames on those channels are the compact writer rows the trackers emit (token:lock: lock account, program, mint, kind, sender, recipient, amount_raw, decimals, schedule; token:fee_claim: event type, mint, actor, recipient, amount_raw, social platform / user id, shareholders), not the enriched REST rows. The TypeScript and Rust SDKs type the frames as what is actually sent, so a client does not have to discover the difference in production. All five endpoints are PRO+ and keyed only (no x402 route); LP locks are not part of locks; fee-claim history starts today.

Robinhood Chain — two endpoints that shipped on 2026-08-16 without a binding. GET /rhc/equities (the beacon-verified tokenized stocks & ETFs — identity is the issuer beacon, never the name) and GET /rhc/lp-events (liquidity removals from our own node — the rug signal; adds are not persisted, and the response says so) are now in robinhood-chain-sdk 0.8.0 (equities(), lpEvents()), robinhood-chain 0.8.0 (crates.io, equities, lp_events), robinhood-chain 0.9.0 (PyPI, equities(), lp_events()), robinhood-chain-x402 0.9.0 (keyed client — neither endpoint is on the USDG rail), mcp-server-robinhood-chain 0.8.0 (rhc_equities, rhc_lp_events), @madeonsol/plugin-robinhood-chain 0.8.0 and solana-agent-kit-plugin-robinhood-chain 0.8.0.

  • Also today: GET /rhc/deployer-hunter/best-tokens had been answering 500 since 2026-08-14 — the elite+good deployer cohort grew to 178 addresses, the query rendered ~7.6 KB into the URL and the proxy answered 414. Chunked; the same ceiling is now respected on /rhc/deployer-hunter/alerts?tier=. Additive SDK release otherwise; nothing breaks if you do not upgrade.
Aug 17Platform

pump.fun fee sharing & claims: who the creator fees are redirected to, and every claim

pump.fun lets a coin's creator fees be split to other wallets (a SharingConfig of shareholders) and earmarked for social identities — an X account whose owner later claims. Two …

Platform+

pump.fun lets a coin's creator fees be split to other wallets (a SharingConfig of shareholders) and earmarked for social identities — an X account whose owner later claims. Two endpoints now read that straight from the programs' own events and account state.

GET /api/v1/tokens/{mint}/fee-shares — the split on a coin right now (each shareholder's share, whether it is the creator, whether it is a social-handle PDA), how much has actually been distributed to each of them, who used to be in the split, and every config change. A coin that never redirected returns is_default: true — a real answer, read live from chain.

GET /api/v1/tokens/fee-claims — the feed: distributions to shareholders (pro-rata per address), social-handle claims (platform + numeric user id, recipient wallet, amount), config changes and creator transfers, newest first with since= cursors — and pushed on the new token:fee_claims WebSocket channel.

  • Decoded from the on-chain Anchor events (DistributeCreatorFeesEvent, SocialFeePdaClaimed, CreateFeeSharingConfigEvent, …) of the pump and pump_fees programs; social-handle PDAs backfilled (10.9k identities, 53k SOL claimed lifetime on day one). Event history starts today.
  • Not stored on purpose: the default 100%-to-creator config pump creates for every coin, and the zero-amount distribution that comes with it — the feed is redirects and real claims only.
Aug 17Platform

Token locks & vesting: who locked, how much, until when — and what unlocks next

Three Solana endpoints that read the locker programs themselves instead of guessing from transfers.

Platform+

Three Solana endpoints that read the locker programs themselves instead of guessing from transfers.

GET /api/v1/tokens/{mint}/locks — every Streamflow stream, Jupiter Lock vesting escrow and Bonfida token-vesting contract on a mint, decoded from the programs' on-chain account state and derived live at request time: how much is still locked right now, what has unlocked, what is claimable, the next unlock event, and a 7d/30d forward schedule. The summary answers the questions that matter before you buy a "team-locked" token: how much of supply is actually locked, until when, by how many wallets — and how many of those locks the locker can still cancel (a cancelable lock is a promise to the recipient, not to you).

GET /api/v1/tokens/locks — the cross-token feed of new locks, newest first, with since= cursors — and pushed live on the new token:locks WebSocket channel the moment the contract lands.

GET /api/v1/tokens/unlocks — an unlock calendar: every active contract's next cliff / periodic / final unlock inside 1h–90d, with the amount, its % of supply and USD value, sortable by soonest or largest. "Which tokens have locked supply hitting the market this week."

  • Coverage today: Streamflow (66k contracts), Jupiter Lock (416k — mostly per-recipient airdrop vestings), Bonfida token-vesting. Adding a locker is a decoder + a program ID. LP locks (Raydium Burn & Earn, Meteora position locks) are a separate, not-yet-built feature — this is token/vesting locks.
  • Amounts are base-unit strings with ui / usd / % of supply alongside; decimals and supply are read off the SPL Mint account for every mint we see (most locked tokens are not memecoins in our trade universe), so the numbers do not depend on the token being "tracked".
  • Also today: the gRPC reconnect path in kol-tracker / dex-stream / deployer-listener could hang forever on a dead channel (a 6-hour single-region blind spot on 2026-08-17 that turned into 36 min of no feed when the other region failed). Connect/subscribe now time out, an orphaned region self-heals, and health monitoring reads region liveness directly.
Aug 17Platform

Who holds a token, exactly — on both chains — and, on Robinhood Chain, who arrived and who left

Two holder endpoints, one on each chain, that answer the question every other data API estimates.

Platform+

Two holder endpoints, one on each chain, that answer the question every other data API estimates.

Solana: GET /api/v1/tokens/{mint}/holders (shipped 2026-08-16, extended today). Not a top-20 list and not a trade-derived guess: a live census of every token account of the mint (mint-scoped getProgramAccounts at confirmed, Token-2022 aware — every pump.fun mint is), merged per owner. So holder_count is exact — distinct non-zero owners minus pools, bonding curves and burns — and top1/10/20/50/100_share are over a circulating denominator that excludes them. Each disclosed owner is labelled from our wallet intelligence (deployer / kol / early_buyer / bundle / bot / dump_cluster). Fresh memecoins scan in well under a second; a 500k-account token takes ~10 s upstream, so you get 503 holder_scan_in_progress with Retry-After 20 while the scan finishes into the cache. Mega-caps the provider refuses fall back to a top-20 view with holder_count: null and the reason stated — never estimated. Amounts are raw u64 strings.

  • Today: excluded owners are named. The #1 raw account of a fresh memecoin is its own pool. Before, everything off-curve was a generic program_account; now excluded[].reason is pool (with dex and pool_address — matched against 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 only when we genuinely cannot attribute the PDA. concentration gains pool_pct / burned_pct / program_pct. Zero extra RPC.
  • PRO discloses ranks 1–10, ULTRA 1–50, BUSINESS 1–100; the maths is the same on every tier.

Robinhood Chain: GET /api/v1/rhc/tokens/{address}/holders now carries holder_growth. RHC holders were already exact — balances folded from ERC-20 Transfer logs on our own node and reconciled against totalSupply() to the wei — and that history is what makes today's field possible: {1h, 24h, 7d} × {entered, entered_still_holding, exited, net}. entered = addresses whose first Transfer of the token landed inside the window; exited = pre-existing holders whose last movement in the window left them at zero; net ≈ the change in holder_count. Pools and burns excluded. Sanity check from ship day: a token launched that morning showed 593 entered / 560 still holding over 24h — and holder_count was exactly 560. The Solana census is a point-in-time ledger read with no history, so this is an RHC-only capability by nature, and we say so rather than approximate it from trades.

  • Also fixed today: the RHC holder reads looked pools up with a lower() on an indexed column and were running a 988k-row parallel seq scan twice per request. Same numbers, ~2.4× less database time.
  • SDKs — published today, all 14 packages. Solana: the holders census had no SDK binding at all until now. madeonsol 2.24.0 (npm, client.alpha.holders(mint), typed TokenHoldersResponse), madeonsol 0.25.0 (crates.io, client.token().holders(mint)), madeonsol-x402 1.26.0 (npm, keyed rest.tokenHolders(mint)), madeonsol-x402 1.26.0 (PyPI, rest.token_holders(mint) + LangChain/CrewAI tools), mcp-server-madeonsol 1.23.0 (madeonsol_token_holders), @madeonsol/plugin-madeonsol 1.22.0 (GET_TOKEN_HOLDERS), solana-agent-kit-plugin-madeonsol 1.22.0 (tokenHolders). Robinhood Chain: holder_growth typed or documented in robinhood-chain-sdk 0.7.0, robinhood-chain 0.7.0 (crates.io), robinhood-chain 0.8.0 (PyPI), robinhood-chain-x402 0.8.0, mcp-server-robinhood-chain 0.7.0, @madeonsol/plugin-robinhood-chain 0.7.0, solana-agent-kit-plugin-robinhood-chain 0.7.0. The census is keyed-only (not on the x402 rail); RHC holder_growth rides the existing /rhc/tokens/{address}/holders route, so it is on the USDG keyless rail too.
  • One honest boundary: the Solana census is a point-in-time ledger read, so there is no holder_growth on Solana — we would rather leave the field absent than infer it from trades.
Aug 16Platform

The Robinhood Chain SDKs can now pay for themselves: keyless x402 in TypeScript and Python

The Robinhood Chain x402 rail has been live since July, but both SDKs were key-mode only — an agent that wanted to pay per call had to hand-roll the EIP-3009 signing from the 40…

Platform+

The Robinhood Chain x402 rail has been live since July, but both SDKs were key-mode only — an agent that wanted to pay per call had to hand-roll the EIP-3009 signing from the 402 challenge. robinhood-chain-x402 0.7.0 (npm) and robinhood-chain 0.7.0 (PyPI) close that: pass a privateKey / private_key of an EVM wallet holding USDG on Robinhood Chain instead of an API key, and the client does the 402 → sign transferWithAuthorization (EIP-712 domain {Global Dollar, 1, 4663}) → retry flow itself, one payment per call, from $0.04. The wallet needs USDG but no ETH — our facilitator relays gas. lastPayment / last_payment carries the on-chain settlement. Both were verified with real USDG settlements before publish.

  • Keyless rail is now 10 endpoints, not 6 — token risk (with live sell simulation), holder census, wallet PnL and tracked-deployer alerts joined the KOL feed / hot tokens / leaderboard / token snapshot / buyer quality / KOL consensus. The new four delegate to the keyed v1 handlers in-process, so the keyless bodies cannot drift from the keyed ones.
  • Honest boundary: any method that is not on the rail throws KeylessNotAvailableError on a keyless client and names the ten that are. Nothing silently downgrades.
  • TypeScript: createKeylessClient(process.env.RHC_PAYER_KEY), optional peer dependency viem; key mode still has zero runtime dependencies. New deployerAlerts() binding (52 methods).
  • Python: RobinhoodClient(private_key=…), extra pip install "robinhood-chain[x402]" (eth-account); sync and async.
  • Also on the API today: GET /rhc/equities (beacon-verified tokenized stocks/ETFs — 20 fake "GameStop • Robinhood Token" contracts existed on ship day and none are listed), /rhc/tokens?sort=newest&since= (+ /rhc/tokens/new), /rhc/lp-events, ?include= on the always-paired Solana calls, since= + stream pointers on the polled KOL feeds, sequence numbers + client-side replay on the WebSocket stream, and price/pool/reserve enrichment on the dex:trades firehose.
Aug 16Platform

A trade row said it moved N tokens for M SOL, then quoted a price that was not M divided by N

An alert fired claiming our per-trade price was 71% wrong. It was not 71% wrong — that number came from a sampling flaw in our own monitor. But chasing it down surfaced somethin…

Platform+

An alert fired claiming our per-trade price was 71% wrong. It was not 71% wrong — that number came from a sampling flaw in our own monitor. But chasing it down surfaced something worse than the alert: for months, price_sol on a trade row was not the price of that trade.

What it actually was. Our market-cap tracker samples a canonical pool price per token, once per pool update. The ingest path stamped that value onto whatever trades landed near it. So a trade row told you it moved N tokens for M SOL, and then reported a price that was not M ÷ N. The gap ran to a 7.9% median and roughly 74% at the 90th percentile.

The mechanism is granularity, not a bug in the tracker. Every trade in the same slot gets one canonical price. On 2026-08-16, slot 439589939 held a dump: seven trades executing from 9.80e-6 down to 6.12e-6, all seven stamped 6.071174e-6. Their individual errors ran from −38% to −0.9%. On top of that sits a lag with a direction: a stale market price is low during a pump and high during a dump, so the error does not cancel when you average it — candles and VWAP built from that tape inherit the bias. Nothing regressed to cause this. The tape simply got faster, and a price sampled per-token stopped being a reasonable stand-in for a price paid per-trade.

What changed. On /tokens/{mint}/trades and /wallet/{address}/trades, price_sol and price_usd are now this trade's executed price, derived from the row's own amounts. They reconcile exactly with sol_amount / token_amount and with what the PnL endpoints sum. Because sol_amount is the wallet's net SOL movement, that price is the trader's all-in effective rate — it includes the swap fee and any account rent paid in the same transaction, and it is not the pool mid. We would rather tell you that plainly than quietly hand you a number you cannot reproduce from the chain.

The old number did not disappear. It moved to market_price_sol and market_price_usd on the same rows. A single per-token price series is genuinely useful, because executed prices bounce around with trade size and direction — it just should not have been wearing the label "the price of this trade". Use price_sol for cost basis, fills and PnL; use market_price_sol when you want a series independent of who traded and how much.

This is computed when you read, not when we write, so it is correct for every row we have ever captured — no backfill, no gap between old and new history. /wallet/{address}/trades gained all four fields; it previously returned amounts and no price at all, leaving every caller to divide by hand.

And we fixed the monitor that cried 71%. The check sampled the newest 1,000 trade rows, which at today's throughput is about twelve seconds of tape — usually one hot token. The mint that produced the 71% reading had 1,574 trades in three minutes and a 71% median all by itself, while the median across all mints in the same window was 12.4%. It now samples six slices across three hours and takes the median of per-mint medians, so no single token can page us. Two neighbouring monitor bugs went with it: a check that read "our node is one block ahead of the reference" as "DNS is dead on that box" (21 false alarms a day and climbing), and a self-healer that restarted services which were merely mid-restart.

Every SDK ships both prices. madeonsol 2.23.0 (TypeScript), madeonsol-x402 1.25.0 (npm and PyPI), mcp-server-madeonsol 1.22.0, @madeonsol/plugin-madeonsol 1.21.0, solana-agent-kit-plugin-madeonsol 1.21.0, and madeonsol 0.24.0 on crates.io. TokenTrade and WalletTrade carry all four fields, and the MCP tool descriptions spell out which price to use — an agent reading the schema should not have to guess which one belongs in a PnL calculation. The Rust fields are Option<f64>, so a client pinned to an older server still deserializes. Nothing breaks if you don't upgrade: price_sol still exists with the same type, it just finally means what its name says. The Robinhood Chain packages are untouched at 0.6.0 — that chain's trades have their own price columns.

Unrelated, but shipping the same day: the crypto checkout asks a harder question. A card payment comes with a counterparty — the issuer checks the billing address. A crypto payment has none, so an address is whatever someone types. One order arrived with a street, a city and a country belonging to three different jurisdictions, and it passed validation because the country it named has no postal codes, which waived the only checkable field. Now countries without a postal system must give a state or region instead, postal codes are checked against their country's format, and when the country you select disagrees with where you're connecting from, the checkout shows you the mismatch and asks you to confirm your country of residence. It isn't a block — VPNs are normal, and we'd rather ask than guess.

Aug 15SDK

We audited our own SDKs and found fifteen endpoints you were paying for but could not call

This week's audit turned on our own packages rather than the API. Fourteen of them across npm, PyPI and crates.io. Registry hygiene was clean — every published version matched i…

SDK+

This week's audit turned on our own packages rather than the API. Fourteen of them across npm, PyPI and crates.io. Registry hygiene was clean — every published version matched its manifest, the OpenAPI spec covers 134 of 135 routes, and every built package emits correct ESM. The problem was the gap between what the API sells and what the SDKs expose, plus a set of dependency ranges that described a version of the x402 ecosystem that stopped existing twenty majors ago.

The entire Robinhood Chain wallet surface had no SDK binding. Eight routes — the 90-day wallet profile, FIFO cost-basis PnL, open positions marked to market, the per-wallet trade tape, and all four watchlist routes — were live, documented in the spec, and reachable by curl, but a grep across all seven RHC packages returned nothing. If you wanted a wallet's PnL on Robinhood Chain you had to hand-roll the HTTP call while holding an SDK that covered forty other endpoints. All eight are now bound in every RHC package: the TypeScript, Python and Rust SDKs, the x402 client, the MCP server, and both agent plugins. The profile, PnL and positions calls share one 90-day snapshot cache server-side, so asking for all three on an address costs roughly one computation rather than three — cache_hit tells you which call paid for it.

Deployer Hunter was better covered on the newer chain than on the flagship one. Seven Solana routes — the reputation leaderboard, chain-wide stats, a single deployer's profile and full launch history, alert-volume stats, best recent tokens, and fresh graduations — were missing from all five Solana packages, while the Robinhood Chain packages covered the exact same seven on their side. The newer, smaller product line was more complete than the one we lead with. Fixed; all seven now ship in the Solana TypeScript, Python, MCP and both plugin packages. The bare madeonsol TypeScript and Rust SDKs already had them.

Our dependency ranges were fiction in both directions. Every x402-capable package declared its peers as unbounded >=0.0.1 or >=0.1.0. The x402 packages are at 2.22, and our code is written against 2.8–2.11. So a user pinned to @x402/[email protected] satisfied our range and got a package that could not possibly work, while a user installing fresh resolved a major we had never built against. The same held for @solana/kit (>=2.0.0 declared, 5.5.1 tested, 7.1.0 latest) and for the Python x402 extra (>=0.1 declared, against a 2.x module layout that does not exist on 0.x). Every range is now a caret bound on the version we actually test. Those peers are also lazily imported and only needed in keyless mode, so they are now marked optional — installing with an API key no longer drags in the entire Solana stack.

A Python bug that would have shipped with the new methods. The synchronous REST client passed query parameters straight to httpx, which encodes None as an empty value — ?tier=. Our routes use strict schemas that reject an empty enum with a 400 rather than reading it as "not supplied". Every method we were adding has optional parameters, so this would have bitten on the first call. Unset parameters are now dropped at the transport layer, matching what the Robinhood Chain Python client already did.

And we fixed the guard that should have caught all of this. Each SDK repo runs a route-parity check that fails CI when a package references an API path that does not exist. It was red on two of the four standalone repos — and every hit was a false positive, because the extractor was reading JSDoc and rustdoc prose as code and flagging backtick code spans like `/risk` as routes. A gate that cries wolf on every push is worse than no gate, because it trains you to ignore the day it is right. Both extractors now skip comments. The two Robinhood Chain checkers were failing differently: their route manifests were hand-maintained and forty entries stale, so the reverse direction — "is every documented route actually bound?" — had been silently passing on an incomplete list. Refreshed from the live spec, that check immediately flagged four unbound routes, all of which turned out to be server-side aliases of endpoints already covered; they are now allow-listed by name with the canonical target written next to each.

Versions. Robinhood Chain: TypeScript, Python, Rust, x402, MCP and both plugins all to 0.6.0. Solana: madeonsol-x402 1.24.0 (npm) and 1.24.0 (PyPI), mcp-server-madeonsol 1.21.0, the ElizaOS plugin 1.20.0, the Solana Agent Kit plugin 1.20.0. No API changes — the endpoints were already there. This release is entirely about being able to reach them.

Aug 12Platform

We audited our own API contract and fixed eight ways it could quietly mislead you

We ran a full product audit across both chains this week. Most of what it found was not broken code — it was working code whose output could mislead a paying customer without an…

Platform+

We ran a full product audit across both chains this week. Most of what it found was not broken code — it was working code whose output could mislead a paying customer without anyone noticing. Eight fixes shipped today. Three are outright bugs; five are disclosures we owed you.

The Robinhood Chain trade tape was silently dropping rows during pagination. /rhc/trades, /rhc/wallet/{address}/trades and /rhc/wallet-tracker/trades paged with a cursor on block_time alone — a second-grained value that dozens of trades can share on a chain producing multiple blocks per second. Whenever a page boundary fell mid-second, the rest of that second was skipped, undetectably. All three routes now use an opaque keyset cursor over (block_time, id) — the same scheme the Solana tape has used all along — with a has_more flag, and next_before is only emitted when there is genuinely more data. Old ISO-timestamp before values are still accepted forever, so existing integrations keep working and stop losing rows the moment they follow the new cursor. A nightly correctness case now walks five pages against a fixed reference window and fails on any missing or duplicated row.

A shipped WebSocket channel was invisible, and a published SDK constant didn't exist. The POST /stream/token discovery response advertised 14 channels; the server accepts 15. The missing one was token:graduations — live since day one, PRO+, and undiscoverable by any client that trusted the documented discovery flow. Separately, the 0.4.0 Robinhood Chain SDKs shipped a typed stream constant rhc:trades for a channel the server calls rhc:dex_trades — a subscribe with it was rejected with a warning frame the TypeScript SDK then silently discarded. Both lists now come from a single canonical registry the discovery route imports, so they structurally cannot drift again; the server accepts rhc:trades as a deprecated alias (inheriting the real channel's ULTRA gate); and a daily correctness case subscribes to every advertised channel and fails on any rejection. Corrected SDKs follow in the next release.

?primary_dex=launchpad filtering finally admits what the pricer already knew. Our own tracker stamps on-curve bonk tokens primary_dex=launchlab — and the /tokens filter enum rejected that exact value with a 400. Fixed, and the token surface gained an explicit launchpad field (pumpfun | launchlab | bags) on /tokens, /token/{mint}, /token/batch and /kol/feed, sourced from deploy records rather than inferred from the pool — because bags launches price through Meteora DBC and are indistinguishable by primary_dex alone. /tokens/almost-bonded accepts ?launchpad= too.

Leaderboards now paginate. /alpha/leaderboard scores tens of thousands of wallets and served exactly the top 100 (500 on ULTRA) with no way to see further — ever. It now takes offset with a deterministic tiebreaker so pages never overlap, as do /kol/leaderboard, /kol/tokens/trending, /kol/tokens/hot, /kol/pairs and /tokens/{mint}/top-traders (the latter sliced from cache, so deep pages cost nothing extra). We also deleted a comment on /deployer-hunter/alerts claiming pagination was ULTRA-only — it never was; the gate it described was dead code.

Every trade-derived endpoint now says what it covers. Persisted Solana trade history is scoped to the launchpad pipeline — that has always been documented, and five routes already carried a machine-readable coverage object saying so. Seven more now do: bundle, top-traders, cap-table, buyer-quality (single, batch and keyless), risk, the wallet profile and wallet holdings. The wallet profile also gained flags.coverage_note, stating plainly that is_sniper / is_bundler / is_dumper being false means not observed in covered trades — never verified clean. That sentence lived in a source comment; it belongs in the response.

Uniswap v4 liquidity now declares itself a ceiling. Last week we clamped v4's virtual-reserve arithmetic to the singleton's real holdings and wrote in this changelog that a clamped value is "a ceiling, not a measurement." Today the API says it too: every response carrying liquidity_usd for a v4-priced token now includes liquidity_basis: "v4_virtual_ceiling" ("measured" everywhere else), with a note on single-token routes. The $100 tradability gate on deployer alerts is unchanged — the clamp only ever lowers a number, so a v4 value can only false-pass a dust filter, and the response now tells you when a pass is a ceiling-pass.

Robinhood Chain aggregates disclose their attribution floor. Wallet-level analysis has carried attribution_complete_from: 2026-07-18 since July — but the four endpoints built on the same attributed-only data (/rhc/alpha-wallets, flow, top-traders, buyer-quality) disclosed nothing. They now carry the same attribution note, and buyer-quality's coverage block no longer claims "full parity with the Solana scorer": for launches before the floor, its "earliest 20 buyers" are the earliest 20 attributed buyers. The backfill that retires the floor entirely is scheduled; until it runs, the caveat travels with the data.

A dead monitor no longer reads as "All systems operational." The status endpoint computed overall from whichever health rows happened to be in the last 50 — so a monitor that stopped writing simply vanished from the calculation, and the page stayed green. Every core service is now fetched individually, a service whose last check is older than three cycles is marked stale, and stale, unknown or missing services degrade overall instead of disappearing from it. A monitoring failure now looks like what it is.

SDKs — all seven Robinhood Chain packages 0.5.0, four Solana packages patched. The RHC TypeScript, Rust and Python SDKs shipped a stream channel that never existed: rhc:trades, where the server says rhc:dex_trades — and the TypeScript event name rhc:trade was equally fictional, so a typed listener could never fire. In 0.5.0 the channel unions carry the six real channels (the four rule-engine channels were missing entirely), the TypeScript SDKs surface the server's channels_rejected warning frame as a typed warning event instead of silently discarding it, the phantom event literal is deliberately a compile error rather than a deprecation (a listener that can never fire should not compile), and the Python SDK gains a streaming client it simply never had — including stream_token(), which was missing even as a REST method. The Rust crate keeps RHC_TRADES for source compatibility, deprecated and re-pointed at the real channel. On the Solana side, madeonsol (TS 2.22.4, Rust 0.23.4), madeonsol-x402 (1.23.4) and the ElizaOS plugin (1.19.4) add the optional coverage object to their typed response models; we verified no published SDK rejects unknown fields, so older versions keep working — they just don't see the new field.

Aug 5Platform

We audited what our Robinhood Chain node actually tells us, and found four things we were getting wrong

We run our own Robinhood Chain node. It captures events well — 32.2 million logs decoded, 21.3 million trades written, KOL attribution resolved through ERC-4337 bundles. What it…

Platform+

We run our own Robinhood Chain node. It captures events well — 32.2 million logs decoded, 21.3 million trades written, KOL attribution resolved through ERC-4337 bundles. What it did badly was state: several values were read from the chain once, cached, and then trusted forever. Four fixes shipped today, three of which were live data errors on paid endpoints.

Market caps on the chain's largest tokens were wrong by up to 114%. Token supply was read exactly once — the first time a token ever traded — and never again. For the ~99% of Robinhood Chain tokens with fixed supply that is harmless. For the tokenized equities and stablecoins, which are beacon proxies whose implementation genuinely exposes mint(), it is not. Measured against our own node: USDe's supply had gone from 110,311,453 to 236,639,292 while we served a $110M market cap against a true ~$237M. The tokenized TSLA had gone from 2,324.297 to 5,043.288 (+117%), MSFT +34.5%. Supply is now re-read on a 10-minute TTL for any token that is still trading, and the correct figure — which our holder-reconciliation job had been reading from the chain every 10 minutes and discarding — is now propagated to the column the API serves. 605 tokens corrected on apply.

20,167 tokens were advertising liquidity that no longer existed. A pool's balances were only re-read when it traded. So a pool whose LP is pulled and then goes quiet kept its last-known liquidity indefinitely. We sampled 30 tokens claiming over $5,000 of liquidity with no trade in seven days and read their live balances on the node: 30 of 30 were fully drained, the largest still published at $92,820 against roughly zero. This is not cosmetic — liquidity_usd is a filter on /rhc/deployer-hunter/alerts and is served on the KOL feed, coordination and best-tokens. Pools now rotate through a balance re-read on a 6-hour TTL whether or not they trade.

And they now re-read within ~15 seconds of an actual LP withdrawal, because we subscribed to the removal events — Burn on Uniswap v2/v3 and negative ModifyLiquidity on v4. The node socket was already open, so this costs no extra RPC. Removals are also persisted, so a rug is now a queryable fact with a size and a timestamp; /rhc/tokens/{address}/risk gained liquidity.last_removed_at and an lp_removed_24h flag. One detail worth stating because it is the whole difficulty of v4: adds and removes are the same event, distinguished only by the sign of liquidityDelta. In our validation window 9,035 of 10,543 v4 liquidity events were adds. A decoder that ignored the sign would have reported every one of them as a rug.

Uniswap v4 liquidity was arithmetic, not money. v4's singleton makes per-pool balance reads impossible, so we derived virtual reserves from the last swap's price and in-range liquidity. Virtual reserves are not TVL, and at an extreme price the arithmetic runs away: 52 tokens each reported more liquidity than the entire v4 singleton holds, and the worst published $7.56 × 10²⁴. The whole PoolManager holds $19.4M across every pool on the chain. Each pool's derived reserve is now clamped to the singleton's real balance of that asset — a bound we can prove, since no single pool can be backed by more of an asset than all pools combined. Where a value is clamped it is a ceiling, not a measurement, and we would rather say so than publish a number we cannot defend.

Our honeypot detector was accusing innocent tokens — and we found it by trying to use it more. /rhc/tokens/{address}/risk simulates a sell through the router with state overrides; a revert is read as "bought but cannot be sold". We began precomputing that assessment for every liquid token so it could annotate the KOL feed and deployer alerts. The first 225 tokens produced 23 flagged as unsellable — and all 23 had completed a real sell on-chain within the previous hour. The simulation uses the Uniswap v3 router path, and 15 of the 23 had only a v2 or v4 route, so the revert meant "no route", not "trapped". Every simulated no is now cross-checked against observed sells and downgraded to unknown when reality disagrees. Across the first 550 tokens assessed, that check overturned 51 flags and zero false accusations remain. The honest consequence is that we currently report no confirmed honeypots on the chain rather than 51 fictional ones. sellable: "no" now means "trapped as far as we can tell", never merely "the call reverted".

/rhc/kol/feed and /rhc/deployer-hunter/alerts now carry a risk object (sellable, upgradeable, score, checked_at). It is null when a token has not been assessed yet — which means unknown, never clean — and it always travels with its own timestamp, because a cached "sellable" is the one thing that must never be mistaken for a live one. /rhc/tokens/{address}/risk is still computed live per request and does not read the cache.

Aug 4Platform

102 new Robinhood Chain KOL wallets, and 139k trades that were already ours

The Robinhood Chain KOL set grew by 102 wallets today, taking rhc_kol_trades from 185,005 rows to 324,788 — a 76% increase in tracked KOL activity. 412 KOLs have traded on the c…

Platform+

The Robinhood Chain KOL set grew by 102 wallets today, taking rhc_kol_trades from 185,005 rows to 324,788 — a 76% increase in tracked KOL activity. 412 KOLs have traded on the chain in the last seven days. Every endpoint that reads KOL data picks this up with no version change: /rhc/kol/feed, /rhc/kol/leaderboard, /rhc/kol/first-touches, consensus, and all four rule engines.

None of this is new ingestion. Every one of the 102 wallets was already trading through our pipeline and being written to rhc_trades — we simply had not labelled them as KOLs, so their activity never surfaced on a KOL endpoint. Retro-matching their history against the trades we already held produced 139,518 rows in under half a minute. The lesson we keep relearning on this chain is that the ingestion is rarely the constraint; the identity mapping is.

Where the coverage gap actually was. Two leaderboards went in. The first, sorted by 30-day smart-money ranking, was 92% new to us. The second, sorted by 1-day PnL, was 78% already covered. The difference is entirely explained by whether a wallet has a linked X account: our earlier imports scraped named KOLs, and every trader on the second list had a handle. The wallets we were missing are the anonymous ones — 73 of the 102 have no public identity at all and appear as a truncated address. They trade like KOLs and now score like them.

One wallet mattered more than the other 101. A trader we already tracked as a Solana KOL turned out to have a Robinhood Chain address we had never linked. That is not a new person — it is the same identity, now joined across both chains, which is the one thing a chain-specific leaderboard cannot tell you.

First-touch records were rebuilt rather than appended. Adding KOLs retroactively changes who touched a token first: 5,400 tokens gained a first-touch record they never had, and 2,575 existing records turned out to name the wrong wallet, because a newly-tracked KOL had bought the same token earlier. Those were repointed to the true earliest buy, keeping their row identity so nothing downstream broke. The correction is usually small and occasionally enormous: the median newly-correct first-toucher beat the previously-recorded one by 136 seconds, but the tail runs to 41 days. Had we skipped this, the next trade any of these KOLs made on a token they had already touched would have fired a "first touch" alert for a token that was first touched weeks ago.

No alerts were sent for any of it. A bulk insert of historical KOL trades will, by default, emit a first-touch event per token onto our internal bus — which is to say it would have pushed several thousand weeks-old tokens to live WebSocket subscribers and first-touch webhooks as if they had just happened. The backfill ran with trigger replication disabled so that history stayed history. If you have a first-touch subscription, you saw nothing today that was not genuinely first-touched today.


2026-08-02 (SDKs) — All seven Robinhood Chain SDKs now speak the rule engines — v0.4.0

Every Robinhood Chain SDK is updated to 0.4.0 with the four rule engines shipped earlier today: copy-trade, price alerts, coordination alerts and first-touch subscriptions — 22 operations each.

  • TypeScript (robinhood-chain-sdk, robinhood-chain-x402) — full CRUD plus the two read endpoints, with typed request/response shapes throughout.
  • Python (robinhood-chain) — same surface, sync and async. Also ships a NULL sentinel: the API's schemas are strict, so None cannot mean both "leave unchanged" and "clear this field" on a PATCH. NULL is how you clear a name, webhook URL or market-cap bound.
  • Rust (robinhood-chain) — same surface.
  • MCP server (mcp-server-robinhood-chain) — 52 tools, up from 30. The 22 new ones are correctly annotated as writes rather than reads, and the four deletes as destructive, so an agent knows what is safe to call speculatively.
  • ElizaOS and Solana Agent Kit plugins — grouped actions per engine. The agent actions default to list, so a mis-triggered action cannot delete one of your rules.

Four bugs we found in our own SDKs while doing this, all pre-existing:

  • Five endpoints were half-shipped in 0.3.x. top-traders, flow, peak-history, risk and holders existed in the TypeScript client but were missing from the Python async dispatch map — so await client.token_risk(...) raised AttributeError rather than returning data. They were also absent from the Solana Agent Kit plugin's method map and from the TypeScript smoke test's expected count, which is why nothing caught it. All fixed, with a regression test that asserts the endpoint map and the async dispatch set cannot diverge again.
  • The ElizaOS Robinhood Chain smoke test was failing outright — it asserted an error message pointing at /developer while the client points at /pricing. Its Agent Kit counterpart only appeared to pass because the assertion sat inside a catch that swallowed the failure.
  • The MCP tool registry had drifted: 30 tools registered, 25 declared in the published manifest. Now all three lists — registration, tool cards, manifest — are generated in step and verified equal.
  • Version manifests disagreed with themselves: the MCP server's server.json said 0.2.0 and its glama.json said 0.1.2 while the package was 0.3.1. All aligned.

None of these were caused by the new work; they were found because adding a surface this size forces you to read every list you own.


2026-08-02 (later) — Copy-trade rules on Robinhood Chain, and the one missing line that kept the chain read-only

Robinhood Chain now has a rule engine: POST /api/v1/rhc/copytrade/subscriptions. Point it at RHC KOL wallets, get a signal the moment one of them trades — by webhook, by WebSocket on the new rhc:copytrade:signals channel, or both.

The body mirrors the Solana engine with EVM-native names: source_wallets (lowercase 0x), min_trade_eth, sizing_amount in ETH, sizing modes fixed | proportional | percent_source. Quotas are per chain — a full set of Solana copy-trade rules does not consume RHC capacity. PRO gets 3 rules × 5 wallets, ULTRA 20 × 50, BUSINESS 100 × 250. Replays cannot double-fire: (subscription_id, tx_hash) is unique and delivery only happens after a fresh insert.

One filter is deliberately absent. There is no min_mc_usd / max_mc_usd on RHC copy-trade. The event our ingest publishes carries no market cap, so the band could only be implemented as a database lookup on every event of a chain doing ~3.3 million trades a day, or as a filter that silently never matches. We would rather the filter not exist than have it quietly lie — the same call we made keeping ?min_kol_winrate off the RHC KOL feed until the scores existed.

Why this took until now is the uncomfortable part. The ingestion service has been publishing rhc:kol_trade onto our internal event bus since the Robinhood Chain rollout. The evaluator that turns events into rule fires was subscribed to that same bus the entire time. It just had no branch for the event type, so every RHC trade arrived and was dropped on the floor. Nothing errored, nothing alerted, and the WebSocket channels carrying the same events worked fine — which is exactly why it went unnoticed. Robinhood Chain was read-only because of a missing if, not a missing pipeline.

There is now a health check that fails if active rules stop producing fires, rather than one that only confirms the tables exist.

Also fixed: you could create an RHC webhook but not edit it. POST /api/v1/webhooks and PATCH /api/v1/webhooks/{id} each carried their own copy of the valid-event list, and they had drifted — rhc:kol_trade was only in the create path. Registering worked, deliveries fired, and any PATCH that round-tripped the webhook's own events array came back 400. Both now read one shared list.

Price-alert webhooks now actually send. If you created a price alert with delivery_mode: "webhook" or "both", we handed you a signing secret and then delivered nothing. The market-cap tracker loaded your webhook URL and secret into memory on every reload and never called the signing/POST path — alerts fired correctly, but only over WebSocket, regardless of the delivery mode you chose. Our own API reference stated delivery happened there, which made it look intentional. It is now implemented: price_alert:dip and price_alert:recovery are signed HMAC-SHA256 over <timestamp>.<body> with the per-alert secret, delivery_mode is honoured, and success or failure is recorded on the alert event so you can see it in the events endpoint.

Price alerts on Robinhood Chain: POST /api/v1/rhc/price-alerts. Set a drop threshold against a token's market cap, get a dip — and optionally a recovery once it bounces off its low by a percentage you choose. Same one-shot state machine as the Solana alerts, delivered by webhook, on the new rhc:price_alert:events WebSocket channel, or both. Quota is per chain.

One difference we are putting in the response, not just the docs. Solana alerts are evaluated inside the market-cap tracker's live price loop and fire sub-second. Robinhood Chain prices are written by a service on a different machine that publishes no event when a price changes, so there is nothing for the evaluator to react to — it polls instead, roughly every 15 seconds, over just the tokens that have an alert on them. Effective latency is that interval plus how often the token itself reprices. Every create response carries an evaluation block saying exactly this, because the failure mode we care about is someone assuming parity with Solana and sizing a strategy around a number that does not apply.

Coordination alerts on Robinhood Chain: POST /api/v1/rhc/kol/coordination/alerts. Fire when several tracked KOLs buy the same token inside a rolling window — set the number of KOLs, the window, a minimum score, a cooldown, and a market-cap band. A token whose cap we cannot read is dropped from the band rather than passed through it; "unknown" is not "inside".

The score is the same v1 scorer we use on Solana, so the number means the same thing on both chains — with two differences we record on every signal rather than smoothing over. Quality is now real on Robinhood Chain: the KOL scoring layer we shipped earlier today supplies a genuine win-rate instead of a placeholder. Earliness is still a default — there is no early-entry measure on this chain, and inventing one would move scores without making them better. Each fired signal carries a score_inputs object showing exactly which components were measured and which were defaulted, so a score can be audited later without guessing what the engine knew at the time.

First-touch alerts on Robinhood Chain: POST /api/v1/rhc/kol/first-touches/subscriptions. Get pushed the moment a token receives its first buy from a tracked KOL — the earliest signal we have, and the one with the least competition on it. The subscription endpoint (filtered delivery to your own webhook) is Ultra. The rhc:kol:first_touches broadcast channel it publishes on is Pro+ — every first touch is emitted whether or not anyone holds a subscription, so a Pro socket receives the full stream.

This was the only one of the four Robinhood Chain rule engines that needed new data capture rather than wiring; the others ran off events that were already flowing. There is now a proper first-touch record per token, backfilled across all history — 9,613 tokens, exactly matching the number that have ever had a KOL buy. A second KOL buying the same token produces nothing, which is the whole point: this is a "first" feed, not a second trade feed.

Filters are kol, min_first_buy_eth, min_kol_winrate, strategy and a market-cap band. Unknown filter keys are rejected outright rather than quietly ignored — if you typo a filter name, you get a 400 instead of an alert stream that silently ignores half your criteria. Note there is deliberately no scout-tier filter here as there is on Solana: Robinhood Chain has no scout scoring, and we would rather omit the filter than ship one that matches nothing.

That completes all four Robinhood Chain rule engines — copy-trade, price alerts, coordination and first-touch — each with its own health check and end-to-end test.

And GET /api/v1/me now reports price_alerts. It was listed in the docs as part of the response and was never actually returned, so a client self-throttling off /me had no way to see its alert quota. The same response now also carries rhc_copytrade_rules — a per-chain budget that does not consume your Solana copy-trade allowance.

Aug 2SDK

Robinhood Chain had live WebSocket streams the whole time. Nobody could find them.

The RHC push surface has existed since the Robinhood Chain rollout. It was in no documentation, so as far as every customer and every SDK was concerned it did not exist.

SDK+

The RHC push surface has existed since the Robinhood Chain rollout. It was in no documentation, so as far as every customer and every SDK was concerned it did not exist.

Two WebSocket channels — rhc:kol_trades (PRO+) and rhc:dex_trades (ULTRA+) — plus the rhc:kol_trade webhook event have been running in production for weeks. They were registered in the streaming service and accepted by the webhooks API, and they appeared in neither our API reference nor the OpenAPI spec. Since our SDKs and MCP server are generated from that spec, they did not expose them either. We sold Robinhood Chain on being early to a new chain and then shipped something you could only poll.

That gap shows up in the numbers. Robinhood Chain currently carries roughly 3.3 million trades a day from ~160,000 distinct traders — on our own measurements about a fifth of Solana's real trading activity — while accounting for 1.6% of API traffic. The chain was never the problem.

All three are now documented, including the part people would otherwise get wrong: RHC channels ride the same socket and the same connection limit as the Solana channels, so you do not need a second connection. Amounts are native ETH, addresses are lowercase 0x, and identifiers are tx_hash/block_number — do not reuse a Solana deserializer unchanged. There is deliberately no rhc:dex_trade webhook; the firehose is WebSocket-only.

/rhc/kol/feed now supports ?min_kol_winrate and ?strategy. These were withheld on purpose — both read a Solana-only scoring table, and a filter that silently matches everything or nothing is worse than no filter. Robinhood Chain now has its own KOL scoring layer, so they work.

Two things about the semantics, because they differ from the Solana feed:

  • Winrate is measured on closed positions only — a position counts once at least 90% of what was bought has been sold. A KOL who has not sold has no winrate rather than a zero, and those wallets are dropped by the filter rather than scored as losers. "Not yet resolved" is not the same as "lost".
  • strategy is a hold-time bucket (scalper, day_trader, swing, inactive, unscored), not a port of the Solana strategy tag. Reusing that label would imply a parity that does not exist.

Endpoints backed by our trade history now tell you when they don't cover something. Persisted Solana trade history is scoped to the launchpad pipeline — pump.fun, LaunchLab/bonk and bags. For a token or wallet outside it, /tokens/{mint}/flow, /wallet/{address}/pnl, /positions and /trades returned zeros and empty arrays, which is indistinguishable from "this never traded". A wallet trading established memecoins got a PnL that was wrong rather than partial, and nothing in the response said so.

Every one of those responses now carries a coverage object with in_scope. When it is false, the zeros mean not captured, not no activity. The /wallet/{address}/pnl 404 keeps its exact status and message — SDKs match on that string — and carries the disclosure alongside it.

Corrections to things we had published that were not true:

  • /rhc/alpha-wallets said it refreshed every 15 minutes. It refreshes every 30, and that is the last stage of a pipeline whose worst case is several hours.
  • The Solana API page said leaderboard and PnL data refreshes every 5 minutes. That is true only for the today and 7-day leaderboards; 30-day is 15 minutes, and 90-day and 180-day are every 6 hours.
  • Our business page promised an "incident history" and an "incident log" on the status page. Neither existed.
  • The status page said six core services were monitored and named one that is not among them, while omitting two that are.
  • The 99.5% uptime figure is now labelled as what it is: an operating target, not a measured result or a guarantee. Our terms disclaim warranties, and publishing a number that reads like a promise next to that was a contradiction we should not have shipped. Measured availability stays public so you can check the real number instead of taking ours.

New: /security and /dpa. A security posture page covering infrastructure, key handling, access control, backups and recovery — including what we don't have (no SOC 2, no ISO 27001, no external penetration test, no disk-level encryption on the database volumes, and a single primary host). A signable GDPR Article 28 Data Processing Agreement with the sub-processor list. Vulnerability reports: /.well-known/security.txt.

Aug 1Platform

Overload is a 503 with `Retry-After` now, not a 500 — and the free tier always had 6× the burst we documented

On the morning of 2026-08-01 the API returned 940 server errors in two hours, and the way we reported them made it worse.

Platform+

On the morning of 2026-08-01 the API returned 940 server errors in two hours, and the way we reported them made it worse.

The trigger was our own nightly database dump. It has grown with the trade firehose to the point where a single pass saturates disk IO for long enough that queries start hitting Postgres' statement timeout. Three endpoints — /tokens/{mint}/bundle, /flow, and /tokens/{mint}/trades — caught that timeout and returned a bare 500.

That is the wrong answer, and not merely cosmetically. A 500 says "this is broken"; a timeout says "this is too heavy right now, try again". A 500 also carries no retry hint, so the client that hit it retried the same token five to nine times a minute and added load to the exact condition that caused the failure. Requests per token went from a baseline of 1.4 to 5.4, and every one of them failed.

What changed:

  • A query killed by the statement timeout now returns 503 with retry_after_seconds — on those three endpoints, matching what top-traders, /wallet and /holdings already did. There was one classifier for this behind three slightly different private copies and three endpoints with none at all; there is now exactly one.
  • Every 503 and 429 now sends a real Retry-After header. Until today not a single 503 in the API set it — the value existed only inside the JSON body, where no HTTP client and none of our seven SDKs look for it. If you have retry logic, it now works without special-casing us.
  • /tokens/{mint}/bundle is cached for 60 seconds. It was the only endpoint in its family without a cache, which is why the retry storm hit it hardest. Cache state is reported in an X-Cache header — deliberately not a new body field, which would break strictly-typed SDK models.

The free tier's burst limit has been 60/min for a while. Our docs said 10. We raised it so bot builders could sustain roughly one request per second, then never updated the pricing page, API docs, or comparison tables — so the limit was six times more generous than what we advertised, and anyone who throttled to our published number was leaving most of it unused. Corrected everywhere. Free is 200 calls/day, 60/min burst. Nothing about your key changed; only what we told you about it.

We also could not see this happening, which is the part worth admitting. The error rate reached 20.9% for two hours and nothing scheduled was reading the table that records what customers actually received. Our health probes reported green throughout, because they check a handful of synthetic endpoints on a path that bypasses normal auth — a different population from real traffic. Nginx could not see it either: an application-generated 500 is a perfectly successful upstream reply as far as the proxy is concerned.

There is now a check that reads the real request log every five minutes and alerts on the 5xx rate directly. While wiring it up we found the alerting had a wider hole: of 77 monitored services, only 10 had ever emitted a status capable of sending an alert at all. That is fixed too.

None of this is a feature. It is the difference between an incident you hear about from us and one you notice yourself.

July 2026

20 ships
Jul 30SDK

`trader_eoa` on Robinhood Chain now means the trader, not the bundler

We were crediting relayers with other people's trades, and we've fixed it — forward and backward.

SDK+

We were crediting relayers with other people's trades, and we've fixed it — forward and backward.

Robinhood Chain trades can be submitted as ERC-4337 user operations: you sign an intent, and a third-party bundler wraps it into a transaction and pays the gas. On those transactions tx.from is the bundler's address, not yours. trader_eoa was being written from tx.from, and documented across every SDK as "tx.from" — so on every bundled trade the relayer got the credit and the actual trader disappeared from the data.

It was not a rounding error. Roughly 46 bundler addresses had absorbed enough trades to occupy ranks 1–40 of the Robinhood Chain alpha-wallet leaderboard — the wallets we present as the sharpest money on the chain were gas relayers. After the fix there are zero in the top 100.

trader_eoa now holds the effective trading account: tx.from on an ordinary transaction, and the userOp sender when the trade was bundled — never the router, never the bundler. The bundler is preserved separately in tx_sender, populated only when the two differ, so nothing is thrown away. Attribution walks the UserOperationEvent log the EntryPoint emits after running each op, which is what makes multi-op bundles (about 11% of them) resolve correctly instead of collapsing to one wallet.

History was reattributed, not just fixed going forward. 4,081,928 past trades were rewritten from a chain-wide sweep of every UserOperationEvent — including ops routed through all three EntryPoint contracts that are live on the chain, since filtering on the Robinhood Chain one alone misses 23% of them. If you pulled a leaderboard, a wallet profile or a top-traders list before today, pull it again: the answers changed.

Our own truth check had been certifying the bug. The oracle that samples recent trades against the chain every two hours was asserting trader_eoa == receipt.from — which is exactly what the bug produced, so bundled rows passed vacuously and the check reported clean. It now resolves the owning user operation from the receipt logs instead. We'd rather publish that than quietly fix it.

All 7 Robinhood Chain SDKs go to 0.3.1 — TypeScript, Python, x402, MCP server, ElizaOS plugin, Solana-Agent-Kit plugin and the Rust crate. Documentation only: no method, parameter or response-shape changes, so it's a drop-in bump. What changes is that they no longer tell you trader_eoa is tx.from.

Jul 30Platform

Five new Robinhood Chain endpoints: who made money, who's dumping, and can you actually sell it

Five new token-intelligence endpoints on Robinhood Chain, all PRO+, all in the SDKs:

Platform+

Five new token-intelligence endpoints on Robinhood Chain, all PRO+, all in the SDKs:

  • GET /api/v1/rhc/tokens/{address}/top-traders — who actually made money on a token, with win-rate, bot heuristic, KOL identity, dump-cluster membership and early-buyer rank. One caveat we'd rather state than bury: net_eth is realized flow (sell − buy), not PnL. It doesn't value a trader's remaining bag, so a wallet that bought and still holds ranks last, not first.
  • GET /api/v1/rhc/tokens/{address}/flow — which cohort is accumulating and which is distributing, split into KOL / bot / dump-cluster / early-buyer / unprofiled / smart-money / retail. Positive net_eth means that cohort sold into you.
  • GET /api/v1/rhc/tokens/{address}/peak-history — peak market cap, drawdown, and a running high-water curve.
  • GET /api/v1/rhc/tokens/{address}/risk — the one we'd actually use before buying.
  • GET /api/v1/rhc/tokens/{address}/early-buyers — the first 20 buyers, joined to realized PnL and whether they still hold.
  • GET /api/v1/rhc/tokens/{address}/holders — exact holder set and concentration.

Risk is EVM-native, not a Solana port — and that distinction is the whole point. EVM has no mint or freeze authority. We scanned 300 random Robinhood Chain tokens: only 2.3% even expose an owner function and 0% expose mint in their own bytecode. A Solana-shaped risk model would answer "all clear" for ~98% of the chain and tell you nothing. So this one reports what actually discriminates: proxy upgradeability, LP custody, and above all sellability — we simulate a sell at the chain head to catch a token you can buy but not sell. That check is never cached, because whether a token is sellable can change the moment an owner flips a setting. Resolving proxies first matters too: 14% of tokens are minimal proxies with no code of their own, and the tokenized equities are beacon proxies whose implementation is what carries mint/pause/upgradeTo — scan the wrapper and you'd report "no owner, no mint" for the only tokens on the chain that genuinely are mintable.

Holders are exact, not estimated — and we tell you when they aren't. Balances are folded from ERC-20 Transfer logs rather than inferred from trades, which is why this exists on Robinhood Chain when the Solana equivalent was withdrawn: trade-derived balances decay to mostly-wrong within days. Before shipping we replayed a token's entire life and the reconstructed supply matched on-chain totalSupply() to the wei, with 15 of 15 top holders matching a live balance read. Every token carries that reconciliation, and one that fails it comes back verified: false with a reason rather than pretending. Concentration deliberately excludes liquidity pools and burn addresses — the biggest "holder" of a token is normally its own pool, which would make top1_share meaningless.

All 7 Robinhood Chain SDKs are at 0.3.0 — TypeScript, Python, x402, MCP server, ElizaOS plugin, Solana-Agent-Kit plugin and the Rust crate — each going from 25 to 30 endpoints.

Jul 29Platform

Checkout that prices upgrades correctly, and Robinhood Chain data that proves itself against the chain

Upgrades are now priced properly, and signed-out payers aren't lost. If you were already on a paid plan and moved up a tier, checkout could quote you the full price of the new p…

Platform+

Upgrades are now priced properly, and signed-out payers aren't lost. If you were already on a paid plan and moved up a tier, checkout could quote you the full price of the new plan instead of the difference. It now prices the upgrade. Separately, anyone who started a purchase while signed out could reach the end of the flow and lose it — that path now carries you through. There's also a dedicated /checkout route rather than a step buried in the dashboard.

The card-required free trial is gone. It converted nobody, and asking for a card up front to access data you can evaluate in a single call was friction with no payoff. Start on a plan when the data is worth it.

Robinhood Chain trade data is now checked against the chain itself. A new oracle samples recent rhc_trades rows every two hours and re-verifies them directly against our own Robinhood Chain node — amount, direction, token and counterparty. It's been running clean at 40/40 on every sample. Nobody else publishing Robinhood Chain data verifies it against the chain in public, and we'd rather find a decoder drift ourselves than have you find it.

Robinhood Chain alpha-wallet data got much faster and materially fresher. The wallet reputation behind /rhc/alpha-wallets, buyer-quality scoring and the wallet endpoints is now maintained incrementally instead of being recomputed wholesale. The refresh that feeds it went from 168 seconds to 22, and the underlying rollup updates in milliseconds rather than minutes — so the rankings you read track the chain closely instead of drifting between rebuilds. A full rebuild runs every six hours and reconciles itself against ground truth, and the difference is measured and alerted on rather than assumed.

Reads no longer stall behind maintenance. Partition-securing DDL could briefly block API reads while it ran. It doesn't anymore.

All 14 SDK packages picked up a documentation pass and a patch release across npm, PyPI and crates.io.

Jul 25Platform

Robinhood Chain deployer intelligence: 9 new endpoints, and a tier model that resists farming

Nine new Robinhood Chain endpoints, closing the biggest gaps against the Solana surface:

Platform+

Nine new Robinhood Chain endpoints, closing the biggest gaps against the Solana surface:

  • GET /api/v1/rhc/deployer-hunter/{address}/trajectory — is this deployer improving or coasting? Streaks, a 10-launch rolling hit rate, and a trend verdict.
  • GET /api/v1/rhc/deployer-hunter/{address}/tokens — the full paginated launch history, enriched with live MC, peak MC and liquidity.
  • GET /api/v1/rhc/deployer-hunter/best-tokens — the highest-peaking launches from reputable deployers only.
  • GET /api/v1/rhc/deployer-hunter/stats — chain-wide reputation census, including the active tier thresholds so you never have to guess what "elite" means.
  • POST /api/v1/rhc/token/batch — up to 50 tokens in one call.
  • POST /api/v1/rhc/tokens/batch/buyer-quality — up to 20 tokens' early-buyer cohorts scored at once.
  • Four path aliases so a Solana integration ported to Robinhood Chain stops 404-ing on capabilities we already ship: /rhc/token/{address}, /rhc/tokens/{address}/trades, /rhc/kol/tokens/hot, /rhc/alpha/leaderboard.

Deployer tiers now resist farming. A $40K peak market cap turned out to be cheap enough to manufacture — roughly 7,400 tokens clear it in a week, and we found operations mass-relaunching a single ticker across rotating wallets (one used 149 wallets and 341 contracts in a month) to farm a high graduation rate. Two of those wallets had earned our top tier.

Tiers are now earned on the $100K runner rate and require 24 hours of deployer history, so a wallet minutes old can no longer qualify, fire alerts and decay. graduation_rate still means the $40K bar and is still returned — it just no longer sets the tier.

The alert feed tells the truth about now, not about then. tier and its explanation are resolved at read time instead of being frozen when the alert fired, so a demoted deployer can't keep being advertised as good-tier (tier_at_alert and tier_is_stale preserve the original). A tradability filter is now on by default — the feed had been serving alerts on tokens that pumped and drained, one at $45K market cap against $68 of liquidity. Pass include_untradeable=true for the raw tape.

All 7 Robinhood Chain SDKs are at 0.2.0 — Python, x402, MCP server, ElizaOS plugin, Solana-Agent-Kit plugin, the bare TypeScript SDK and the Rust crate — each going from 14 to 25 endpoints.

Jul 22Platform

Robinhood Chain x402: pay-per-call in USDG or USDC

Six Robinhood Chain intelligence endpoints are now keyless and pay-per-call for AI agents via the x402 protocol — the first KOL & deployer intelligence API on Robinhood Chain pa…

Platform+

Six Robinhood Chain intelligence endpoints are now keyless and pay-per-call for AI agents via the x402 protocol — the first KOL & deployer intelligence API on Robinhood Chain payable per-call in USDG. Your agent's wallet is the key: no signup, no subscription.

Every endpoint is dual-accept — the agent pays with whichever stablecoin it holds:

  • USDG on Robinhood Chain (native, chain id 4663, via EIP-3009 transferWithAuthorization) — flat $0.04 minimum per call.
  • USDC on Solana — the standard $0.005–$0.02 per call.

Endpoints: GET /api/x402/rhc/kol/feed, /kol/hot-tokens, /kol/leaderboard, /tokens/{address}, /tokens/{address}/buyer-quality, /tokens/{address}/kol-consensus — responses match the equivalent keyed /api/v1/rhc/* endpoints exactly. Settlement runs through our own Robinhood Chain node and a self-hosted, non-custodial facilitator (the payment moves wallet→wallet directly — we never take custody).

Free discovery endpoint for agent self-configuration: GET /api/x402/rhc. Full details at /robinhood/x402. Prefer a flat monthly plan (Robinhood Chain bundled at no extra cost)? See madeonsol.com/pricing.

Jul 21SDK

Dedicated Robinhood Chain SDKs

Robinhood Chain now has its own SDKs — seven standalone packages, separate from the Solana ones so it's unmistakable you're building on a different chain. Each is fully typed wi…

SDK+

Robinhood Chain now has its own SDKs — seven standalone packages, separate from the Solana ones so it's unmistakable you're building on a different chain. Each is fully typed with EVM-native fields (0x addresses, eth_amount, tx_hash, block_number) and covers the full RHC surface: KOL feed / leaderboard / hot-tokens / profile, the DEX trade tape, token discovery + candles + KOL-consensus + buyer-quality + launch-bundle detection, Deployer Hunter, and smart-money alpha wallets.

New packages:

  • TypeScript — npm i robinhood-chain-sdk
  • Python — pip install robinhood-chain
  • Rust — cargo add robinhood-chain
  • x402 (robinhood-chain-x402), MCP server (mcp-server-robinhood-chain), ElizaOS (@madeonsol/plugin-robinhood-chain), and Solana Agent Kit (solana-agent-kit-plugin-robinhood-chain) plugins — for AI agents.

Same msk_ key, same base URL — and Robinhood Chain is bundled into every tier at no extra cost. The free tier is 200 requests/day across every endpoint. Start at madeonsol.com/pricing; full reference at /robinhood and /api-docs.

Jul 20Platform

Robinhood Chain: launch-bundle detection

Spot coordinated launch bundles on Robinhood Chain — the same signal we run on Solana, now on RHC.

Platform+

Spot coordinated launch bundles on Robinhood Chain — the same signal we run on Solana, now on RHC.

New API endpoint (/api/v1/rhc/*):

  • GET /rhc/tokens/{address}/bundle (BASIC gets the scalar signal; PRO adds the top-10 wallets; ULTRA the full cohort with alpha-wallet identity) — detects when a token's earliest buyers are a coordinated bundle: we rank the first 20 distinct buyers by on-chain order and flag a bundle when 3+ of them buy in the same block, then report how much of what they bought they still hold (held_ratio, held_pct_of_supply) and whether they've fully exited (bought the launch, then dumped). Robinhood Chain is an Arbitrum Orbit L2 with no atomic multi-wallet transaction, so a detected bundle is same_block — there's no atomic_tx sleight-of-hand to hide behind.

Buyer-quality now has full Solana parity. GET /rhc/tokens/{address}/buyer-quality previously declared bundle and dump-cluster detection unavailable — both are now live. A bundled buyer in the top 10 costs the quality score −5, and a heavily bundled cohort (>10 of the first 20) costs −15, so bundled launches land in the negative band. And a new dump_cluster_count flags early buyers that repeatedly show up in launches that crashed off their own peak (a rolling 42-day ensemble) — informational, so it surfaces the pattern without moving the score. We out-of-sample validated it on Robinhood Chain first: a wallet cluster of 3+ in a token's first 20 buyers predicts a crash ~98% of the time vs a 50% base. The coverage field now reports both signals available.

Forward-looking by design: bundles clip right after launch, so detection runs on new launches going forward — straight from our own Robinhood Chain node, same accuracy standard as Solana.

Jul 20SDK

SDK streaming: clean shutdown

A lifecycle fix for the two TypeScript SDKs' managed WebSocket streaming client. Calling close() now fully tears down the underlying socket, so short-lived scripts (a one-off st…

SDK+

A lifecycle fix for the two TypeScript SDKs' managed WebSocket streaming client. Calling close() now fully tears down the underlying socket, so short-lived scripts (a one-off stream read, a cron task) exit promptly instead of hanging until the process is killed.

  • [email protected] and [email protected] — on Node the stream client now prefers the ws package (which exposes terminate()) and hard-terminates the socket on close(); browsers still use the native WebSocket. On Node ≥22 the global WebSocket kept its TLS socket open after close(), holding the event loop.

No API changes — purely a client-side lifecycle fix. If you're on Node ≥22 and want the fast exit, make sure ws is installed (npm i ws); it's already a dependency in most setups.

Jul 19Platform

Robinhood Chain token intelligence: KOL consensus + buyer quality

Two new per-token intel endpoints on Robinhood Chain, plus a correctness fix under the hood.

Platform+

Two new per-token intel endpoints on Robinhood Chain, plus a correctness fix under the hood.

New API endpoints (/api/v1/rhc/*):

  • GET /rhc/tokens/{address}/kol-consensus (PRO; ULTRA adds the buyer/exited wallet lists) — how the tracked-KOL cohort is positioned on any RHC token: distinct buyers vs sellers, exit rate, net ETH flow, total buy/sell volume, first-touch wallet, and median entry market cap. It also returns entry_mc_samples so you can see how many buys the median is based on. Aggregated server-side across every KOL trade on the token — no result-size cap.
  • GET /rhc/tokens/{address}/buyer-quality (free tier) — a 0–100 quality score on a token's earliest buyer cohort, built from wallet win-rate, KOL presence, and bot-domination. We're upfront about coverage: the bundle-buyer and dump-cluster signals we run on Solana need launchpad-level decoding we don't have on RHC yet, so those are declared unavailable in a coverage field rather than reported as a misleading zero.

Reliability: the bulk POST /tokens/batch/buyer-quality (Solana) now runs its wallet lookups in parallel, removing the intermittent timeout that could affect very large batches on busy days.

As always, straight from our own nodes — same accuracy standard across both chains.

Jul 17Platform

Robinhood Chain deployer reputation, KOL launchpads, and consensus signals

Robinhood Chain Deployer Hunter is live. Check any RHC token deployer's reputation and get live signals when proven ones launch — /robinhood/deployer-hunter.

Platform+

Robinhood Chain Deployer Hunter is live. Check any RHC token deployer's reputation and get live signals when proven ones launch — /robinhood/deployer-hunter.

  • Market-cap graduation model. Most RHC launchpads are direct-to-DEX (no bonding curve), so a deployer's graduation rate = the share of their tokens that reached a $40K+ peak market cap, and runner rate = $100K+. Every deployer from chain genesis is scored and tiered (elite / good / neutral / spam factory).
  • Peak market caps reconstructed to genesis. We backfilled each token's all-time-high market cap from on-chain DEX trades back to the chain's first block, so reputation reflects a token's full history — not just what we've seen since we started tracking.
  • Live deployer signal feed + free deployer checker on the site, with the full ranked leaderboard available via the API.

API changes (/api/v1/rhc/*):

  • /rhc/deployer-hunter/leaderboard and /{address} now return graduation_rate, graduated, runners, and runner_rate. This replaces the old bonding_rate / curve_tokens fields — RHC graduation is a market-cap milestone, not a bonding-curve event.
  • launchpad added to RHC KOL trades and trade endpoints, so you can filter by where each token launched.
  • New GET /api/v1/rhc/kol/hot-tokens (free tier) — tokens multiple tracked RHC KOLs are buying right now (consensus signal), with current market cap and buyer counts.
  • Richer RHC KOL data — feed and per-wallet endpoints now include current market cap, the multiple since the KOL traded (did the call run), deployer tier, and graduation status.

All of it comes straight from our own Robinhood Chain node — same accuracy standard as our Solana feeds, no third-party data API in the middle.

Jul 15Platform

Robinhood Chain support is coming: MadeOnSol goes multichain

MadeOnSol is expanding beyond Solana. Over the coming week we're rolling out coverage for Robinhood Chain — Robinhood's new EVM Layer-2 (Arbitrum Orbit, chain ID 4663) — bringin…

Platform+

MadeOnSol is expanding beyond Solana. Over the coming week we're rolling out coverage for Robinhood Chain — Robinhood's new EVM Layer-2 (Arbitrum Orbit, chain ID 4663) — bringing the same on-chain intelligence you use for Solana to a second chain, on the back of one of the busiest memecoin scenes in crypto right now.

Live today:

  • Chain switcher in the header — Solana now, with Robinhood Chain — Soon alongside it. The site is multichain-aware end to end.
  • A research cluster on Robinhood Chain on the blog: what the chain is, how to bridge to it, the memecoin landscape, and the hood.fun launchpad.

Rolling out over the next few days:

  • KOL, deployer, and sniper intelligence for Robinhood Chain, served through the same /api/v1 endpoints (chain-parameterized) and gated by the same tiers as their Solana equivalents — no per-chain upsell, it's coverage included in the plan you already have.
  • We're running our own Robinhood Chain node, so the data comes straight from the chain — the same accuracy standard as our Solana feeds, with no third-party data API in the middle.

New here? The free tier is 200 requests/day across every endpoint. See plans.

Jul 13SDK

Token depth / price impact + SDK release across all 7 packages

API:

SDK+

API:

  • New GET /api/v1/tokens/{mint}/depth (PRO+) — per-pool price-impact / slippage: "how much SOL does it take to move the price 1% / 5% / 10%" (to_move_price) plus the impact, average fill price, and tokens received for each buy size you ask about (?sizes= up to 8 SOL amounts, default 0.5,1,5,10). Exact for constant-product AMMs (PumpSwap, Raydium v4/CPMM, Meteora DAMM — computed from our streamed reserves, zero RPC, validated against Jupiter) and correct for pump.fun / bonk bonding curves via a live read of the curve's virtual reserves. Honesty built in: impact is per-pool (not router-optimal), and concentrated-liquidity pools (Raydium CLMM, Orca, Meteora DLMM) return under unsupported_pools[] with a reason instead of a wrong number. The sizing data a bot actually needs — raw liquidity_usd can't tell a deep pool from a thin one-sided one.

SDKs — all 7 packages updated:

  • Every SDK gains a token depth method and documents the risk endpoint's dev self-activity block (dev-buy at create, dev sells, live wallet_empty / transferred_out): TypeScript madeonsol 2.21.0, Rust madeonsol 0.23.0, Python madeonsol-x402 1.23.0, TypeScript madeonsol-x402 1.22.0, MCP server 1.20.0, ElizaOS plugin 1.19.0, Solana Agent Kit plugin 1.19.0.
Jul 11Platform

Dev-activity intelligence: did the dev buy, did the dev dump, is the dev wallet empty

API:

Platform+

API:

  • New dev block on GET /api/v1/tokens/{mint}/risk — the full deployer self-activity story for a launch, three layers deep:
    • Dev-buy at create: buy_sol, buy_tokens, buy_supply_pct — the deployer's self-buy extracted exactly from the create transaction's balance meta ("dev bought 2.5 SOL = 8.2% of supply at launch"). Captured on effectively all new pump.fun creates going forward.
    • Dev sells: sold_tokens, sold_sol, first_sell_at, last_sell_at — the deployer's post-create trades on their own token, rolled up every 2 minutes.
    • Live truth: holdings_tokens, holdings_supply_pct, and wallet_empty — the dev wallet's current on-chain balance for the mint, read live (60s cache). This answers the question that actually gates most buys — "is the dev wallet empty right now?" — regardless of trade-capture coverage.
    • Plus transferred_out: when the on-chain balance sits well below what the dev's trades say they should still hold, the tokens left by transfer, not sale — the classic pre-dump wallet-hop. Only asserted when we have the coverage to prove it; reads null (unknown), never a guess.
  • deployer:alert webhook/WS payloads now carry dev_buy_sol + dev_buy_supply_pct — filter tracked-deployer launch alerts by dev skin-in-the-game the moment they fire.
  • GET /api/v1/wallet/{address} is faster at the tail — the enrichment layer's external lookups are now cached, tighter-bounded, and parallelized; worst-case latency dropped from ~6s to well under 1.5s, typical repeat lookups ~100ms.
Jul 11Security

x402 never-charged-for-errors, gap-free deployer history, security & data hardening

x402:

Security+

x402:

  • Invalid requests are now rejected before payment. Every keyless x402 endpoint validates your query params — enums, numeric ranges, address/timestamp formats, and from/to ordering — before settlement, returning a clean 400 with the offending param named. A malformed call like ?tf=99m or ?period=99d is no longer settled-then-errored, honoring the "pay → get data, never pay for an error" contract across the whole catalog (previously enforced on only two endpoints).

API:

  • GET /api/v1/deployer-hunter/{wallet}/history returns a continuous daily series. Snapshots are now stored write-on-change (a row only when a deployer's reputation actually changes), and the endpoint forward-fills the gaps on read — so you still get one entry per day, with a new carried flag marking days synthesized from the most recent real snapshot. Same shape, far less storage, no behavior change for consumers beyond the new field.

Reliability & security:

  • Account deletion is now all-or-nothing. Every erasure step is checked and the irreversible account delete is aborted if any step fails — no more orphaned rows on a partial failure — and the statutory invoice snapshot is guaranteed to persist before payment records are removed.
  • Changing your password now signs out your other sessions.
  • Hardened webhook signature enforcement, tightened a handful of error responses (duplicate actions now return 409, malformed input 400 instead of 500), and added dead-cron / retention-job monitoring across the platform.
Jul 10Platform

Wallet reputation flags + batch classify, token trade tape, sniper footprint, x402 catalog 18 → 25

API:

Platform+

API:

  • New POST /api/v1/wallet/batch/classify (PRO+) — bulk wallet reputation flags for up to 100 addresses in one call. Body { wallets: string[] } (or a comma-separated string). Per wallet: is_sniper, is_bundler, is_dumper + the raw dump_cluster cohort counts, is_kol + kol_name, and bot_confidence — values identical to the single-wallet flags block. Pure index lookups: ~10ms per 100-address batch, counts as 1 request. Screen an entire early-buyer list or copy-trade candidate set in a single call.
  • GET /api/v1/wallet/{address} — reputation flags in the flags block. New: is_sniper (≥5 tokens early-bought with ≥80% flipped in under 5 minutes; behavior-updated ~every 12 min), is_bundler (bought >1 token in the same block, ever — lifetime flag), is_dumper (≥5 dump cohorts and 0 runner cohorts in a rolling 42-day window) plus the dump_cluster cohort counts. Also fixed: bot_confidence was always null due to a coercion bug — it now returns the real string enum (none/low/medium/high). Honesty note: flags are pump.fun-pipeline scoped — false means not observed, not verified clean.
  • New GET /api/v1/tokens/{mint}/trades (PRO+) — the mint-scoped trade tape: every captured trade for one token, newest first, cursor-paginated. Filters: limit (1–500), action (buy/sell), wallet, since/until (default full history). Each trade carries tx_signature, wallet_address, action, sol_amount, token_amount, price_sol/price_usd, early_buyer_rank, slot, and block_time. The response's coverage block states the capture window plainly (history starts 2026-04-12, pump.fun-pipeline scoped). The backfill complement to the live firehose — seed your history, then stay current via the stream.
  • Sniper footprint — how hard a launch was sniped. GET /api/v1/tokens/{mint}/risk gains inputs.sniper_footprint and every deploy on GET /api/v1/sniper/recent gains a footprint block: the rollup of buys landing in slots deploy−1 through deploy+3 — buys, buyers, sol, supply_pct (% of supply bought in-window), and sniper_wallet_buys (window buyers already on the sniper registry). Informational — it doesn't move the risk score — and data_available: false means the mint is outside our capture window, not zero snipes. Null on sniper/recent for deploys younger than the rollup's 10-minute settle window.

x402:

  • Keyless catalog grew 18 → 25 endpoints. Seven more endpoints are now payable per-call in USDC with no API key: tokens/{mint}/candles ($0.01), tokens/almost-bonded ($0.01), tokens/{mint}/top-traders ($0.02), tokens/{mint}/cap-table ($0.02), sniper/recent ($0.01), tokens/{mint}/flow ($0.01), and deployer-hunter/{wallet}/trajectory ($0.01). Full list on the free discovery endpoint at /api/x402.

Data quality:

  • Phantom counterparty rows eliminated. Bonding-curve PDAs had been recorded as wallet-side traders on ~32% of token_trades rows — those phantom rows are now filtered at ingest and cleaned up historically, and early-buyer ranks were recomputed accordingly. Cap-table, buyer-quality, trade tapes, and wallet PnL all read cleaner for it.

SDKs:

  • The batch-classify and token-trades methods ship across all 7 SDKs — madeonsol-x402 1.21.0 (npm), the bare TypeScript madeonsol 2.20.0, madeonsol 1.22.0 (PyPI), the Rust crate madeonsol 0.22.0, the MCP server mcp-server-madeonsol 1.19.0, the Eliza plugin @madeonsol/plugin-madeonsol 1.18.0, and solana-agent-kit-plugin-madeonsol 1.18.0. Additive only, no breaking changes.
Jul 8Platform

Business tier — self-serve embedding at 500k requests/day

Pricing:

Platform+

Pricing:

  • New BUSINESS tier — €400/mo or €4,000/yr. The self-serve tier between Ultra and contact-sales Enterprise, built for embedders and high-volume builders. Everything in Ultra at roughly 5× the limits: 500,000 requests/day, 3,000/min burst, 10 WebSocket connections + 5 DEX-firehose connections, 30 webhooks, copy-trade 250 wallets across 100 rules, 100 coordination rules, 50 first-touch subscriptions, 125 price alerts, and a 500-slot wallet tracker.
  • The embed license. Business is the first tier licensed to display MadeOnSol data inside your own product to your end users (one product). The terms now spell out the data license per tier: below Business, usage is internal-only. Raw resale, redistribution, and white-label stay on Enterprise.
  • Available on every payment rail — one-off SOL/USDC, card (Stripe), and on-chain USDC auto-renew. Upgrade from /pricing or straight from the upgrade link in an Ultra 429 body.
Jul 7SDK

Verified wallet holdings in every SDK

API:

SDK+

API:

  • GET /api/v1/wallet/{address}/holdings (ULTRA) is now documented in the OpenAPI spec and shipped across all SDKs. It returns a wallet's chain-verified current holdings — its actual SPL + Token-2022 token accounts and SOL balance read live from chain, enriched with price, market cap, and name/symbol from our own data. Unlike /wallet/{address}/positions (trade-derived FIFO, transfer-blind), this is a true holdings census, and each holding carries transfer_delta = on-chain amount minus the trade-derived net position — a large positive delta flags tokens that arrived without a swap (airdrops, insider funding, wallet-hopping). 90s cache; cache hits are free.

SDKs:

  • The new holdings method ships across all 7 SDKs — madeonsol-x402 1.20.0 (npm), the bare TypeScript madeonsol 2.19.0, madeonsol 1.21.0 (PyPI), the Rust crate madeonsol 0.21.0, the MCP server mcp-server-madeonsol 1.18.0 (tool madeonsol_wallet_holdings), the Eliza plugin @madeonsol/plugin-madeonsol 1.17.0, and solana-agent-kit-plugin-madeonsol 1.17.0. Call walletHoldings(wallet) (TS) / wallet_holdings(wallet) (Python/Rust). Additive only, no breaking changes.
Jul 5Platform

Four new endpoints: pool map, early-buyer PnL, deployer history, supply-inflation risk

API:

Platform+

API:

  • New GET /api/v1/tokens/{mint}/pools (PRO+) — the per-venue liquidity map for a token. Every pool it trades in across pump.fun / PumpSwap / Raydium / Meteora / Orca, with each pool's liquidity_usd, last_price_sol, DEX and quote mint, whether it's live vs parked (is_active), plus a summary: total liquidity, pool/DEX counts, the primary (deepest) pool, and top_pool_share_pct (how concentrated liquidity is in one pool). GET /token/{mint} returns a single aggregate liquidity number — this shows where that liquidity actually sits and how fragmented it is.
  • GET /api/v1/tokens/{mint}/cap-table — enriched with exit/PnL. Each early buyer now carries realized_pnl_sol, total_sol_bought / total_sol_sold, first_sell_at, and still_holding. Turns the early-buyer list into a smart-money exhaustion read: did the early money profit, and has it already cashed out? Computed from confirmed on-chain trades.
  • New GET /api/v1/deployer-hunter/{wallet}/history (PRO+) — a deployer's daily reputation time-series: bonding_rate, recent_bond_rate, tier, avg_peak_mc and totals per day. Lets you answer "was this deployer elite at the time it launched token X?" — i.e. backtest deployer alerts without look-ahead bias, which the point-in-time GET /deployer-hunter/{wallet} can't.
  • Token risk: new supply_inflation factor. GET /api/v1/tokens/{mint}/risk now flags on-chain supply that has grown above its expected/launch supply (stealth mint / post-launch dilution), normalized by supply so it's decimals-agnostic and noise-filtered. A rug vector distinct from mint-authority — the authority can be revoked yet supply already have been inflated before.

All new/changed endpoints are PRO+ (cap-table stays field-gated across tiers). Full reference on the API docs.

Jul 4Platform

Bundle intelligence: how much of supply the bundle still holds

API:

Platform+

API:

  • New GET /api/v1/tokens/{mint}/bundle — bundle intelligence for a token. It resolves the token's bundle cohort — the same-slot "bundle" wallets that bought together (≥3 wallets buying in one slot = is_bundle) — and, the headline, how much of supply that cohort still holds. The bundle block returns wallet_count, bundle_kind (atomic_tx | same_slot | none), held_ratio, held_pct_of_supply (net tokens held ÷ supply, clamped 0–1 — the rug/insider read), fully_exited, buy_volume, and tokens_held. Crucially this is computed from confirmed on-chain trades (token_trades), not a pre-execution shred feed — it's the incumbents' headline "current held %" signal done the correct confirmed-data way, with bundle_kind atomicity added on top. Honest about its inputs: held_pct_of_supply is a swap-derived net proxy (clamped), tokens_held is that same net proxy rather than 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, same as buyer-quality / cap-table): BASIC/TRADER get the scalar bundle block only, PRO adds the top-10 wallets (flags only), and ULTRA returns the full cohort enriched with KOL/alpha identity (kol_name, win_rate, bot_confidence). Full reference on the API docs.

SDKs:

  • A new bundle-holdings method ships across all 7 SDKs — madeonsol-x402 1.19.0 (npm), the MCP server mcp-server-madeonsol 1.17.0 (tool madeonsol_token_bundle), the Eliza plugin @madeonsol/plugin-madeonsol 1.16.0, solana-agent-kit-plugin-madeonsol 1.16.0, madeonsol 1.20.0 (PyPI), the bare TypeScript madeonsol 2.18.0, and the Rust crate madeonsol 0.20.0. Additive only, no breaking changes.

Site:

  • The API docs now list and let you try /tokens/{mint}/bundle alongside cap-table and buyer-quality.
Jul 1Platform

Accurate PnL (cost-basis + unrealized) + bonk/bags coverage

API — PnL accuracy:

Platform+

API — PnL accuracy:

  • KOL leaderboard & wallet PnL are now cost-basis realized PnL, not net SOL flow. Before, a trader mid-accumulation — bought a lot, sold a little — showed a large "loss" because the full cost was charged against partial proceeds. Now only the cost of the sold portion counts, so /api/v1/kol/leaderboard, /api/v1/kol/{wallet}/pnl, and the wallet endpoints report realized PnL that reflects actual round-trips. Accumulators no longer read as losers, and the leaderboard ranks on true realized PnL.

  • Unrealized PnL on still-held positions. /api/v1/kol/{wallet}/pnl and the wallet endpoints now include unrealized_pnl_sol + total_pnl_sol — the mark-to-market value of tokens a wallet is still holding, priced from our own data, alongside realized. Held inventory is valued, not counted as a loss.

  • USDC/USDT-quoted trades are now captured. Swaps priced in USDC/USDT rather than SOL — a growing share on pump.fun & PumpSwap stable pairs — are now recorded and counted in PnL, volume, and firehose data instead of being dropped.

API — beyond pump.fun:

  • Wallet PnL, token flow, and cap-table now cover bonk (LetsBonk) & bags launchpad tokens, not just pump.fun — a wallet's bonk/bags trades now show up in /api/v1/wallet/{address}/pnl, /api/v1/tokens/{mint}/flow, and the cap-table.

  • Deployer-hunter now surfaces bonk deploys. GET /api/v1/deployer-hunter/{wallet} gains a launchpad_tokens field listing a deployer's bonk (Raydium LaunchLab) tokens from our own on-chain index, alongside the existing pump.fun pump_tokens.

  • Almost-bonded now covers bonk (LetsBonk). GET /api/v1/tokens/almost-bonded widened past pump.fun to include bonk/LetsBonk (Raydium LaunchLab) tokens approaching graduation, with live bonding-curve progress_pct computed from the LaunchLab curve. Each token now carries a launchpad field (pumpfun or launchlab) so you can tell the venue apart. Read straight from our firehose — no external API.

June 2026

23 ships
Jun 30Platform

Pay by card (Stripe) + EUR-canonical pricing

Payments:

Platform+

Payments:

  • Card payments are live. You can now subscribe to PRO or ULTRA with a credit or debit card via Stripe Checkout, right alongside the existing crypto rails — one-off USDC/SOL, or on-chain USDC auto-renew. Card is the default at checkout, renewals are automatic, and you can upgrade, downgrade, update your card, or cancel anytime from the Stripe billing portal (linked in the developer dashboard). Non-EU buyers are shown their local currency at checkout via Stripe Adaptive Pricing.

  • EUR is now the canonical price. Plans are billed in euro — PRO €43/mo (€430/yr), ULTRA €131/mo (€1,310/yr) — with the dollar figure shown as a live "≈ $49 / ≈ $149" reference that floats with the daily rate. The crypto rails price off the same fixed euro amount, converted to USDC/SOL at the day's rate, so every method quotes the same price. The checkout pay button shows what you'll actually send per rail (e.g. "~0.67 SOL (€43/mo)").

Site:

  • Pricing, checkout, the developer dashboard, blog, and SDK docs now show "€X (≈ $Y)" with card, USDC, and SOL all offered (card first). Product structured data and page metadata were updated to the euro prices.
Jun 29Platform

Self-serve WebSocket session management

API:

Platform+

API:

  • New GET /api/v1/stream/sessions (PRO/ULTRA) — list your live WebSocket sessions across both the event stream and the DEX firehose. Each entry carries its id, service, tier, subscribed channels, connected_at, remote_ip, and messages_sent. It reflects in-memory connection state, not historical logs, so every id it returns is one you can act on.

  • New DELETE /api/v1/stream/sessions/{id} (PRO/ULTRA) — force-close one of your own live sessions and release its connection slot immediately. This is the self-serve fix for a 4002 Connection limit reached lockout when a redeploy on your side (e.g. an old and new instance briefly running at once) leaves a half-open socket holding your slot — no need to email support or wait for the server-side reaper. The socket is closed with code 4002; you can only terminate sessions belonging to your own key.

Jun 27Platform

Almost-bonded discovery + trending/momentum sorts

API:

Platform+

API:

  • New GET /api/v1/tokens/almost-bonded (PRO/ULTRA) — pre-bond pump.fun tokens approaching graduation, so you can catch them before they bond. Each token carries its live bonding-curve progress_pct (from on-chain real_token_reserves depletion) and, uniquely, its velocity (velocity_pct_per_min = Δprogress/min) plus a linear eta_minutes projection — "95% and accelerating" ranks above "92% stalled". Enriched with deployer reputation (deployer_tier) so you can filter to elite/good deployers only. Filters: min_progress/max_progress (default 80–99.99% band), min_velocity_pct_per_min, max_age_minutes, deployer_tier, authority_revoked, min_liq. Sort by velocity_desc (default), progress_desc, or eta_asc. Self-hosted from our firehose — no external API.

  • Trending / momentum sorts on GET /api/v1/tokens (PRO/ULTRA). The token directory now accepts four new sort values — mc_change_5m_desc, mc_change_1h_desc, volume_1h_desc, and trending (recent volume × momentum) — turning it into a reputation-aware momentum board. Combine with deployer_tier and max_mev_share_pct to surface clean-volume movers from trusted deployers and screen out bot-driven wash-pump volume.

Jun 26Platform

Data-services hub for builders + in-article embed CTA

Content:

Platform+

Content:

  • New builder's hub: Solana Memecoin Data API for Builders. A pillar guide for teams embedding our data in a product — what the KOL-flow, deployer-reputation, coordination, and DEX-firehose layer actually is, the build-vs-buy math, the four ways to pull it in (REST, WebSocket, webhooks, MCP/SDKs), and when to white-label it on Enterprise. It anchors a B2B-embedder content cluster, interlinked with the gRPC streaming, Geyser-plugin, and self-hosting cost guides.

Site:

  • In-article "embed our data" CTA. Data-service blog posts now surface a compact data-services call-to-action partway through the article, not only in the footer band — so readers building on Solana data hit the Enterprise / white-label path before they finish reading, instead of scrolling past it at the end.
Jun 21API

Token trade-flow endpoint + deployer SOL balance on alerts

API:

API+

API:

  • New GET /api/v1/tokens/{mint}/flow?window=1h|24h (PRO/ULTRA) — a per-token trade-flow aggregate computed straight from the trade firehose, the "organic vs fake volume" read for a single mint. Returns unique_wallets, unique_buyers, unique_sellers, buy_count, sell_count, total_trades, buy_sol, sell_sol, net_sol, and trades_per_wallet. trades_per_wallet is a wash-trading proxy: a high trade count concentrated across very few wallets is the classic synthetic-volume tell, while a low ratio across many wallets reads as organic demand. Counts and flows only — no holder data. Self-hosted from our firehose, no external API.

  • deployer_sol_balance on deployer-hunter alerts. GET /api/v1/deployer-hunter/alerts items now carry deployer_sol_balance (number | null) — the deployer wallet's SOL balance captured at alert time. null for rows alerted before 2026-06-21. The field was already on the deployer:alert webhook payload; it's now on the REST feed too.

SDKs:

  • A new tokenFlow method ships across all 7 SDKs — madeonsol 2.15.0 (TypeScript), madeonsol-x402 1.16.0 (TS) and 1.17.0 (Python), the MCP server 1.14.0, the Eliza and Solana Agent Kit plugins 1.13.0, and the Rust crate madeonsol-rs 0.17.0 — and the deployer-alert types gain the deployer_sol_balance field. Additive only, no breaking changes.
Jun 21Platform

Call the API from the browser (CORS) + Enterprise tier

API:

Platform+

API:

  • CORS is now enabled on every /api/v1 endpoint. Browser and frontend apps — dashboards, widgets, in-app panels — can call the keyed API directly with their Authorization: Bearer token, no server-side proxy required. Preflight OPTIONS requests return immediately, and the Access-Control-Allow-* headers ride every response. Auth is Bearer-token (not cookies), so direct browser calls are safe.

Platform:

  • Enterprise tier. For tools, funds, and platforms embedding our data in production: an uptime SLA, dedicated rate limits beyond Ultra's 100k/day, white-label and redistribution rights, custom endpoints, and a priority support channel. See Pricing or email [email protected].

SDK (1.12.1):

  • Fixed copy-trade & alpha methods in the Eliza and Solana Agent Kit plugins. They were calling retired paths (/copy-trade/rules, /alpha/wallet/{w}) and 404ing; they now hit the live routes (/copytrade/subscriptions, /alpha/{w}). copyTradeCreate also takes the correct body — source_wallets[] + sizing_amount — instead of the old single-source_wallet shape.
Jun 20Platform

Canonical pricing across the API

Every token price we serve — on the /tokens endpoints, wallet PnL, positions, and the KOL feed — now comes straight from on-chain pool and bonding-curve reserves, the same sourc…

Platform+

Every token price we serve — on the /tokens endpoints, wallet PnL, positions, and the KOL feed — now comes straight from on-chain pool and bonding-curve reserves, the same source our market-cap engine trusts.

We retired the older trade-derived estimate, which could be thrown off by network fees, Jito tips, and rent on small trades, and we revived pricing for pre-graduation pump.fun tokens so brand-new launches get a real price instead of a gap. The result: roughly 98% of trade prices now land inside the minute's actual traded range, and the rare order-of-magnitude bad-price tail is gone.

Jun 19Security

x402 security hardening on keyless pay-per-call

A focused security pass on the keyless x402 surface — the path where agents and scripts pay per request with no API key.

Security+

A focused security pass on the keyless x402 surface — the path where agents and scripts pay per request with no API key.

  • Method precheck. Unsupported HTTP methods are rejected before any payment is requested, so you're never charged for a request that was never going to succeed.
  • Per-IP rate limiting. The keyless surface now enforces the same in-memory per-IP limits as the keyed API — a single caller can't hammer it.
  • Strictly read-only. The x402 path exposes data endpoints only; no state-changing route is reachable without a key.
  • Consistent validation. Every x402 endpoint validates mint and wallet inputs identically to the keyed /api/v1 routes, and the OpenAPI spec now matches actual behavior — including string-or-array batch mints and Solana path-param examples.
Jun 17Platform

Upgrade-aware 403s + one-click first call

Two onboarding upgrades: the API now tells you exactly how to unlock a gated endpoint, and the dashboard runs your first call for you.

Platform+

Two onboarding upgrades: the API now tells you exactly how to unlock a gated endpoint, and the dashboard runs your first call for you.

API:

  • Tier-gated endpoints now return an actionable 403. When a free or under-tier key calls a PRO/ULTRA endpoint, the response is no longer a bare error string — it carries an upgrade block with the required_tier, monthly price, the new daily/burst limits, a one-line note of what unlocks, and a direct upgrade_url. SDK clients (and humans curling) see the path out inline instead of bouncing to the docs. Applied across every tier-gated route — token risk, cap tables, wallet PnL/positions, sniper feeds, copy-trade, KOL coordination, and more.

Site:

  • "Run your first call" on the /developer dashboard — generate a key and fire a real request against live data in one click, no code or curl needed. Returning key-holders get the same one-click sample call.
  • The Quick Start snippet now pre-fills your actual key, so it's copy-paste-run.
  • API pricing CTAs added across the Intelligence pages (KOL Tracker, Deployer Hunter, Wallet Scanner, Token Lookup, Scout Leaderboard, Daily Alpha) — a reminder that the free tier is 200 calls/day, no card.
Jun 15Platform

Token Risk Score: a rug-risk number you can audit

A single, transparent safety score for any token — with the per-factor breakdown that produced it, not just an opaque number.

Platform+

A single, transparent safety score for any token — with the per-factor breakdown that produced it, not just an opaque number.

API:

  • New GET /api/v1/tokens/{mint}/risk (PRO/ULTRA) — a 0–100 rug-risk / safety score with a band (safe / caution / danger) and an auditable factors[] array. Each factor carries its own status, points, and detail — mint/freeze authority, liquidity depth & thinness, Token-2022 transfer fee, LP burn, bundled/sniped open, deployer track record, KOL distribution, and blacklist. Unlike a black-box score, you can see exactly why a token landed where it did. The response also returns the raw inputs and a score_version. Composed from the same data layer as GET /token/{mint}, so there's no extra latency. Full reference on /api-docs#tools.

SDKs:

  • madeonsol-x402 1.13.0 · madeonsol (PyPI) 1.14.0 · mcp-server-madeonsol 1.12.0 · @madeonsol/plugin-madeonsol 1.11.0 · solana-agent-kit-plugin 1.11.0 — all gain a token-risk method/tool. Additive only, no breaking changes.
  • Bare TypeScript SDK madeonsol 2.13.0 and the Rust SDK madeonsol 0.14.0 — also updated with the token-risk method.

Site:

  • Token Risk Score added to the pricing/feature cards, the /developer page, and the API docs.
Jun 14Platform

Liquidity depth, launch cohort, and deployer-tier filters on /tokens

Four new enrichment fields and three new filters — all computed from data we already hold, no new pipeline.

Platform+

Four new enrichment fields and three new filters — all computed from data we already hold, no new pipeline.

New fields on /token/{mint} and /token/batch:

  • liquidity_to_mc_ratio — liquidity_usd ÷ market_cap. A structural depth gauge: low ratios flag thin pools where a single exit can crater price. Useful as a risk screen before sizing a position.
  • launch_cohort_sol — total SOL committed by the token's first-20 buyers. A proxy for early conviction: high cohort SOL on a no-name deployer is a signal worth watching; high SOL with a dump-factory deployer is a counter-signal.
  • launch_cohort_size — how many of the first-20 buyer slots are filled (0–20). Low size on an older token typically means it was abandoned early.

New fields on /tokens list response: liquidity_to_mc_ratio and deployer_tier are now returned per token — screen the whole list without a /token/{mint} roundtrip.

New filters on /tokens:

  • min_liq_mc_ratio / max_liq_mc_ratio — keep only tokens within a liquidity-depth band.
  • deployer_tier — filter to tokens from a specific deployer reputation tier (elite | good | moderate | rising | cold | unranked). Combine with min_liq_mc_ratio=0.05 to find elite-deployer tokens that still have meaningful liquidity.

New fields on /kol/leaderboard: median_hold_minutes_30d and percentile_early_entry_30d are now returned per KOL, surfacing hold-duration and timing discipline without a separate profile call.

All fields are additive — no breaking changes.

Jun 14SDK

SDK v1.12.0: enrichment fields + new filters

All seven SDKs updated with today's API additions. Additive only, no breaking changes.

SDK+

All seven SDKs updated with today's API additions. Additive only, no breaking changes.

madeonsol 2.12.0 · madeonsol-x402 1.12.0 · madeonsol-python 1.13.0 · madeonsol-rs 0.13.0 · mcp-server-madeonsol 1.11.0 · @madeonsol/plugin-madeonsol 1.10.0 · solana-agent-kit-plugin 1.10.1

  • TypeScript / x402 — TokenResponseBody gains liquidity_to_mc_ratio, launch_cohort_sol, launch_cohort_size; TokenListParams gains min_liq_mc_ratio, max_liq_mc_ratio, deployer_tier; KolLeaderboardEntry gains median_hold_minutes_30d, percentile_early_entry_30d; new getSignalPerformance(name) method.
  • Python — tokens_list() now accepts min_liq_mc_ratio, max_liq_mc_ratio, and deployer_tier keyword args.
  • Rust — all three structs (TokenResponseBody, TokensListParams, KolLeaderboardEntry) updated with typed fields.
  • MCP — madeonsol_tokens_list tool gains the three new filter params; new madeonsol_signal_performance tool added.
  • Plugins — getTokensList() / tokensList() extended with the three new filter params.
Jun 11Platform

Data quality you can see

We don't just claim the data's clean — we continuously verify it and show you the result. /api-status now reports live data-quality SLOs alongside service uptime:

Platform+

We don't just claim the data's clean — we continuously verify it and show you the result. /api-status now reports live data-quality SLOs alongside service uptime:

  • On-chain accuracy — a rolling sample of served tokens is re-checked against on-chain supply (FDV ≡ price × supply). A stale-supply or phantom-price market cap is caught within minutes, not on your bug report.
  • Field correctness — every served field on the core data endpoints is validated against its contract (never-null where it shouldn't be, values in range) on a fast cadence.
  • Quality drift — per-field null-rates are tracked against a trailing baseline, so a slow degradation surfaces before it crosses a hard line.
  • Serve-time integrity — the exact bytes we send you are audited the instant they leave the API.

Each is shown as adherence over a trailing window with its sample count — honest, on-chain-grounded (no external aggregators), and self-correcting as history accrues. The same checks page us internally the moment something slips.

Also for developers: subscribing to an unknown or tier-gated WebSocket channel now returns a channels_rejected warning naming what was dropped and why — instead of silently delivering nothing. (Tried dex:trades and got silence? The DEX firehose is a separate ULTRA endpoint — the warning now points you there.)

Jun 9Platform

Signal Scorecard: every signal, backtested live

You shouldn't have to trust a signal on faith. Every signal we serve now self-reports how well it actually works — measured out-of-sample, refreshed daily, and shown openly.

Platform+

You shouldn't have to trust a signal on faith. Every signal we serve now self-reports how well it actually works — measured out-of-sample, refreshed daily, and shown openly.

  • Public Signal Scorecard — per-signal hit rate by bucket, lift over base, and sample size. Starts with dump-cluster detection and deployer runner-rate; more to come.
  • Inline on tokens/{mint}/buyer-quality — responses now include a signal_stats block so a raw value explains itself: dump_cluster_count=17 comes back as "98% of such tokens dumped vs 75% base (1.3× lift), n=190, 14d out-of-sample."
  • New GET /api/v1/signals/{name}/performance — the full backtest as JSON (dump_cluster_count | runner_rate), so bots can weight signals programmatically instead of guessing. ?history=true returns the per-day series for drift.

How it stays honest: rolling train/test split (signals graded only on data they weren't built from — no lookahead), a ≥15 early-buyer filter so sparse tokens can't inflate the numbers, and peak-timing labels (dump <15 min, runner ≥60 min). The numbers will move with the market — that's the point.

Also shipped:

  • WS deployer:bond now carries runner_rate, labeled_tokens, and recent_bond_rate (previously only on deployer:alert) — read deployer quality straight off a graduation event, no REST round-trip.
  • Token market caps — fixed a class of stale-supply phantom MCs (idle tokens whose on-chain supply had drifted after we stopped tracking them). /tokens and /token/{mint} now reconcile supply against the live chain daily, so a dead token can't report an impossible market cap.
Jun 8Platform

Deployer runner-rate on alerts, sniper deploys & streams

Every deployer signal now carries the deployer's runner-rate — the fraction of their tokens (with a real first-20 buyer cohort) that ran (peak ≥60 min after deploy) vs dumped (p…

Platform+

Every deployer signal now carries the deployer's runner-rate — the fraction of their tokens (with a real first-20 buyer cohort) that ran (peak ≥60 min after deploy) vs dumped (peak under 15 min). It's a validated as-of read on the next launch: out-of-sample across 8,635 auto-labeled tokens it moved P(runner) monotonically from 10.5% (deployers who never produce runners) to 75.5% (deployers who consistently do), against a 27.6% base — and it adds signal within tier, separating a 0%-runner "elite" pump-and-dump factory from a genuine builder the tier alone scores the same.

New fields (additive, no breaking changes):

  • deployer-hunter/alerts + deployer-hunter/{wallet} — runner_rate, labeled_tokens (the confidence denominator — gate on ≥3), and avg_time_to_bond_minutes.
  • sniper/recent + WS sniper:deploys — deployer_runner_rate, deployer_labeled_tokens, snapshotted onto the pre-confirmation deploy.
  • WS deployer:alert / deployer:bond — runner_rate, labeled_tokens.

Refreshed every 6 hours. One counter-intuitive note from the validation: fast bonders skew dump, not runner — a deployer who bonds in under 30 min runs 12% of the time vs 40% for those taking 6 h+. Slow bond = organic demand.

Also fixed: WS min_mc_usd / max_mc_usd band filtering now works on deployer:alert, deployer:bond and token:graduations. It previously matched the field on none of those channels and silently dropped every event when a band was set.

Jun 7SDK

SDK v1.11.0: graduation events + dump-cluster types

All seven SDKs updated for today's API additions — additive only, no breaking changes:

SDK+

All seven SDKs updated for today's API additions — additive only, no breaking changes:

  • TypeScript madeonsol-x402 1.11.0 and bare madeonsol 2.11.0 — token:graduations added to the typed channel union (no more casting to subscribe), new GraduationEvent payload interface, buyer-quality breakdown typed with dump_cluster_count + recycled_early_buyer_count.
  • Rust madeonsol 0.12.0 — same two breakdown fields on AlphaBuyerQualityBreakdown (previously serde dropped them silently) + GraduationEvent struct.
  • Python madeonsol-x402 1.12.0 — channel/event registries updated; string subscribe already worked, docs now match.
  • mcp-server-madeonsol 1.10.3 — buyer-quality tool description corrected (full breakdown is returned on all tiers, not PRO+) and now mentions the dump-cluster fields.
  • @madeonsol/plugin-madeonsol and solana-agent-kit-plugin-madeonsol 1.9.2 — README documentation for both features (payloads pass through unchanged).
Jun 7Platform

Real-time graduation events

Pump.fun graduations (bonding curve complete → PumpSwap migration) are now pushed in real time, two ways:

Platform+

Pump.fun graduations (bonding curve complete → PumpSwap migration) are now pushed in real time, two ways:

token:graduations channel on the WebSocket stream (PRO + ULTRA) — every graduation, whether or not the deployer is tracked. This closes the gap left by deployer:bond, which only covers tracked deployers. Payload carries token_mint, name/symbol, time_to_bond_minutes, deployer_wallet, deployer_tier (unranked when unknown), market_cap_usd at bond, and bonded_at. The deployer_tier array filter applies if you only want graded deployers.

In-band dex:graduations frames on the DEX firehose (ULTRA) — subscriptions that scope mints via token_mint(s) receive the graduation for those mints on the same connection and sub_id as the trade flow. If you're watching an open position, the bond arrives in the stream you're already reading — no separate connection, no polling recent-bonds.

Detection rides the hardened three-layer bond pipeline (instruction parser on dual-region gRPC, pool-state confirmation, curve-confirm reconciler) — the same source of truth as deployer-hunter stats. Events fire from the real-time paths only, so a graduation frame is always seconds-fresh, never a stale backfill.

Jun 7Platform

Buyer-quality: dump-cluster wallet detection

Two new fields in the buyer-quality breakdown (single + batch endpoints, all tiers, no score impact):

Platform+

Two new fields in the buyer-quality breakdown (single + batch endpoints, all tiers, no score impact):

dump_cluster_count — how many of the token's first-20 buyers are on a rolling dump-cluster list: wallets whose recent first-20 appearances (5+) are exclusively on tokens that peaked within 15 minutes of deploy. This shipped only after surviving out-of-sample validation on 8,300+ auto-labeled launches with a strict temporal split: 3+ such wallets in a cohort predicted a sub-15-minute peak 94% of the time (vs 61% base rate), rising to 99% at 5+. Controls confirmed it's the composition that matters — raw sniper-wallet activity in a cohort predicts nothing (61%, exactly base).

recycled_early_buyer_count — first-20 buyers with 5+ recent first-20 appearances of any kind. On its own it's noise, but the combination is informative in both directions: a heavily recycled cohort with dump_cluster_count 0 historically leaned runner (39% dump — 22 points below base).

The list is rebuilt daily over a trailing 42-day window — validation showed wallet churn kills any static list within ~2 weeks, so the ensemble rolls. Individual wallets are never exposed.

Jun 7API

DEX firehose: replay buffer deepened 12×

replay: N on a firehose subscription backfills the N most recent trades matching your filters from a server-side buffer — it is not connection-scoped, so it covers trades from b…

API+

replay: N on a firehose subscription backfills the N most recent trades matching your filters from a server-side buffer — it is not connection-scoped, so it covers trades from before your connection existed. Until today that buffer held only ~30 seconds of firehose history (it was sized for reconnect gaps); it now holds roughly 5–6 minutes at typical volume (2–3 minutes at peak). Subscribing to a mint at alert time with replay: 500 now recovers the in-flight trade history, not just the last half-minute.

Semantics worth knowing (now also in the API docs): replayed trades arrive newest-first flagged "replay": true, followed by a replay_done frame — sort by block_time client-side. The per-subscription cap stays at 500 trades; async filters (token age, market cap, deployer tier) are skipped on replay since they evaluate against live state. No client or SDK changes required.

Jun 6Platform

WebSocket streaming overhaul: no more silent connections

A delivery audit found that most streaming customers were getting stuck in the same invisible traps — connected but never receiving events. All of them are now dismantled:

Platform+

A delivery audit found that most streaming customers were getting stuck in the same invisible traps — connected but never receiving events. All of them are now dismantled:

The server tells you when you're not subscribed. A WebSocket connection delivers nothing until you send {"type":"subscribe","channels":[...]} — previously, getting that wrong meant silence with no feedback. Now the connected frame includes a subscribe example and the full channel list, and if no channels are active after 10 seconds the server sends a hint frame with exactly what to send. Same on the DEX firehose.

Token lifecycle is no longer hostile to long-running clients.

  • POST /v1/stream/token is idempotent while your current token has more than 6 hours left — the same token is returned, so multi-process clients no longer invalidate each other's tokens on every mint.
  • When a token does rotate, the previous token stays valid for 60 seconds — in-flight reconnects survive the swap.
  • Expiring tokens are now rotated server-side and pushed in-band as a {"type":"token_refresh"} frame. Healthy connections are never hard-closed at the 24-hour mark anymore.
  • The mint endpoint got its own rate bucket (10/min), exempt from the shared REST quota — heavy REST usage can no longer lock you out of minting a streaming token.

Webhook owners are notified when their endpoint breaks. Ten consecutive failed deliveries still auto-pause a webhook, but now the owner gets an email explaining what failed and how to resume — previously the pause was silent.

Coordination alert latency, measured: in a live end-to-end test today, a coordination signal reached the subscriber's WebSocket 570ms after the triggering on-chain trade (rule create → KOL convergence → push).

Subscription housekeeping: when a paid plan lapses, copy-trade and coordination rules are now deactivated alongside webhooks and streaming tokens (previously they kept firing into the void), and they re-enable from the dashboard after renewal.

Jun 5SDK

SDK metadata patch release

Housekeeping release across four packages — no API surface changes:

SDK+

Housekeeping release across four packages — no API surface changes:

  • Pricing tables corrected in the package READMEs (they showed retired tiers; the real lineup is BASIC free / PRO $49/mo / ULTRA $149/mo, annual two-months-free): @madeonsol/plugin-madeonsol 1.9.1, solana-agent-kit-plugin-madeonsol 1.9.1, mcp-server-madeonsol 1.10.2, madeonsol-x402 (PyPI) 1.11.1.
  • The ElizaOS plugin's npm page now links to its GitHub repository (missing repository field added).
  • GitHub mirror repos synced + re-topiced for discoverability.
Jun 1SDK

SDKs: managed real-time streaming client

One-line WebSocket streaming across all SDKs. Until now every SDK handed you a token and left you to hand-roll the connection — open the socket, refresh the 24h token, reconnect…

SDK+

One-line WebSocket streaming across all SDKs. Until now every SDK handed you a token and left you to hand-roll the connection — open the socket, refresh the 24h token, reconnect on drop, parse heartbeats, type the events. The new managed client does all of it: client.stream() (TypeScript madeonsol-x402 1.10.0 / Python madeonsol-x402 1.11.0) and client.stream.connect() (bare madeonsol 2.10.0) return a stream you just subscribe-and-listen on, with auto-reconnect (backoff + jitter), token auto-refresh, heartbeat liveness, and typed events for all eight channels (KOL trades, coordination, first-touches, deployer alerts, wallet-tracker, copy-trade, price alerts, sniper deploys).

const stream = client.stream();               // x402
stream.on("kol:trade", (t) => console.log(t.token_symbol, t.action));
stream.subscribe(["kol:trades", "deployer:alerts"]);

The TypeScript clients use the native WebSocket on Node 22+ (with a lazy ws fallback) and zero required dependencies; the Python client is asyncio-based behind the optional madeonsol-x402[stream] extra.

Bare madeonsol SDK reaches full parity. Added the copy-trade namespace (client.copytrade — rules CRUD + signal history) that was the last gap versus madeonsol-x402.

Jun 1Platform

Public token pages, on-chain naming, reliability fixes

New: public token pages at /token/[mint]. Every token now has a shareable, AI-citable page — live price, market cap, liquidity, rug-safety checks (mint/freeze authority, LP burn…

Platform+

New: public token pages at /token/[mint]. Every token now has a shareable, AI-citable page — live price, market cap, liquidity, rug-safety checks (mint/freeze authority, LP burn, Token-2022 transfer fees), deployer reputation, and which tracked KOL wallets are buying or selling. Reachable from a new Token Lookup entry in the Intelligence menu (paste any mint). Pages carry FAQ + breadcrumb structured data; only tokens with real substance (named, liquid, or with KOL activity) are indexed — the long tail stays noindex to protect crawl budget.

On-chain token naming. Names/symbols for non-pump tokens (Raydium/Meteora/established SPL) are now resolved on-chain — Metaplex metadata accounts and the Token-2022 metadata extension — and cached. mc-tracker resolves each new token at first sighting (off the price hot path), so the highest-search-demand tokens get named and indexed automatically.

Deployer Hunter: false "Unknown" deploy alerts fixed. A parser bug was mis-reading ordinary swaps (which log Instruction: CreateTokenAccount/CreateIdempotent) as brand-new deploys, surfacing already-bonded tokens — some over a year old — as fresh "Unknown" launches. Create detection is now anchored to genuine pump-program token creates (with InitializeMint2 proof), and the auto-discovery that had widened the listener to the whole DEX firehose was reset to the real pump programs. Existing false alerts were cleaned up and affected deployer tiers reconciled.

Universal Wallet API resilience. /v1/wallet/{address} no longer returns a 500 on very high-trade-count wallets — when the 90-day aggregation exceeds the query timeout it degrades gracefully (core flags returned with an enrichment_unavailable flag) and the response is briefly cached, so repeat polls on the same heavy wallet are instant instead of timing out.

May 2026

23 ships
May 31Security

Content clusters, sitemap fix, security hardening

15 new blog posts across three content clusters. Trading-bot comparisons (Bloom vs BullX, Bloom vs Trojan, Photon vs Axiom, Banana Gun vs Trojan) and tool reviews (Bullpen, MevX…

Security+

15 new blog posts across three content clusters. Trading-bot comparisons (Bloom vs BullX, Bloom vs Trojan, Photon vs Axiom, Banana Gun vs Trojan) and tool reviews (Bullpen, MevX, TradeWiz, Cypherock X1, SafePal), plus a KOL/pump.fun guide set: filtering bot wallets from a KOL list, finding pump.fun tokens before KOLs tweet, why most pump.fun tokens die in the first hour, scoring a new token in 60 seconds, free vs paid KOL trackers, and Cielo vs Birdeye vs Solscan. All wired into hub/spoke internal links.

Sitemap fix — every blog post now indexable. The sitemap was only emitting the blog index page, not the ~360 individual posts (a stale-build artifact). Added hourly revalidation so all published posts now surface to search engines and AI crawlers. IndexNow notified on each new post.

Security: referral-earnings function locked down. The increment_referral_earnings Postgres function was callable by the anon/authenticated roles via PostgREST. Execute is now revoked from everything except the server-side service role (migration 158). No abuse observed — closed proactively after a health check flagged it.

Affiliate click attribution. Blog affiliate links now route through tracked /go/[slug]?source=blog/... redirects for per-post attribution, and admin clicks are excluded from affiliate stats to prevent self-click inflation.

Product structured-data fixes. Resolved Google Search Console warnings on tool pages (missing image and availability fields in the Product/Offer JSON-LD).

May 30Platform

Deployer Hunter: reliable bond detection (MigrateV2 fix)

Fixed: ~75% of pump.fun graduations were being missed. pump.fun renamed its on-chain graduation instruction (Migrate → MigrateV2), and our parser's exact-match guard silently dr…

Platform+

Fixed: ~75% of pump.fun graduations were being missed. pump.fun renamed its on-chain graduation instruction (Migrate → MigrateV2), and our parser's exact-match guard silently dropped every V2 migration — so most "bonded" events never fired. Detection now recognizes Migrate, MigrateV2, and future variants, restoring real-time bonded alerts across webhook, WebSocket, and Telegram. Verified live (a graduation recorded ~1 minute after it landed on-chain).

Authoritative catch-up reconciler. A new 5-minute backstop reconciles recently-deployed tokens against the bonding-curve complete flag on-chain — the single source of truth — recovering any graduation the live gRPC stream missed during reconnects, with zero false positives. Idempotent and silent (no duplicate or stale alerts).

Every graduation now counts, including unknown deployers. Detection is keyed on the graduation itself, not on whether we already track the deployer, so bonds from previously-unseen wallets are now recorded. This corrected lifetime bond stats network-wide and promoted ~390 deployers into tracked tiers (12,207 → 12,596).

May 29Platform

Sniper Alerts now on Pro (curated)

Sniper Alerts come to PRO. The pre-confirm pump.fun deploy feed — previously ULTRA-exclusive — is now available on PRO, curated to elite + good-tier deployers (the high-signal l…

Platform+

Sniper Alerts come to PRO. The pre-confirm pump.fun deploy feed — previously ULTRA-exclusive — is now available on PRO, curated to elite + good-tier deployers (the high-signal launches). ULTRA keeps the full firehose: every deployer tier, the all scope, custom watchlists, and the /v1/sniper/by-deployer/{wallet} audit feed.

The curation runs at delivery time across all three channels (webhook, WebSocket, Telegram), so it applies consistently whether you consume sniper:deploy webhooks, the sniper:deploys WS channel, /alert sniper in Telegram, or the GET /v1/sniper/recent read API. Same pre-confirm head start on both tiers.

Custom deployer watchlist (ULTRA). New GET/POST /v1/sniper/watchlist + DELETE /v1/sniper/watchlist/{wallet} (up to 50 deployers). Turn on "watchlist" scope to receive deploys from only the deployers you track, regardless of tier — works across the read API (?watchlist=true), webhook + WebSocket (sniper_scope: "watchlist"), and Telegram (/alert sniper watchlist). One source of truth across every channel.

Head-start instrumentation. We now reconcile each deshred detection against the confirmed stream and record confirmed_at on sniper_deploys, giving a measured per-deploy head start (currently ~415ms median / ~518ms p90 in production).

May 28Platform

Sniper Alerts (Ultra): pre-confirm pump.fun deploys

New ULTRA feature. Pre-confirmation pump.fun deploy alerts. New token launches surface in the feed before they confirm on-chain — a head start measured in production against our…

Platform+

New ULTRA feature. Pre-confirmation pump.fun deploy alerts. New token launches surface in the feed before they confirm on-chain — a head start measured in production against our existing CONFIRMED-stream deployer alerts, reconciled per deploy and published live on /benchmarks. (Measured 2026-09-20: median ~290 ms over 37,957 reconciled deploys in 24 h.) Delivery on every channel: webhook (sniper:deploy event), WebSocket (sniper:deploys), and Telegram (/alert sniper elite,good). ULTRA-tier exclusive.

Payload. Each alert includes mint, deployer wallet, signature, slot, plus a snapshot of the deployer's reputation (tier, lifetime bond rate, last-10 outcome bitmap). Pre-execution detection — no balances, logs, or compute info in the payload. Honest caveat: ~1-3% of detected deploys can abandon before chain settlement; payloads include confidence: "deshred" so consumers can treat the alert as "buy intent observed", not a guaranteed deploy.

Read API (Ultra). Two new endpoints for backtesting and post-hoc auditing:

  • GET /v1/sniper/recent — paginated deploy feed with filters: since, deployer_tier, min_bond_rate
  • GET /v1/sniper/by-deployer/{wallet} — deploys filtered to a specific deployer wallet

Telegram. New /alert sniper command in @MadeOnSolAlphaBot. Scope options: elite, elite,good, all, or off. ULTRA-tier check enforced at the command level.

Operator playbook. Full sniper guide added to /developer (under the Sniper spotlight card): pre-built tx templates, priority fees + Jito tip sizing, low-latency infra placement, deployer reputation filtering, buy params, exit triggers, and realistic latency budgets. The head start only converts to fills if your stack is set up to execute inside it.

May 26Platform

Bond sweep, hot-token auto-poster, deploy validation, 5 blog posts

Bond detection sweep. mc-tracker now runs a 2-minute periodic sweep that catches PumpSwap graduations the gRPC stream missed. Previously, missed bonds were only detected on mc-t…

Platform+

Bond detection sweep. mc-tracker now runs a 2-minute periodic sweep that catches PumpSwap graduations the gRPC stream missed. Previously, missed bonds were only detected on mc-tracker restart — now max detection delay is 2 minutes. Deployer-listener also enriches missing token metadata from pump.fun API before creating bond alerts.

Hot-token auto-poster. New X post type: every 4 hours, finds the token with the most KOL buyers in the last 30 minutes and posts with full enrichments — live MC, net SOL flow, token age, deployer tier + bond rate, buy/sell sentiment signal, and up to 5 KOL handles tagged. Repeat KOL detection highlights wallets that appeared in the previous hot pick.

Sentiment signals on X posts. Hot-token posts include a plain-language sentiment label based on KOL buy/sell ratio: "Strong accumulation", "Accumulating", "Leaning bullish", "Mixed signals", or "KOLs exiting".

Deploy validation hardened. Zero-downtime deploy script now runs deep checks before swapping nginx: API ping, status endpoint, static assets, and blog content. Failed validation aborts the swap and keeps the old slot running.

Resend webhook improvements. Bounce handler now correctly tracks all bounced addresses. Click tracking enabled for outbound emails.

5 new blog posts. What Is a Solana API, Light Terminal review, gRPC pipeline deep dive, deployer intelligence scoring, signal caller evaluation guide.

New tool. Light Terminal added to directory — social trading terminal with strategy marketplace, creator leaderboard, and automated limit orders on Solana.

May 25Platform

v1.9.0: Price alerts, wallet scanner enrichments, 5 new endpoints

Price Alert System — Sub-second token MC dip/recovery alerts. Set a drop % threshold on any tracked token; get notified via webhook or WebSocket when MC drops below baseline. Op…

Platform+

Price Alert System — Sub-second token MC dip/recovery alerts. 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 alerts, ULTRA: 25. New API: 6 CRUD + events endpoints. New WS channel: price_alert:events. New TG command: /pricealert.

5 New API Endpoints:

  • GET /kol/scouts/leaderboard — Scout leaderboard: top KOLs ranked by scout score and swarm attraction (ULTRA)
  • GET /tokens/{mint}/kol-consensus — KOL buy/sell consensus on a token with exit rate and median entry MC (PRO+)
  • GET /tokens/{mint}/peak-history — ATH market cap history with MC at bond and post-bond snapshots (PRO+)
  • GET /kol/coordination/history — Historical coordination alert fires (ULTRA)
  • GET /deployer-hunter/{wallet}/trajectory?include=daily_snapshots — Daily tier/bonding snapshots (extended)

Wallet Scanner Enrichments:

  • Win rate, ROI, best/worst trade, AI-classified verdict ("Degen flipper", "Smart money", etc.)
  • Biggest miss: scans all round-trip tokens, calculates missed SOL profit using pump.fun ATH
  • Ticker symbols resolved via pump.fun API (was showing contract addresses)
  • ATH market cap per token from pump.fun (was showing misleading current MC)
  • All enrichments available via REST API (derived block on /wallet/{address}) and Telegram /wallet

SDK v1.9.0 — All 7 packages updated: TypeScript 2.8.0, Rust 0.10.0, x402-TS/Python/MCP/ElizaOS/SAK all 1.9.0.

May 23Platform

Bond detection fix, 7 blog posts, 11 MCP servers, ad placements, new tools

Deployer Hunter bond detection rebuilt. 96%+ of bonds were being missed. New pipeline: mc-tracker emits pg_notify('pumpswap_bond') on graduation → deployer-listener resolves in …

Platform+

Deployer Hunter bond detection rebuilt. 96%+ of bonds were being missed. New pipeline: mc-tracker emits pg_notify('pumpswap_bond') on graduation → deployer-listener resolves in near real-time. Zero extra gRPC bandwidth. 436 historical bonds backfilled.

7 new blog posts. CoinTracking vs CoinLedger vs Blockpit, How to Buy SOL on Binance/MEXC, Bitsgap review, CoinStats review, Chainstack RPC review, Sol Trading Bot review, MEXC vs Binance vs Bybit comparison.

11 new MCP servers added to directory (21 total): Phantom, Vybe Network, Flipside, Jupiter, Crossmint, DexScreener, OpenSVM, Memecoin Observatory, Rug Check, PumpSwap, Magic Eden.

Banner advertising system. 5 ad placements across the site (homepage, /tools, /best/[category], KOL Tracker, Deployer Hunter) with "Your project here" placeholders linking to /advertise. Pricing from $75-$150/mo, manually approved via email.

New tools. Monkey Tools, CoinStats API, NordVPN, Surfshark, ProtonVPN, Cryptohopper added to directory.

Other. Promo banner system (CoinStats 10% off). Wallet scan counter on /wallet. Telegram page redesigned. Re-engagement emails sent to 4 silent PRO subscribers.

May 21Platform

v1.8.1 patch: Wallet Scanner web page + 4 API enrichments + TG `/wallet`

Three additive surfaces shipped on top of yesterday's v1.8.0 wallet endpoints:

Platform+

Three additive surfaces shipped on top of yesterday's v1.8.0 wallet endpoints:

1. Wallet Scanner web page. New /wallet search page under Intelligence in the navbar — paste any Solana address, get the same KOL/Deployer/Alpha flag check plus the new enrichment block in one render. Free, no signup, unlimited scans. The results page (/wallet/{address}) is non-indexed but freely linkable, so the page works as a shareable lookup for tippers, scouts, and the curious.

2. Four API enrichments on /api/v1/wallet/{address}. Additive fields, zero breaking changes:

  • top_tokens[] — most-traded tokens in the 90d window with realized PnL per token, plus current MC and peak MC (cross-joined with deployer_tokens for pump.fun launches).
  • trading_style — average trade size (SOL), sniper rate (% trades placed in the first 10 buyers of a token), round-trip rate (% tokens with both buys and sells), median hold minutes, dominant action.
  • deployer_breakdown — tier distribution of pump.fun deployers this wallet has bought from (ELITE / GOOD / RISING / MODERATE / COLD / unranked). Useful for spotting alpha-buyers vs random degens.
  • recent_trades[] — last 10 trades regardless of window with token symbols joined in.

All four are nullable so old SDK consumers ignoring them keep working. Backed by 4 new STABLE SECURITY DEFINER SQL helpers (migration 150).

3. Telegram /wallet command in @MadeOnSolAlphaBot. Same flag-set, light 7-day stats, deeplink to the web profile. Free 3 scans/day per chat, paid tiers unlimited. Rate-limited via the existing rate_limit_buckets (key tg-wallet:{chat_id}).

SDK propagation: all 7 packages bumped to v1.8.1 with the new response fields in the type definitions. No method-signature changes.

madeonsol                          2.7.0  →  2.7.1   (bare TypeScript)
madeonsol-x402                     1.8.0  →  1.8.1   (npm)
madeonsol-x402                     1.8.0  →  1.8.1   (PyPI)
mcp-server-madeonsol               1.8.0  →  1.8.1
@madeonsol/plugin-madeonsol        1.8.0  →  1.8.1   (Eliza)
solana-agent-kit-plugin-madeonsol  1.8.0  →  1.8.1
madeonsol (crates.io)              0.9.0  →  0.9.1   (Rust)

Bonus: stale middleware redirect /wallet → /best/wallets removed (was from a pre-scanner time when the path didn't exist — 113 GSC impressions that previously went to the listicle now land on the real scanner).

May 20SDK

SDK v1.8.0 release: wallet endpoints in all 7 packages

All 7 official SDKs ship the new Universal Wallet API surface — same shape across TypeScript, Python, Rust, MCP server, ElizaOS plugin, and Solana Agent Kit plugin.

SDK+

All 7 official SDKs ship the new Universal Wallet API surface — same shape across TypeScript, Python, Rust, MCP server, ElizaOS plugin, and Solana Agent Kit plugin.

madeonsol                          2.6.3  →  2.7.0   (bare TypeScript)
madeonsol-x402                     1.7.3  →  1.8.0   (npm)
madeonsol-x402                     1.7.3  →  1.8.0   (PyPI — pip install madeonsol-x402)
mcp-server-madeonsol               1.7.4  →  1.8.0
@madeonsol/plugin-madeonsol        1.7.3  →  1.8.0   (Eliza)
solana-agent-kit-plugin-madeonsol  1.7.3  →  1.8.0
madeonsol (crates.io)              0.8.2  →  0.9.0   (Rust)

Each SDK now exposes 4 new typed methods: wallet.stats(address), wallet.pnl(address), wallet.positions(address), wallet.trades(address, params?) (naming varies slightly per language convention). Full type definitions for every response shape — WalletStats, WalletPnl, WalletOpenPosition, WalletClosedPosition, WalletTrade, etc. — exported from each package so SDK consumers get autocomplete and compile-time validation.

The endpoints themselves shipped separately (see the entry below) — this release is the SDK propagation pass. /api/x402/wallet/* mirrors are wired into the x402 SDKs at the same prices ($0.005 / $0.02 / $0.01 / $0.005). OpenAPI spec bumped to v1.3.0 with full schemas for every wallet endpoint, so downstream code generators stay in sync.

Test status: 221 cases passed / 0 failed across REST matrix (200), WS events (5+6), SDK smoke tests (10), velocity-shape regression guard (7), and the new wallet-endpoint regression suite (17/17 — all filter combinations).

May 20Security

RLS gap closure on 5 internal tables (security)

Audit triggered by an end-of-day "is the DB secured?" check found five tables with row-level security disabled and the Supabase anon role (the public key shipped to every browse…

Security+

Audit triggered by an end-of-day "is the DB secured?" check found five tables with row-level security disabled and the Supabase anon role (the public key shipped to every browser) granted full CRUD via PostgREST: mv_early_buyer_pnl, sniper_wallets_cache, bundler_wallets_cache, token_blacklist, and early_buyer_pnl_refresh_state. Per-wallet realized PnL and the internal moderation blacklist were readable; cache tables and refresh-state were also DELETE/TRUNCATE-able.

Migration 148 enables RLS on all five tables (deny-by-default) and revokes privilege grants as defense in depth. No code changes needed — all endpoints continued working. Regression guard added for future RLS changes.

May 20Platform

Universal wallet endpoints: stats, PnL, positions, paginated trades

Four new Pro/Ultra endpoints under /api/v1/wallet/{address} let you pull profile data for any Solana wallet — not just the 1,058 we curate as KOLs. Same FIFO cost-basis math, sa…

Platform+

Four new Pro/Ultra endpoints under /api/v1/wallet/{address} let you pull profile data for any Solana wallet — not just the 1,058 we curate as KOLs. Same FIFO cost-basis math, same response shape, but the address space is everyone we've seen trade through our DEX firehose (90-day window, ~38 days of historical data right now).

GET /api/v1/wallet/{address} — cheap stats lookup. Returns total_trades, buys/sells split, SOL in/out, unique tokens, first/last seen, plus cross-product flags (is_kol, is_alpha_tracked with bot_confidence + win rate + net PnL, is_deployer with tokens deployed). Backed by a get_wallet_stats() SQL function that reads the existing idx_token_trades_wallet_cover — sub-100ms on a wallet with 1,123 trades across 324 tokens. No materialised view, no new ingestion pipeline.

GET /api/v1/wallet/{address}/pnl — full PnL with the same shape as /api/v1/kol/{wallet}/pnl: realized + unrealized SOL, profit factor, avg + median hold minutes, max drawdown, daily PnL curve (UTC), closed positions (sorted by pnl desc) with ROI %, open positions with current price fetched live from our market-cap tracker. Cached in wallet_analyses with dynamic TTL — 5 min for wallets active in the last 24h, 1 hour for 1–7d old, 24 hours for dormant. Cache hits are free against your daily quota.

GET /api/v1/wallet/{address}/positions — open lots only, leaner response for client UIs that don't need the full PnL summary. Shares the /pnl cache so if you've recently called /pnl for this wallet the /positions call is a cache hit immediately.

GET /api/v1/wallet/{address}/trades — paginated raw trades. Cursor-based on (block_time, id) for stable DESC ordering. Filters: action (buy/sell), token_mint, since/until Unix timestamps, limit (1–500, default 100). Response includes next_cursor + has_more.

Honest about the data window. Cost basis is only observable inside the 38-day data window (we started capturing every DEX swap on 2026-04-12). A wallet that bought a token 60 days ago and sells it today gets the sell counted but no matching cost basis — overflow sells are silently discarded rather than inventing a realized PnL number. notes.cost_basis_observable_from in the response surfaces the cutoff so clients can warn users when relevant.

Why this matters for SDK users. Pre-1.8 you could only get rich PnL data for hand-curated KOL wallets. Now any wallet works — feed an address from a Twitter pump screenshot, a deployer's wallet, a trader who DM'd you, and get the same shape back. The four endpoints will land in the next SDK release across all 7 packages.

Suite addition: a new scripts/test-wallet-endpoints.mjs runs as part of /testapi covering every filter combo (action, token_mint, since/until, cursor pagination, limit clamp, invalid inputs, unknown wallets, cache hits). 17/17 green on first prod run.

Heads up if you build on top: open-position counts are bounded by mc-tracker's price coverage — mints without a current price in our cache return unrealized_sol: null rather than a fabricated zero. Same with the new MC clamp shipped earlier today on kol_trades (see below): if mc-tracker's quoted price is 5× the swap-implied rate, the MC and price fields land as null on that trade rather than letting a momentary phantom-pool number poison history.

May 20Platform

KOL trade MC sanity-clamp (no more $57M phantom market caps)

When a KOL trade lands, kol-tracker fetches the current market cap from mc-tracker and writes it into kol_trades.market_cap_usd_at_trade. That value is now sanity-clamped: if mc…

Platform+

When a KOL trade lands, kol-tracker fetches the current market cap from mc-tracker and writes it into kol_trades.market_cap_usd_at_trade. That value is now sanity-clamped: if mc-tracker's quoted per-token price is more than 5× higher than the swap-implied rate (sol_amount / token_amount × sol_usd), the MC and price fields are nulled before writing to the row.

This was triggered by a 2026-05-19 autopost that announced $MC: $72.4K → $57.9M MC — the high-MC number came from two trades where mc-tracker quoted a price 16× and 182× the actual swap rate, briefly during a graduation-moment when a phantom routing wallet became the primary pool. The two bad rows poisoned the 6-hour band-crosser query downstream.

The clamp is inflation-only. Creator-fee PumpSwap tokens where the trader receives ~0.15% of bought tokens have implied price way higher than headline — those are not clamped because the headline is correct, the implied is the distorted one.

Downstream protection: webhook deliveries, WebSocket kol:trade events, the Telegram bot's "@ MC $X" line, copy-trade signal payloads, charts, and the X autopost all read the same market_cap_usd_at_trade column. One clamp at the write boundary protects every consumer.

In the first 5 minutes of running, the clamp fired exactly once on a HENRY token (different mint than the headline-named one) where mc-tracker briefly quoted $0.0087/tok vs implied $0.001/tok (8.4×). The good first-delivery from the redundant multi-region gRPC streams had already inserted the correct row; the clamp on the second delivery was a correct no-op.

May 19Bot

Free Telegram alerts: KOL trades + elite deployer launches

The MadeOnSol Alpha Bot moves from broadcast-only to interactive for the free tier. Previously, free users got the /digest once per day plus on-demand lookups (/token, /wallet, …

Bot+

The MadeOnSol Alpha Bot moves from broadcast-only to interactive for the free tier. Previously, free users got the /digest once per day plus on-demand lookups (/token, /wallet, /deployer) and nothing else — real-time fan-out was paid-only. That made the bot feel like a newsletter and drove a 37% pause rate among linked free users.

/alert kol and /alert deployer are now open to the free tier, with two server-side caps and full user-set filters:

  • /alert kol — up to 30 KOL trades per day matching your own rule. Set your own min_sol threshold (e.g. /alert kol 5 for buys ≥ 5 SOL), scope to a specific KOL (/alert kol "Casino"), token mint, or wallet. Same filter grammar as the paid tiers.
  • /alert deployer elite,good — up to 3 deployer launches per day matching the tiers you picked. All five deployer tiers (elite, good, moderate, rising, cold) are selectable.

Both caps reset at 00:00 UTC. Hit one and the bot silently stops fanning out that rule type for the day — no scary "rate limit" message, just quiet — and resumes after midnight. The user-set filters (min SOL, KOL name, token mint, deployer tier) decide which trades make the cut; the bot doesn't second-guess your taste.

Paid features stay paid. Coordination alerts (/alert coord), copy-trade signals (/alert copytrade), and the wallet tracker (/watch) remain Pro/Ultra. Free users see those submenus but the toggle buttons are gated with a "requires Pro/Ultra" message. The 30/day kol_trade cap is also the main reason to upgrade — Pro removes it entirely.

If you're already linked, /menu → 🚨 Configure alerts → 📊 KOL trades to start. If you don't have a MadeOnSol account yet, madeonsol.com/developer takes about 30 seconds.

May 14Platform

Public `/pricing` page, demo key on `/api-docs`, smarter 429s, lineup trimmed

Five user-facing changes ship together — most of them long-overdue housekeeping around the API funnel.

Platform+

Five user-facing changes ship together — most of them long-overdue housekeeping around the API funnel.

New public /pricing route. Plans, limits, and feature matrix now live on a dedicated marketing page at madeonsol.com/pricing. The /developer page stays focused on its job — signing in, generating + managing keys, managing your subscription. All "see plans / free tier / starts free at…" CTAs across the site, the LLM docs, the Telegram bot, and changelog point at /pricing; action CTAs ("Generate your key", "Manage your subscription") keep pointing at /developer.

Public demo key on /api-docs. The try-it widget on /api-docs is now wired to a public demo key — no signup needed. Capped at 20 req/hr per IP across 3 endpoints (/kol/feed, /deployer-hunter/alerts, /token/{mint}). Validate the response shape in 10 seconds before signing up.

429 responses now carry upgrade info inline. Hitting the daily or burst cap used to return a bare 429 { error: "rate_limit_exceeded" } plus the standard Retry-After header. The body now includes the caller's current tier, the violated limit, the absolute resets_at ISO timestamp, and an upgrade_url pointing at /pricing. SDKs can surface "you're on Free, upgrade to Pro for 50× headroom" without a second /me round-trip. Retry-After is still set on every 429 (seconds-until-reset for daily, seconds-until-burst-window-rolls for burst).

Pro headline sharpened. The Pro tier was previously sold as "Telegram + full v1 API", which understated what it actually unlocks. The new headline across the pricing page, the bot's /upgrade message, the LLM docs, and the SDK READMEs is "Production webhooks + copy-trade signals" — HMAC-signed webhooks, per-rule copy-trade delivery, coordination alerts with custom thresholds, wallet tracker, and the WS streaming surface. The 10k req/day + 120 burst/min limits are still the same — only the framing changes.

Trader tier retired from sale. The $25/mo Trader tier (Telegram-only alerts) is no longer purchasable. Existing Trader subscribers keep their access through the end of their billing period — no forced migration. The lineup is now Free / Pro / Ultra everywhere. References to Trader in marketing surfaces (pricing page, bot upsells, LLM docs, this changelog going forward) are gone; the underlying database tier code and existing Trader subscriber flows are unchanged.

SDK surface sync — docs/marketing-URL patch (no API changes):

madeonsol                          2.6.1  →  2.6.2   (bare TypeScript)
madeonsol-x402                     1.7.1  →  1.7.2   (npm)
madeonsol-x402                     1.7.1  →  1.7.2   (PyPI — pip install madeonsol-x402)
mcp-server-madeonsol               1.7.0  →  1.7.2
@madeonsol/plugin-madeonsol        1.7.0  →  1.7.2   (Eliza)
solana-agent-kit-plugin-madeonsol  1.7.0  →  1.7.2
madeonsol (crates.io)              0.8.0  →  0.8.1   (Rust)

Every README, JSDoc, docstring, tool-description, error message, code-comment, and CLI hint across 30+ files now sends prospects to /pricing (public, free-tier card visible without auth) instead of /developer (login-gated). Action-tone refs ("sign in", "manage your key") still point at /developer. Trader tier dropped from package README tier lists. Rust SDK README ULTRA annual price corrected ($1990 → $1490). No runtime behaviour changes; SDK types unchanged; ApiTier::Trader / "TRADER" union variant retained for grandfathered subscriber rows.

May 13API

Velocity on `/kol/coordination` + SDK velocity-shape patch (1.7.1 / 2.6.1)

Two related changes shipped today.

API+

Two related changes shipped today.

/api/v1/kol/coordination now returns velocity fields alongside every cluster: mc_change_pct, volume_usd, mev_volume_pct (each keyed by 5m/15m/1h/2h/4h) and history_age_seconds. Same shape as /token/{mint} and /copytrade/signals. Lets coordination consumers tell whether a cluster is firing into a moving token or before the move, in one call instead of N follow-up /token/{mint} lookups. Sparse — only windows with enough mc-tracker history are populated.

SDK velocity-shape patch (1.7.1 / 2.6.1): the 1.7.0 / 2.6.0 release shipped TypeScript types and README examples for velocity in a velocity[window].mc_change_pct shape that didn't match the API's actual mc_change_pct[window] shape. Anyone reading client.token.get(...).velocity?.["1h"]?.mc_change_pct was getting undefined. Patched packages:

madeonsol         2.6.0  →  2.6.1   (bare TypeScript)
madeonsol-x402    1.7.0  →  1.7.1   (npm + PyPI)

mcp-server-madeonsol, plugin-madeonsol, solana-agent-kit-plugin (1.7.0) had only generic mentions and stay at 1.7.0. Rust SDK (madeonsol crate, 0.8.0) doesn't surface velocity yet — no patch needed. The fix is type-only; runtime API contract is unchanged.

May 12SDK

Token directory, account self-inspection, smarter 400s (SDK 1.7.0)

Three new API surfaces, two long-deferred cleanups, and a defensive throttle for endpoint probers.

SDK+

Three new API surfaces, two long-deferred cleanups, and a defensive throttle for endpoint probers.

New endpoints:

GET /api/v1/me        → all tiers
GET /api/v1/tokens    → PRO+

GET /api/v1/me reads from the same in-memory counters that drive rate-limit enforcement — quota.daily.remaining is authoritative, no header parsing required. Returns tier, subscription block (status, billing_cycle, current_period_end, started_at), quota.daily (limit/used/remaining/resets_at), quota.burst (limit/used/remaining/window_seconds), and per-feature usage across webhooks, copy-trade wallets/rules, coordination rules, first-touch subscriptions, ws/dex connections, and wallet-tracker watchlist. Useful for self-throttling clients and quota-aware retry logic.

GET /api/v1/tokens is a filtered, sortable directory across every active mint we track — complements the single-mint /token/{mint} and the KOL-scoped /kol/tokens/{hot,trending}. Server-side filters: min_mc, max_mc, min_liq (default 2000 USD — set 0 to disable phantom-MC dust floor), active_h, primary_dex (pumpfun/pumpswap/raydium/meteora/orca/raydium_clmm), authority_revoked, exclude_token2022, min_lp_burnt_pct. Computed post-filters (over-fetches 3× and filters in app): min_volume_1h_usd, max_mev_share_pct, mc_change_1h_min_pct, mc_change_1h_max_pct. Sort: mc_desc / mc_asc / last_trade_desc / liquidity_desc / cumulative_volume_desc. Pagination response includes post_filtered: true so clients can detect when computed filters trim a page below limit.

// Momentum scanner: liquid mints up >20% in 1h, low bot share
const { tokens } = await client.token.list({
  min_liq: 10000,
  min_volume_1h_usd: 5000,
  max_mev_share_pct: 60,
  mc_change_1h_min_pct: 20,
  sort: "mc_desc",
});

Structured 400 on /token/{mint}: invalid mints now ship code: "invalid_mint", reason (specific diagnosis — "too short — got 8 chars, need 32-44", "contains '0' which isn't valid base58", etc.), received, received_length, expected_length, example, and a docs URL. No more trial-and-error.

Velocity / MEV-share fields added to every TokenResponseBody (catching the SDK up to the 2026-05-07 server-side ship): mc_change_pct, volume_usd, mev_volume_pct (each keyed by 5m/15m/1h/2h/4h) plus history_age_seconds on the parent. mev_volume_pct is unique to MadeOnSol — flag wash-pump patterns where headline volume is bot-driven (sandwich/Jito-bundle MEV) rather than organic demand. Note: the 1.7.0 typed shape was wrong (velocity[window] instead of field-keyed) — patched in 1.7.1 / 2.6.1, see entry above.

Per-IP 401 throttle: repeated authentication failures from the same IP now hit a 30-failure/min cap that short-circuits to a 429 with a tiny body — stops endpoint-fishing without DB lookups. Legitimate clients with a typo get 30 retries before the cap fires.

TRADER tier (Telegram) unlocks coordination + copy-trade alerts: the $25/mo Trader tier now includes 1 copy-trade wallet + 1 coordination alert rule, delivered exclusively over Telegram (/alert copytrade <wallet>, /alert coord on). REST/WS/webhook access for those endpoints stays PRO+ — the underlying rules are auto-created on direct DB write when a Trader user opts in via the bot. Default coord thresholds locked at min_kols=5, window=15min, cooldown=30min for Trader; PRO+ keep custom thresholds.

TG bot /start UX: new unlinked users now see one real sample alert appended to the welcome message (no rate-limit hit), the $25/mo price line moved out of the cold open into /upgrade, a "Just /pause anytime to silence" reassurance line was added, and the post-link flow renders a one-tap "🚨 Configure my alerts" keyboard instead of plain text.

Removed: the deprecated avg_entry_mc_usd / entry_mc_samples fields are now fully gone from leaderboard endpoints, SDK types, READMEs, openapi-spec, llms.txt, and MCP tool descriptions. If you were reading them, switch to per-trade market_cap_usd_at_trade (via the v1.6 MC enrichment).

SDK versions published:

madeonsol                          2.5.0  →  2.6.0   (bare TypeScript)
madeonsol-x402                     1.6.0  →  1.7.0   (npm)
madeonsol-x402                     1.6.1  →  1.7.0   (PyPI — pip install madeonsol-x402)
@madeonsol/mcp-server              1.6.0  →  1.7.0
@madeonsol/plugin                  1.6.0  →  1.7.0   (Eliza)
@madeonsol/solana-agent-kit-plugin 1.6.0  →  1.7.0
madeonsol (crates.io)              0.7.0  →  0.8.0   (Rust)

All packages add a me() method (or client.rest.me() in Python) and a tokensList() / token.list() / tokens_list() method, plus expose the velocity/MEV-share fields on token responses. The MCP server gains two new tools: madeonsol_me and madeonsol_tokens_list. The Eliza and Solana-Agent-Kit plugins gain matching meAction and tokensListAction.

May 9SDK

Market-cap filtering everywhere (SDK 1.6.0)

The MC enrichment from the last release now becomes a first-class filter. Every signal surface — REST, WebSocket, per-rule alerts, the Telegram bot — accepts min_mc_usd and max_…

SDK+

The MC enrichment from the last release now becomes a first-class filter. Every signal surface — REST, WebSocket, per-rule alerts, the Telegram bot — accepts min_mc_usd and max_mc_usd so callers can scope every request or every alert rule to a specific market-cap band. "Show me only sub-$50K KOL trades". "Skip every coordination signal on tokens above $5M". "Auto-fire the copy-trade only when the source bought between $100K and $1M MC".

REST API — four endpoints accept the band:

/api/v1/kol/feed?max_mc_usd=50000           → only sub-$50K KOL trades
/api/v1/kol/coordination?min_mc_usd=100000  → skip micro-cap coordination
/api/v1/kol/first-touches?max_mc_usd=200000 → S-tier scout entries below $200K
/api/v1/copytrade/signals?max_mc_usd=500000 → drop signals above $500K

/kol/feed filters at the database layer (uses the existing idx_kol_trades_mc_at_trade partial index). The other three filter post-aggregate on whichever MC concept matches the endpoint — /coordination filters on the cluster's MC at the chronologically-first KOL buy, /first-touches on the at-touch MC, /copytrade/signals on the source trade's MC. Trades with unknown MC drop out when the band is set — the caller asked for a specific range, we don't pretend "unknown" matches.

WebSocket — subscribe-time bands on kol:trades, kol:first_touch, and kol:coordination. The server-side filter drops events that miss the band before pushing — saves bandwidth and lets your bot wake on relevant alpha only.

ws.send(JSON.stringify({
  type: "subscribe",
  channels: ["kol:trades"],
  filters: { min_mc_usd: 10000, max_mc_usd: 250000 },
}));

Per-rule alert tables now carry the band. Three user-rule tables — coordination_alert_rules, copytrade_subscriptions, kol_first_touch_subscriptions — gain min_mc_usd / max_mc_usd columns. The signal-evaluator reads them on every trade and drops triggers that fall outside the rule's band before the alert ever fires. Lets you persist "alert me on KOL coordination, but only on tokens under $50K MC" as the rule itself instead of post-filtering downstream.

Telegram bot — global per-user MC band. New /mc command sets a band that overlays on top of every alert the bot delivers to you, regardless of which underlying rule fired:

/mc 50k-1m   → only alerts on tokens between $50K and $1M MC
/mc -500k    → only alerts on tokens at or below $500K
/mc 200k-    → only alerts on tokens at or above $200K
/mc          → show current band
/mc clear    → remove the band

The outbox poller filters at delivery time using the user's pref. Daily digests (no per-token MC) are unaffected; alerts whose extracted MC is unknown still deliver (we don't penalise missing data on the noise-filter side).

SDKs — bumped:

  • madeonsol (npm, bare) → 2.5.0
  • madeonsol-x402 (npm + PyPI) → 1.6.0
  • mcp-server-madeonsol → 1.6.0
  • @madeonsol/plugin-madeonsol → 1.6.0
  • solana-agent-kit-plugin-madeonsol → 1.6.0
  • madeonsol (Rust crate) → 0.7.0

All min_mc_usd / max_mc_usd params are optional — the SDK call signatures stay backwards-compatible. Param fields also live on the coordinationAlerts.create/update and firstTouchSubscriptions.create/update methods so persistent rules carry the band end-to-end.

Cleanup — avg_entry_mc_usd removed. The deprecated avg_entry_mc_usd and entry_mc_samples fields on /kol/leaderboard and /alpha/leaderboard are gone. They were a 2026-05-06 experiment that the new MC band on requests subsumes — instead of asking for "the avg entry MC for this KOL", filter the trade feed by max_mc_usd and you get the actual sub-set you cared about.

Coverage breadth (since 1.5.0): Moonshot bonding curve indexed in kol-tracker + dex-stream. Meteora CPAMM (DAMM v2) pool state subscription. USD1 added to the recognised quote-mint set. Phantom-pool rejection and a /price/{mint} trades_24h ReferenceError fix on the side.

Ops note: Backup format upgraded for improved restore reliability. No customer-visible change.

May 7API

Velocity deltas + organic/MEV volume on `/api/v1/token/{mint}`

The big one. Every call to /api/v1/token/{mint} now returns a per-window breakdown of how the market cap moved and what kind of volume drove it.

API+

The big one. Every call to /api/v1/token/{mint} now returns a per-window breakdown of how the market cap moved and what kind of volume drove it.

{
  "token": {
    "mint": "...",
    "market_cap": 423000,
    "mc_change_pct": { "5m": 8.2, "15m": 31.4, "1h": 62.1, "2h": 75.0, "4h": 87.0 },
    "volume_usd":     { "5m": 42000, "15m": 118000, "1h": 340000, "2h": 500000, "4h": 920000 },
    "mev_volume_pct": { "5m": 18.4, "15m": 22.1, "1h": 27.3, "2h": 31.8, "4h": 34.2 },
    "history_age_seconds": 14400
  }
}

Window choice. 5m / 15m / 1h / 2h / 4h matches memecoin lifecycle: 5m and 15m for entry timing, the 1h-2h-4h gradient is where pumps separate from fades. We deliberately skipped 6h and 24h because most memecoins don't survive that long — the survivors are a different product surface.

Volume is split into organic and MEV. volume_usd excludes sandwich and Jito-bundle bot churn (mc-tracker tags these per-trade via the existing MEV detector). mev_volume_pct surfaces the MEV share as a separate field so traders can flag wash-pump patterns. A token with volume_usd.4h: 920k and mev_volume_pct.4h: 35% is materially different from the same headline volume at 5%. Nobody else surfaces this.

Reorg-safe. mc-tracker consumes from dex-stream's CONFIRMED-commitment Yellowstone subscription (~1-3s lag from chain head, vs shred's sub-150ms). Cumulative volume counters are stable across reorgs at this commitment depth.

Coverage. Window keys are only present when the token has been tracked long enough — a 1-hour-old token only returns 5m, 15m, and 1h (not 2h or 4h). history_age_seconds reports our in-memory ring's coverage so SDKs can branch cleanly without probing for missing keys.

Heads-up after first deploy. mc-tracker's history ring rebuilds in memory; expect roughly a 4-hour warmup before all windows are populated for tokens that existed before deploy. Subsequent restarts hydrate cumulative counters from the persisted columns and warm up faster (the ring itself is rebuilt from scratch but counters carry).

Backed by migration 129 (18 new columns on token_prices), mc-tracker's new in-memory velocity ring (24-byte tuples per token, sparse, 60s append rate-limit, 4h trim), and a projectMcDeltas helper in mc-enrichment.ts.

Also enriched with the same shape (REST):

  • POST /api/v1/token/batch — same per-mint deltas as the single-mint endpoint, batched up to 50 mints/call.
  • GET /api/v1/copytrade/signals — every signal now carries the source token's current mc_change_pct, volume_usd, mev_volume_pct alongside the existing market_cap_usd_at_trade. Lets copy-trade clients see at a glance whether the signal token is still pumping or already faded.

WebSocket + webhook payloads — every event with a token_mint now carries velocity:

  • mc:update broadcast (consumed by ws-streaming WS subscribers + webhook-worker push customers) now includes mc_change_pct, volume_usd, mev_volume_pct, history_age_seconds. ~300B → ~500B per payload, well under the 7,500B budget.
  • kol:trade — token's velocity context attached at emit time (the trader bought into a token already up 62% in 1h with 18% MEV share, or into a flat token).
  • kol:coordination — cluster trigger token's velocity context.
  • deployer:alert + deployer:bond — the launching token's velocity right at alert time.
  • wallet_tracker:event — tracked-wallet trade target token's velocity context.
  • copytrade:signal — same velocity fields as the REST endpoint, on every fire.

Telegram alerts now render velocity: Every paid TG alert template (KOL trades, deployer launches, deployer bonds, KOL coordination clusters, wallet activity, copy-trade signals) carries one extra line:

📈 +62.1% / 1h · vol $340K · 🤖 18% MEV

The MEV badge only fires when ≥10% of the window's volume is sandwich/bundle activity — that's the signal that a headline pump may be wash-traded rather than organic. Window picked automatically from the most informative one available (1h preferred, falls back to 15m → 5m → 2h → 4h).

May 7Platform

Friendlier 400s on token endpoints, `is_deployer` flag

Two ergonomics fixes driven by 7-day audit-log review.

Platform+

Two ergonomics fixes driven by 7-day audit-log review.

Token endpoints — clearer error on tickers. /api/v1/token/{mint}, /api/v1/tokens/{mint}/buyer-quality, and /api/v1/tokens/{mint}/cap-table now return a richer 400 when the path isn't a base58 mint:

{
  "error": "Invalid token mint address",
  "hint": "Pass a Solana base58 mint address (32-44 chars). Tickers like 'BTC', 'ETH', or 'XRP' aren't supported because they aren't Solana-native assets. For SOL, use the wrapped SOL mint: So11111111111111111111111111111111111111112.",
  "received": "BTC"
}

The audit log showed users hitting /token/SOL, /token/BTC, /token/AAPL, /token/CRO, /token/XRP and burning rate-limit on cryptic 400s. The hint text points them at the wrapped SOL mint and explains why the rest don't have Solana-native equivalents.

/api/v1/deployer-hunter/{wallet} — 404 → 200 with is_deployer: false. Untracked wallets used to return 404 with { "error": "Deployer not found" }. They now return 200 with:

{
  "is_deployer": false,
  "wallet": "<echoed>",
  "deployer": null,
  "pump_stats": null,
  "pump_tokens": [],
  "pump_error": null
}

Backwards compatible — clients checking if (response.deployer) still see falsy. Branch on is_deployer going forward. The change matches user intent: "is this wallet a deployer?" is a feature, not an error.

May 6Platform

Market cap enrichment everywhere

The MC-at-trade-time work that landed yesterday now flows through every signal surface — every paid endpoint, every WebSocket event, every webhook, every Telegram alert, and the…

Platform+

The MC-at-trade-time work that landed yesterday now flows through every signal surface — every paid endpoint, every WebSocket event, every webhook, every Telegram alert, and the leaderboards.

REST endpoints — new fields:

  • GET /api/v1/copytrade/signals — market_cap_usd_at_trade, price_usd_at_trade (joined from the source kol_trades row by tx_signature), plus current market_cap_usd/last_price_usd from token_prices. No more separate /token round-trip after every signal.
  • GET /api/v1/kol/coordination — market_cap_usd_at_first_buy (cap at the cluster's chronologically-first KOL buy) + current market_cap_usd/last_price_usd per token. Distinguishes coordinated accumulation at micro-cap from late-stage chasing.
  • GET /api/v1/kol/alerts/recent — consensus_cluster alerts now match fresh_token_kol_buy's shape: market_cap_usd_at_first_buy + current MC fields.
  • GET /api/v1/kol/first-touches — market_cap_usd_at_first_buy, price_usd_at_first_buy (joined via tx_signature), plus current market_cap_usd/last_price_usd. Lets the scout-tier filter combine with cap band ("S-tier scouts entering at <$50K MC").
  • GET /api/v1/kol/leaderboard — avg_entry_mc_usd + entry_mc_samples per KOL, computed live from buys in the period. Surfaces who's playing micro-cap vs mid-cap.
  • GET /api/v1/alpha/leaderboard — same avg_entry_mc_usd + entry_mc_samples per wallet (null + 0 for non-KOL wallets).
  • GET /api/v1/deployer-hunter/stats — avg_mc_at_alert_usd_30d per tier (elite/good/rising) + sample count. Shows whether elite deployers launch at micro-cap or already-pumped.

WebSocket + webhook payloads — three event types newly carry MC:

  • kol:first_touch (live + replay) — market_cap_usd_at_trade + price_usd_at_trade flow through via the updated record_kol_first_touch Postgres trigger.
  • kol:coordination — triggering_trade.market_cap_usd_at_trade + price_usd_at_trade.
  • copytrade:signal — market_cap_usd_at_trade + price_usd_at_trade on every signal.

Telegram bot — five surfaces newly enriched:

  • copytrade:signal alerts: bought 5 SOL of $TOKEN at $50K MC
  • kol:coordination alerts: Latest in: X (5 SOL at $50K MC) on the triggering trade line
  • /token <mint> adds a current-MC line: 📈 MC $50K · liq $10K · on pumpswap
  • /wallet <addr> shows @ $50K MC on each recent trade
  • /digest top-tokens-by-KOL-interest now includes avg $50K MC per token

Website:

  • KOL leaderboard table: new Avg Entry MC column with sample-count tooltip (micro-cap vs mid-cap trader signal).
  • KOL profile token-PnL table: new Avg Buy MC column.

Pipeline reliability fixes shipped alongside (root causes that dropped accuracy):

  • mc-tracker flushDirty now chunks at 500 rows per tx — eliminated the ~9% flush-failure rate from statement_timeout on large UPSERTs.
  • Eager-fetch hint from kol-tracker: when /mc/<mint> misses for a KOL trade, mc-tracker preemptively fetches mint supply + (if tx_signature provided) synthesizes a swap event from the tx, eliminating the bootstrap-lag window.
  • Bags.app pool support: activity-based authority bypass (liquidity_usd ≥ $5K AND swap_count ≥ 3) admits real Bags pools whose Meteora-wrapped non-PDA authorities previously failed phantom-pool detection.
  • PumpSwap canonical pool-state subscription: Pool state account (245B, owner pAMMBay…) decoded via the official IDL → token.pumpswap_canonical[quote_mint] registry. Pool entries whose pool_address doesn't match the canonical token-vault get flagged is_canonical=false and excluded from primary selection / VWAP / last_price propagation. Closes the creator-fee redirect-treasury contamination class.
  • Multi-hop Jupiter routes (≥2 underlying DEXes in one tx) are now tagged dex=jupiter so mc-tracker's existing jupiter filter rejects them at handleSwap entry — no more phantom router-as-pool entries (the Apple $46M-MC bug class).
  • Stablecoin filter: KOL trades where token_mint ∈ {SOL, USDC, USDT} are dropped before insert — no more "$KOL bought 100 SOL of USDC" noise on the feed.

Tools: SDK packages already at 1.4.0 from yesterday's bump pick up the new fields automatically (untyped-access). A 1.5.0 release with full TS type extensions across all 5 SDKs ships next session.

May 5Bot

Market cap at trade time (KOL feed + WS + TG bot)

Every KOL trade now ships with the token's market cap at the exact moment the swap fired. Sourced live from our in-memory price tracker (the same one that powers /api/v1/token/{…

Bot+

Every KOL trade now ships with the token's market cap at the exact moment the swap fired. Sourced live from our in-memory price tracker (the same one that powers /api/v1/token/{mint}), not from a Dexscreener round-trip — so the number reflects the real cap during a fast-moving wave, not whatever the chart settled at later.

REST: GET /api/v1/kol/feed, GET /api/v1/kol/alerts/recent, GET /api/v1/kol/{wallet} — each trade gains market_cap_usd_at_trade and price_usd_at_trade (USD; nullable for tokens we don't track yet).

WebSocket: the kol:trade event payload includes both fields automatically — ULTRA WS subscribers see them with no client change.

SDKs: bumped — npm madeonsol 2.3.0, madeonsol-x402 1.4.0, @madeonsol/plugin-madeonsol 1.4.0, solana-agent-kit-plugin-madeonsol 1.4.0, mcp-server-madeonsol 1.4.0, PyPI madeonsol-x402 1.4.0, crates.io madeonsol 0.5.0. TypeScript and Rust SDKs surface the new fields as typed optionals; Python passes them through in the response dict.

TG alerts: KOL ALERT messages now read e.g. Goyim bought 5.05 SOL of $WURK at $18K MC, with sells correctly labeled sold.

Storage: persisted on kol_trades (migration 126) so historical "show KOL trades that hit MC < $X" queries work end-to-end. Backfilled trades skip the enrichment to avoid stamping current state on old block_times.

May 3Bot

Telegram bot: 1-tap signup, /menu hub, and 3 free lookup commands

Two days after launch, the bot got a UX pass driven by the friction we watched in production. Fifteen slash commands collapse into a single button hub; the deep-link signup is r…

Bot+

Two days after launch, the bot got a UX pass driven by the friction we watched in production. Fifteen slash commands collapse into a single button hub; the deep-link signup is replaced by a 1-tap Mini App; three new free lookup commands work without an account.

/menu hub (new) — five buttons replace the wall of slash commands: 📊 Discover (lookups + digest), 🚨 Configure alerts (tap-to-toggle, no grammar), 👁 Wallet tracker, 👤 Account (tier, usage, pause/resume), ❓ Help. Power-user CLI commands all still work — they're just hidden from the slash autocomplete.

Free lookup commands (new, no signup) — /token <mint> returns unique KOL buyer count, still-in vs exited split, momentum (buyers in 1h / 15m / 5m), total SOL bought vs sold, deployer tier, and the latest 5 KOL buyers. /wallet <addr> returns KOL identity (name, strategy, X followers) if tracked, plus 7-day buys/sells/unique-tokens, SOL in vs out, and the latest 5 trades. /deployer <addr> returns tier, bond rate, last-10 streak, avg time-to-bond, peak MC of best token, and recent launches with bond status.

1-tap Mini App signup (new) — old flow: visit /developer in a browser → click Connect Telegram → follow the deep link back into the bot → confirm. Three context switches, two browser tabs. New flow: open the bot → tap "Create free account (1 tap)" → sign in via Google or email inside the Telegram Mini App → done. TG chat binds via a signed HMAC token; webview auto-closes via WebApp.close(); works on iOS / Android / desktop. Existing accounts are detected and re-bound on the same screen.

Tap-to-toggle coordination presets — /menu → Configure alerts → 🧬 Coordination now offers 🟢 Strict (5 KOLs / 15 min) · 🟡 Moderate (4 / 10) · 🔴 Aggressive (3 / 5) · 🔇 Off. Persists into coordination_alert_rules under name='tg-bot' so the same rule shows up in the WebSocket subscription.

📤 Share as image — every /token output now ships with a Share-as-image button that posts a 1200×630 PNG (rendered server-side via next/og) with our brand baked in. Drop straight into X, Discord, or your group chat.

Inline confirms for destructive actions — /menu → Account → 🔌 Unlink now morphs into a Yes / Cancel inline keyboard instead of asking the user to type /unlink. One tap to ask, one tap to confirm.

Slim slash-menu — BOT_COMMANDS registered with Telegram trimmed to 6: start, menu, digest, sample, upgrade, help. Everything else still works when typed manually.

Alpha-wallet bot detection improved (migration 124) — mv_alpha_wallets.bot_confidence now flags as high when tokens-per-active-hour > 5, when win rate ≥ 1.0 over ≥10 samples, or when the burner pattern (>10 tokens in under 6 active hours) is met. Filters out the obvious bot 100%-winrate wallets from the homepage scout list.

Landing page refresh: the Telegram landing page (since removed) led with the free commands and the 1-tap onboarding. Pricing on /solana-api updated to reflect the free lookups in the BASIC tier and the tap-to-toggle config in the TRADER tier.

May 2Bot

MadeOnSol Alpha Bot: real-time alerts in Telegram

Five live alert streams pushed to your Telegram DM in under 2 seconds end-to-end: KOL trades, Pump.fun deployer launches and bonds, KOL coordination clusters, copy-trade signals…

Bot+

Five live alert streams pushed to your Telegram DM in under 2 seconds end-to-end: KOL trades, Pump.fun deployer launches and bonds, KOL coordination clusters, copy-trade signals, and wallet-tracker events. Same pg_notify pipeline our WebSocket customers already use — Telegram is just another delivery target.

@MadeOnSolAlphaBot (new) — open the bot, run /digest for top tokens & scouts (last 24h), or /sample for one delayed real alert. Both work free, no signup. Connect your account at /developer → "Connect Telegram" to enable real-time delivery.

/alert grammar — /alert kol N (catch-all min SOL), /alert kol "Casino" 1 (per-KOL), /alert kol mint <mint> 1 (per-token), /alert kol wallet <addr> 1 (per-wallet), /alert deployer elite,good, /alert tracker on, /alert copytrade on, /alert coord on. Append off to disable any rule. /rules lists everything active, /delete <id> removes one.

Alert enrichment — every KOL alert ships with the trader's 7-day win rate; deployer alerts ship with the full track record (lifetime bond rate, last-10 outcome streaks, avg time-to-bond, peak market cap of the deployer's best token); coordination alerts ship with score 0-100, cluster avg win rate, exited count, and top 5 names.

Group mode (Ultra) — add the bot to a Telegram group, link from an Ultra account (/start link_<token> in the group), alerts broadcast to everyone in the chat. Per-chat rate gate auto-throttles to Telegram's 20 msg/min group cap.

Pricing: free /digest + 1 daily /sample for everyone; Trader $25/mo unlocks real-time KOL + deployer alerts; Pro / Ultra add copy-trade, coordination, wallet tracker, group-mode broadcasting.

Three bot tokens already provisioned (@MadeOnSolAlphaBot, @MadeOnSolAlpha2Bot, @MadeOnSolAlpha3Bot) — single bot today, sharded fan-out kicks in at 3k+ users. Outbox delivery uses FOR UPDATE SKIP LOCKED row claiming, per-chat 1msg/sec gate, global 25/sec token bucket. Daily /digest cron + 7d tg_outbox retention sweep run via pg_cron.

Landing page: /telegram (since removed). Docs: /help inside the bot.

April 2026

20 ships
Apr 26Platform

Scout signal: first-KOL-touch as a queryable + pushable feed

New product surface for tracking the moment a tracked KOL first buys a token — backtested as a meaningful leading indicator of multi-KOL coordination. 38d / 491k buys / 72,549 e…

Platform+

New product surface for tracking the moment a tracked KOL first buys a token — backtested as a meaningful leading indicator of multi-KOL coordination. 38d / 491k buys / 72,549 events analyzed; conditioning on top scouts (S-tier) lifts ≥3-follower hit rate from ~14% baseline to ~50%.

GET /api/v1/kol/first-touches (new) — every first KOL buy, filterable by min_scout_tier (S/A/B/C), min_kol_winrate_7d, min_n_touches, strategy, token_age_max_min, min_first_buy_sol, mint_suffix, plus since / before cursors. preset=scout and preset=fresh_launch shortcuts apply curated filter sets. include=followers_4h attaches retrospective follower counts for events ≥4h old. ULTRA gets the KOL wallet field; PRO/BASIC get name + scout context.

WebSocket kol:first_touches (new) — sub-second push on the same channel infrastructure as kol:coordination. Filterable at subscribe time on min_scout_tier, mint_suffix, min_first_buy_sol, kol, min_n_touches. PRO + ULTRA. Median lead time before the second KOL is 12 seconds, so the WS surface is the only one fast enough for automated trading.

POST /api/v1/kol/first-touches/subscriptions (new, ULTRA) — webhook delivery with HMAC-SHA256 signing. Up to 10 per-rule subscriptions with independent filter sets. Mirrors coordination/alerts.

mv_kol_scout_score materialized view — per-KOL aggregate over a rolling 30d window: n_first_touches_30d, avg_followers_4h, swarm_3plus_pct, swarm_5plus_pct, scout_tier. Refreshes hourly via pg_cron with advisory-lock guard. Stable across non-overlapping halves at n≥30 (Pearson r=0.78).

Public scout leaderboard at /kol/scouts — sortable table of top scouts with per-scout detail at /kol/scouts/[wallet] showing recent first-touches and follower outcomes.

SDKs: madeonsol-x402 (npm) → 1.3.1, madeonsol-x402 (PyPI) → 1.3.1, @madeonsol/plugin-madeonsol → 1.3.1, mcp-server-madeonsol → 1.3.1, and solana-agent-kit-plugin-madeonsol → 1.3.1 all expose firstTouches() plus firstTouchSubscriptions{List,Create,Get,Update,Delete} (Ultra). Bare madeonsol (npm) and the Rust SDK on crates.io ship in a follow-up release.

Apr 25Platform

Push-delivery observability: WS sessions + admin dashboards

Resolved a silent-failure mode that turned up on 2026-04-23: a PRO user (1ff470bd…) had 2,310 copy-trade signals fire over a week with 0 delivered — their WebSocket had been dis…

Platform+

Resolved a silent-failure mode that turned up on 2026-04-23: a PRO user (1ff470bd…) had 2,310 copy-trade signals fire over a week with 0 delivered — their WebSocket had been disconnected for days and no surface flagged it. Customers can't tell the difference between "no alpha to deliver" and "delivery is broken", so we built one.

  • ws_sessions table (migration 110) — every WS connect/disconnect on ws-streaming and dex-stream writes a row with user_id, tier, channels[], connected_at / disconnected_at, close_code, close_reason, messages_sent, remote_ip. 60-day retention.
  • coordination_alert_signals table (migration 111) — per-fire history for kol:coordination, parallel to copytrade_signals. Tracks delivered, delivered_at, delivery_error per dispatch (was previously fire-and-forget).
  • Admin push-delivery breakdowns (migration 112 + /admin/api) — three new SECURITY DEFINER functions (admin_copytrade_delivery_breakdown, admin_coord_delivery_breakdown, admin_first_touch_delivery_breakdown) bucket fires by failure mode (ws_not_connected / ws_not_subscribed / webhook_err / no_status / delivered). The /admin/api page now shows per-customer delivery health with at-a-glance churn vs. broken-pipe distinction.

No customer-visible API changes — purely operational visibility.

Apr 24Infra

Cron perf: incremental bundler/sniper cache refresh

refresh_bundler_sniper_caches() (introduced in migration 105) was full-scanning token_early_buyers on every run. Once that table crossed ~1M rows, the cron job started timing ou…

Infra+

refresh_bundler_sniper_caches() (introduced in migration 105) was full-scanning token_early_buyers on every run. Once that table crossed ~1M rows, the cron job started timing out at 60s — both the 2026-04-20 and 2026-04-21 runs failed silently.

Migration 109 rewrites the function to be incremental:

  • Watermark column on early_buyer_pnl_refresh_state tracks the max block_time covered by the last refresh.
  • Bundler cache — append-only by definition (a wallet that did a same-block multi-token buy stays flagged), so we only scan buys in new blocks.
  • Sniper cache — must handle additions and removals (a fresh slow-sell can drop a wallet's quick-flip ratio below 0.8). Builds a candidate set of wallets with new early-buy rows or new sells, recomputes qualification across each candidate's full history, then upserts/deletes against the cache.
  • First-run path preserved as a one-time bootstrap with elevated statement_timeout and work_mem.

Post-fix: cron runs in 2–4s instead of timing out. New index idx_early_buyers_first_buy_at supports the candidate-discovery query.

Apr 23API

Top-6 endpoint improvements + batch lookups

Audit of 30d api_audit_log surfaced concrete gaps on the most-used paid routes — missing filters, silent response bugs, no batch support. High-priority fixes shipped together:

API+

Audit of 30d api_audit_log surfaced concrete gaps on the most-used paid routes — missing filters, silent response bugs, no batch support. High-priority fixes shipped together:

/kol/feed — token_image_url now returned (was selected in the query but dropped from the mapped response — silent bug; UI consumers were missing token icons). Added ?before=<ISO> cursor pagination with next_before so polling clients stop re-fetching the same top rows.

/token/{mint} — enriched with first_seen_at, age_seconds, is_blacklisted, and blacklist_category (stablecoin / wrapped_sol / lst / rug). Joins against token_first_seen + token_blacklist, saving consumers a follow-up call.

POST /token/batch (new) — bulk lookup of up to 50 mints in one request. Same per-mint shape as GET /token/{mint}. Cuts request volume 10–20× for sniper workflows that previously polled per-mint.

POST /tokens/batch/buyer-quality (new) — bulk buyer-quality scoring for up to 50 mints. Shares the LRU cache with the single-mint endpoint — repeat calls return cache_hits=N at near-zero cost.

/deployer-hunter/alerts — new filters: ?min_kol_buys=N, ?alert_type=, ?priority=high|medium|low. ?before=<ISO> cursor pagination (was only offset-paginated). Joined deployer payload now includes best_token_peak_mc.

/deployer-hunter/recent-bonds — ?since=<ISO> for incremental polling + next_since cursor (without it, every poll re-returned the same rows). Added ?tier=, ?peak_mc_min=, and token_image_url in the response.

All additions backward-compatible. /api-docs, /solana-api, openapi-spec, and llms.txt updated to match. Filter matrix verified 30/30 on the green slot before deploy.

Apr 23SDK

SDK refresh: filters + batch routes across all 7 SDKs

Mirrored the new endpoint surface into every official SDK so consumers can call the new filters and batch routes through typed methods.

SDK+

Mirrored the new endpoint surface into every official SDK so consumers can call the new filters and batch routes through typed methods.

  • madeonsol (TypeScript) → 2.1.0 (npm) — kol.feed() before cursor + next_before, KolTrade.token_image_url. deployer.alerts() before / alert_type / priority / min_kol_buys. deployer.recentBonds() since / tier / peak_mc_min + next_since. New client.token namespace: get(), batch(), batchBuyerQuality().
  • madeonsol (Rust) → 0.3.0 (crates.io) — same additions on types.rs + api/{kol,deployer}.rs; new api/token.rs with Token::{get, batch, batch_buyer_quality} registered as client.token.
  • mcp-server-madeonsol → 1.2.1 — three new MCP tools (madeonsol_token_get, madeonsol_token_batch, madeonsol_tokens_batch_buyer_quality) + new filter params on madeonsol_kol_feed and madeonsol_deployer_alerts. Strategy enum corrected to scalper / day_trader / swing_trader / hodler / mixed (matches the live mv_kol_scores classifier).
  • @madeonsol/plugin-madeonsol → 1.2.0 — getToken, getTokenBatch, getTokenBuyerQualityBatch + new filter args. Bug fixes: getAlphaLinked now hits /alpha/{w}/linked (was 404'ing on /alpha/wallet/{w}/linked); getTokenCapTable + getTokenBuyerQuality now use plural /tokens/ paths.
  • solana-agent-kit-plugin-madeonsol → 1.2.0 — same additions + same path-bug fixes on alphaWallet, alphaLinked, tokenCapTable, tokenBuyerQuality. New tokenGet, tokenBatch, tokenBuyerQualityBatch functions.
  • madeonsol-x402 (npm) → 1.2.0 — KolFeedParams.before, DeployerAlertsParams.{before, alert_type, priority, min_kol_buys}, next_before in response, strategy enum corrected.
  • madeonsol-x402 (PyPI) → 1.2.0 — kol_feed(before=...) and deployer_alerts(before=, alert_type=, priority=, min_kol_buys=).

All changes backward-compatible — new params are optional, new fields are additive, new methods don't change existing signatures. Existing consumers continue to work without modification.

Apr 23Infra

gRPC stream teardown fix + dex-stream always-on

@triton-one/yellowstone-grpc moved to a native N-API client where ClientDuplexStream extends stream.Duplex and has no .cancel() method, so every reconnect path was silently no-o…

Infra+

@triton-one/yellowstone-grpc moved to a native N-API client where ClientDuplexStream extends stream.Duplex and has no .cancel() method, so every reconnect path was silently no-op'ing on teardown, leaving the subscription + TCP socket dangling. wallet-tracker (which reconnects on every wallet_watchlist_changes pg_notify) had accumulated 97 sockets to Kaldera, saturating the per-account limit and causing dex-stream subscribe attempts to be rejected with GenericFailure.

  • Replaced state.stream.cancel() → state.stream.destroy() across all 15 call sites in wallet-tracker, kol-tracker, dex-stream, and deployer-listener.
  • dex-stream no longer auto-shuts when no client is subscribed — rapid subscribe/unsubscribe churn was tripping Kaldera anti-abuse for extended windows. Now matches kol-tracker's always-on pattern, so the all-DEX firehose is ready the moment a ULTRA client connects.
  • Tightened pg pool idleTimeoutMillis (30s → 10s) and tagged application_name across the three gRPC services for cleaner DB-side observability.

Post-fix, wallet-tracker dropped from 97 → 4 sockets and dex-stream subscribes cleanly to both gRPC regions (~15k tx per 30s heartbeat).

Apr 23Infra

Dependency refresh (`@supabase/ssr` 0.9 → 0.10.2)

Routine semver-patch sweep: 17 npm packages updated (Next 16.2.4, React 19.2.5, @supabase/supabase-js 2.104.1, Tailwind 4.2.4, @x402/* 2.10.0, Resend 6.12.2, Vitest 4.1.5, other…

Infra+

Routine semver-patch sweep: 17 npm packages updated (Next 16.2.4, React 19.2.5, @supabase/supabase-js 2.104.1, Tailwind 4.2.4, @x402/* 2.10.0, Resend 6.12.2, Vitest 4.1.5, others). Plus one one-major bump worth flagging:

@supabase/ssr 0.9.0 → 0.10.2 — v0.10 propagates cache headers to setAll to prevent CDN caching of auth responses, and now respects user-provided auth options in createBrowserClient. No API signature changes — middleware.ts, supabase/client.ts, supabase/server.ts compile unchanged.

@solana/kit 5.5 → 6.8 deferred: would dedupe-invalidate against @x402/svm → @solana-program/[email protected] which peer-requires @solana/kit@^5. Risk of runtime break in the x402 subscription payment path; waiting for upstream compute-budget v6 support.

Apr 22SDK

Broken-link redirect + SDK error-message cleanup

Site

SDK+

Site

  • Added middleware rule that strips trailing ), )., ,, ;, ] from paths and 301-redirects. Rescues clicks from auto-linkified URLs in emails, terminals, and IDE tooltips that over-greedy grabbed trailing punctuation (affected /developer), /developer). among others).

SDKs — all x402 / ElizaOS variants

  • @madeonsol/plugin-madeonsol → 1.1.2 (npm)
  • madeonsol-x402 (npm) → 1.1.2 (npm)
  • madeonsol-x402 (PyPI) → 1.1.3 (PyPI)

Reworded every (free at madeonsol.com/developer) pattern in error messages, JSDoc, and docstrings to an em-dashed form — — free at https://madeonsol.com/developer — — so no terminal or email auto-linkifier grabs a trailing paren. No behaviour or API changes.

Apr 21SDK

Rust SDK launch + TypeScript SDK correctness fix

New: Official Rust SDK (crates.io)

SDK+

New: Official Rust SDK (crates.io)

cargo add madeonsol

Full-surface async client built on tokio + reqwest with rustls — no OpenSSL dependency, cross-compiles cleanly. Covers the same endpoint set as the TypeScript SDK: KOL feed/leaderboard/coordination/pairs/hot/trending/entry-order/timing/pnl, deployer alerts and leaderboards, wallet tracker, alpha wallet intelligence, and x402 discovery. Typed response structs, structured error surfacing, and the same msk_ Bearer auth as every other SDK.

TypeScript SDK v2.0.0 (npm) — correctness release

The major bump is a breaking response-type realignment:

  • KolTrade.signature → tx_signature (and sibling fields on DeployerAlert, WalletEvent, coordination wallet rows) — now matches the actual REST payload. Previous versions had drifted from the live API shape.
  • MadeOnSolError.message now surfaces the server's error field from the response body instead of the generic HTTP status text — real diagnostics in catch blocks.
  • Response types across KOL, deployer, wallet, and alpha endpoints audited against the live API and corrected.

Upgrade: npm install madeonsol@latest. If you were reading signature off trade objects, rename to tx_signature. No other call-site changes.

Apr 20API

Coordination v1.1: peak-density, exits, push alerts

The /kol/coordination endpoint got three upgrades and a new companion API for real-time push alerts.

API+

The /kol/coordination endpoint got three upgrades and a new companion API for real-time push alerts.

Richer response (backward-compatible)

  • Peak-density window: response now includes peak_window_start, peak_window_end, peak_kols, peak_buys — the densest window_minutes slice inside the full period. A cluster where 8 KOLs bought across 4 hours is very different from one where 8 KOLs bought in a 15-minute window. Now you can tell.
  • Exits: exited_count flags KOLs that net-sold the token after buying — a quiet but strong de-weight signal for copy-trading.
  • Coordination score: coordination_score (0-100) is a composite over peak density, freshness, exits, avg winrate, and strategy diversity. Use ?min_score=70 to filter for only high-conviction clusters.
  • New filters: ?window_minutes=1-60 (default 15), ?min_score=0-100 (default 60), ?include_majors=true|false (filter WIF/BONK/POPCAT noise, default false).
  • Majors are blacklisted via the coordination_excluded_mints table — contact us if you want a specific mint added.

New: Coordination Alerts API (PRO/ULTRA — 5 endpoints)

Push alerts fire within ~1s of a qualifying trade (pg_notify, not cron-poll). Delivered via WebSocket (kol:coordination, user-scoped) and/or per-rule HMAC-signed webhook.

POST   /api/v1/kol/coordination/alerts
GET    /api/v1/kol/coordination/alerts
GET    /api/v1/kol/coordination/alerts/{id}
PATCH  /api/v1/kol/coordination/alerts/{id}
DELETE /api/v1/kol/coordination/alerts/{id}

Rule fields: name, min_kols (2-50), window_minutes, min_score, include_majors, cooldown_min (60 default — de-dupe per (rule, token)), score_jump_break (10 default — re-fire inside cooldown if score jumps by N), delivery_mode (webhook / websocket / both), webhook_url. Webhook secret returned once on create — store it securely.

Limits: PRO 5 rules. ULTRA 20 rules.

SDKs

All six SDKs (TypeScript 1.11.0, Python 1.1.0, MCP 1.1.0, ElizaOS 1.1.0, Solana Agent Kit 1.1.0, madeonsol-x402 TS 1.1.0) expose the new fields on kolCoordination() and add coordinationAlerts{List,Create,Get,Update,Delete}.

Full surface on /api-docs#kol.

Apr 18API

Rate limit headers, live stats, SDK refresh

API

API+

API

  • Every response now returns X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, and X-Request-Id. Useful for client-side backoff and for support — paste the X-Request-Id in any bug report and we can trace it end-to-end.
  • Error envelopes now include a _rid watermark for the same reason.

SDKs

  • All six SDKs (TypeScript, Python, MCP, ElizaOS, Solana Agent Kit, LangChain) now support KOL entry-order queries, wallet compare, and alerts/recent.

Site

  • Live platform stats on the homepage, /developer, and /solana-api — pulled from the public stats endpoint and cached for 5 minutes.
Apr 18API

KOL API v2

New mv_kol_scores materialized view backs the entire KOL surface. Three net-new endpoints, five enriched.

API+

New mv_kol_scores materialized view backs the entire KOL surface. Three net-new endpoints, five enriched.

  • GET /kol/coordination — multi-KOL convergence signals with cluster avg winrate + distinct-strategy filters (PRO+).
  • GET /kol/hot — trending KOLs by recent momentum.
  • GET /kol/compare — side-by-side stats for up to 10 wallets.
  • GET /kol/leaderboard now supports sort=pnl|winrate|profit_factor|roi|early_entry (PRO+) and a strategy filter.
  • GET /kol/{wallet} adds include=pnl_by_token (PRO/ULTRA).

Trade retention extended to 180 days across all KOL endpoints. Full surface on /api-docs#kol.

Apr 16API

DEX Firehose v2

wss://ws.madeonsol.com/dex (ULTRA-only) now supports:

API+

wss://ws.madeonsol.com/dex (ULTRA-only) now supports:

  • Multi-subscription: subscribe to multiple filter sets over a single connection.
  • Replay: request the last N seconds on reconnect to bridge any gap.
  • Server-side filters: min_sol, token_age_max_min, min_market_cap, min_kol_tier.
  • Alt gRPC endpoint: redundant stream on a second provider for failover.

Catches roughly every swap on every major Solana DEX with sub-second latency. See DEX stream docs.

Apr 16API

Webhook signatures v2

Webhook deliveries now sign <timestamp>.<body> with HMAC-SHA256 under the X-MadeOnSol-Signature header, and include X-MadeOnSol-Timestamp. Reject any delivery older than ~5 minu…

API+

Webhook deliveries now sign <timestamp>.<body> with HMAC-SHA256 under the X-MadeOnSol-Signature header, and include X-MadeOnSol-Timestamp. Reject any delivery older than ~5 minutes to defeat replay. Verify examples in the webhooks docs.

Correction (2026-09-25): this entry originally said that v1 signatures would keep working during a transition. That was wrong: from this release every delivery was signed only with the new scheme, and the body-only v1 signature was never sent alongside it. For reference, the scheme in force since this date: X-MadeOnSol-Timestamp is unix milliseconds, regenerated on every delivery attempt; X-MadeOnSol-Signature is the lowercase hex HMAC-SHA256 (no prefix) of the timestamp, a dot and the raw request body, keyed with your webhook secret exactly as the API returned it. The 5 minute window is a check on your side; the server does not enforce one.

Apr 16Security

Security audit pass

Security+
  • XSS + SSRF hardening across all user-supplied URL inputs.
  • Scheme whitelist (http: / https: only) on every outbound fetch.
  • Input size caps + NaN guards on all numeric query params.
  • RLS enabled on all sensitive tables.
  • Tightened access on public-facing routes.
Apr 15Platform

Navbar refresh

Platform+
  • API dropdown got bordered cards for scannability.
  • The "API" section is now labelled Solana API end-to-end — the product covers the entire Solana data stack, not just MadeOnSol-specific data.
Apr 15API

v0.7.0: Wallet Tracker API

Powers the new /developer dashboard wallet panel. Full reference on /api-docs#wallet-tracker.

API+
  • POST /wallet-tracker/watch — add any Solana wallet to your watchlist.
  • GET /wallet-tracker/summary — aggregate stats for your tracked wallets.
  • GET /wallet-tracker/trades — unified recent swaps + transfers feed.
  • BASIC: 10 wallets. PRO: 50. ULTRA: 100 + live WS events.

Powers the new /developer dashboard wallet panel. Full reference on /api-docs#wallet-tracker.

Apr 14API

v0.6.0: Alpha wallet intelligence

API+
  • New human_wallets signal separates organic traders from bundle/sniper bots using our mv_alpha_wallets bot-confidence classifier.
  • Buyer quality scoring revamped: base score = avg 7d winrate of non-bot buyers with ≥3 tokens, + KOL bonuses, − bundle/bot penalties.
  • GET /tokens/{mint}/buyer-quality and GET /tokens/{mint}/cap-table now return richer breakdowns (PRO+).
  • Homepage refreshed to lead with real numbers instead of copy.
Apr 10API

v0.5.0: KOL PnL + trending tokens

API+
  • GET /kol/{wallet} — full KOL wallet profile with PnL stats and trade history.
  • GET /tokens/trending — tokens gaining KOL attention right now.
  • First version of /api-docs, llms.txt, and an OpenAPI spec for AI agents.
Apr 7Infra

Nginx buffer autofix

Production 502 outage traced to proxy_buffer_size too small for large PostgREST responses on mv_kol_scores. Fix: the health-monitor cron now automatically bumps proxy_buffer_siz…

Infra+

Production 502 outage traced to proxy_buffer_size too small for large PostgREST responses on mv_kol_scores. Fix: the health-monitor cron now automatically bumps proxy_buffer_size (capped at 128k) when it detects "upstream sent too big header" in nginx error logs, reloads nginx, and posts to system_health_checks.


Older

For releases before April 2026, see git log on the repo or the blog archive.

Keep exploring

Read the docs. Get a key. Ship the bot.

API reference Get free API keyPricingStatus