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
Solana APIWebSocket streaming

Protocol and channel list verified 2026-09-22 against the live registry.

Solana + Robinhood Chain API · real-time

WebSocket streaming
with seq, replay and 31 channels.

One socket at wss://madeonsol.com/ws/v1/stream pushes KOL trades, deployer alerts, pre-confirmation deploys, price ticks, token surges and Robinhood Chain events the moment they are confirmed. Every event frame carries a sequence number and a stable id, a client that reconnects, even after a server restart, can resume up to 60 minutes of what it missed, and pushed events never spend your daily quota.

Stream from PRO (€43/mo) Three-line integration

Heartbeat every 15 s · replay buffer 20,000 frames · slots PRO 2 / ULTRA 3 / BUSINESS 10 · stream token never expires

The stream

Counted from the live channel registry.

31
Channels

16 Solana · 15 RHC

15 s
Heartbeat

ghosts reaped in ≤ 30 s

60 min
Resume window

from storage · ~6-8 min in memory

0
Quota per frame

pushed events are free

Why stream

Polling pays twice: in latency and in quota.

A poller that asks every second spends 86,400 calls a day to learn about a few hundred events. A stream delivers each event once, when it happens, and the delivery is not a request.

Quota

Pushed events are not metered.

The daily limit meters authenticated REST calls; the stream service holds no counter and writes nothing to the request log. Mint one token at boot and receive as many frames as the channels produce.

Latency

Delivered on confirmation.

Frames ride the same internal event bus the site runs on — KOL trades and deployer alerts land within ~3 s of the on-chain transaction, sniper deploys before it confirms, surges the moment the sustain rule holds.

Recovery

Resume, and see what was not recovered.

A reconnect sends its cursor as resume and gets the missed frames back, from memory or from storage after a server restart (up to 60 min), before live frames resume. replay_end says per channel what could not be recovered.

Channels

31 channels, one connection, one tier gate each.

Solana and Robinhood Chain channels ride the same socket and the same connection slots — subscribe to a mix in one message. A channel without an explicit gate is open to any tier that can mint a stream token (PRO and above). User-scoped channels deliver only your own rules' fires. The Resume column says what a resume can rebuild from storage after a server restart.

Solana (16)

ChannelEventsWhat you getScopeGateResume
kol:tradeskol:tradeEvery buy/sell from tracked KOL wallets, with market cap and USD price at trade time.broadcastPRO+partial (no slot, fdv, liquidity, pool)
kol:coordinationkol:coordinationFires from your own coordination alert rules: multi-KOL convergence on one token with a 0-100 score.user-scopedPRO+partial (no kols[])
kol:first_toucheskol:first_touchFirst tracked-KOL buy on a token — the scout signal, filterable by scout tier.broadcastPRO+full
deployer:alertsdeployer:alert · deployer:bondTracked-deployer launches and graduations with reputation fields.broadcastPRO+partial (new deploys lack tx and dev-buy fields)
wallet_tracker:eventswallet_tracker:eventSwaps and transfers on the wallets in your own watchlist.user-scopedULTRA+full
copytrade:signalscopytrade:signalFires from your own copy-trade rules.user-scopedPRO+full
price_alert:eventsprice_alert:dip · price_alert:recoveryYour own market-cap dip / recovery alerts, evaluated every 250 ms on Solana.user-scopedPRO+full
sniper:deployssniper:deployPre-confirmation pump.fun deploys from deshred; PRO receives elite/good deployers only.broadcastULTRA+full
token:graduationstoken:graduationEvery pump.fun graduation, tracked deployer or not.broadcastPRO+in-memory buffer only
token:pricestoken:pricePer-mint price / MC ticks (~250 ms coalesced) for the mints you name.mint-scopedPRO+current price snapshot
token:lockstoken:lock (+ lifecycle, opt-in)New Streamflow / Jupiter Lock / Bonfida lock or vesting contracts. With filters.lifecycle: true also claims, cancels, closes, top-ups / extensions and the unlock schedule (upcoming within 24 h, available = claimable per the schedule, not claimed). Keeper-cranked automatic claims are hidden unless you ask for them.broadcastPRO+full (lifecycle events too, with filters.lifecycle)
token:fee_claimstoken:fee_claimpump.fun creator-fee distributions, social-handle claims, config changes.broadcastPRO+full
token:surgestoken:surge · token:revivalToken momentum fires with risk flags — see /surges.broadcastPRO+full
token:candlescandle:closed (+ candle:update, opt-in)Live 1-minute candles for the mints you name: each closed minute as it is written to our candle table (open/high/low/close price and market cap, volume, trade counts), usually 10–25 s after the minute ends. With filters.updates: true also the minute in progress, at most once per mint per second. Fully flat minutes with no trades are not sent.mint-scopedPRO+closed candles full, up to 10,000 rows; in-progress updates are not replayed
token:riskrisk:authority_changed · risk:supply_inflated (+ risk:inputs snapshot)Changes to the stored risk INPUTS of the mints you name: a mint or freeze authority revoked, a Token-2022 transfer fee changed, the first supply-inflation crossing (0.5 % / 5 %). A snapshot of the current inputs arrives on subscribe. Not a risk-band stream: the band moves with price and is computed by GET /tokens/{mint}/risk.mint-scopedPRO+full, plus a snapshot of the current inputs
wallet:scoresdeployer:tier_changed · kol:score_state_changedTier changes of the Solana deployers you name (including an unranked wallet entering a ranked tier) and categorical state changes of the KOLs you name (cold, heating up, strategy tag). Every frame carries source and computed_at: a KOL change means the recompute at that time found a new value, not that it changed at that moment.wallet-scopedPRO+full (deployer tiers + KOL state, one row budget)

Robinhood Chain (15)

ChannelEventsWhat you getScopeGateResume
rhc:kol_tradesrhc:kol_tradeTracked-KOL trades on Robinhood Chain (EVM-native fields).broadcastPRO+full
rhc:dex_tradesrhc:dex_tradeRobinhood Chain DEX firehose, token-attributed trades (Uniswap v2/v3/v4 + launchpads), ~40–55 trades/s at tip. Pair with rhc:dex_trades_unattributed for full chain coverage.broadcastULTRA+partial (no liquidity_usd, quote.usd, quote.observed_at), last 10 min, up to 10,000 rows
rhc:dex_trades_unattributedrhc:dex_trade_unattributedThe additive complement to rhc:dex_trades — trades where no single side could be named the token (e.g. WETH/USDG). Raw token_in/token_out/amount_in/amount_out, no decimals or buy/sell. Subscribe to both for full chain coverage.broadcastULTRA+partial (no liquidity_usd), last 10 min, up to 10,000 rows
rhc:new_tokensrhc:new_tokenFires once per RHC token, the moment its symbol/name/decimals resolve on-chain — not on first trade.broadcastULTRA+in-memory buffer only
rhc:copytrade:signalsrhc:copytrade:signalFires from your own RHC copy-trade rules.user-scopedPRO+partial (no traded_at)
rhc:price_alert:eventsrhc:price_alert:dip · rhc:price_alert:recoveryYour own RHC price alerts. Event-driven off the rhc:dex_trade feed (a few seconds, not the 250 ms Solana loop), with table polls and a tape replay as safety nets.user-scopedPRO+full
rhc:kol:coordinationrhc:kol:coordinationYour own RHC coordination rules.user-scopedPRO+partial (no market_cap_usd)
rhc:kol:first_touchesrhc:kol:first_touchFirst tracked-KOL buy per RHC token.broadcastPRO+full
rhc:token_locksrhc:token_lock (+ unlock schedule, opt-in)New Robinhood Chain token lock / vesting contracts, one event per lock created. With filters.lifecycle: true also the unlock schedule (upcoming within 24 h, available = claimable per the schedule, not claimed). Claims, extensions and cancels are not observable on RHC.broadcastPRO+partial (no family_name, amount, amount_pct_of_supply); unlock-schedule events full
rhc:token_pricesrhc:token_pricePer-token Robinhood Chain price ticks for the addresses you name: one snapshot per address on subscribe, then updates derived from the RHC trade feed (at most one per address per 250 ms, latest value), each stamped quality fresh / stale / unreliable with a reason.address-scopedPRO+current price snapshot
rhc:lp_eventsrhc:lp_eventRobinhood Chain liquidity events on the pools we track: adds, removals and pool creations, with the position's tick range, whether it was in range of the current price, its share of active liquidity (v3/v4) or of reserves (v2), and a material flag for removals of 25 % or more. The in-range and share fields are null when the pool's current tick was not known; the provider is usually a router or position manager.broadcastULTRA+last 60 min, up to 10,000 rows (token symbol/decimals approximate on replay)
rhc:token_candlesrhc:candle_closed · rhc:candle_revised (+ rhc:candle_update, opt-in)Live 1-minute Robinhood Chain candles for the addresses you name. A stored candle that is rewritten later (a restart merge or a spoofed-pool repair) is re-sent as rhc:candle_revised with a revision number. filters.updates: true adds the minute in progress, at most once per address per second.address-scopedPRO+closed candles full (latest revision only), up to 10,000 rows; in-progress updates are not replayed
rhc:token_riskrhc:risk_verdict_changed (+ rhc:risk_verdict snapshot)A recheck stored a different contract-risk verdict for an RHC token you name (sellable, proxy / upgradeable, owner model, mint / pause, LP custody, flags), with before / after. Detection is by a recheck sweep: the change happened somewhere between previous_checked_at and checked_at, currently days to weeks apart. Score is higher = safer.address-scopedPRO+full, plus a snapshot of the current verdict
rhc:wallet_scoresrhc:deployer_tier_changedRobinhood Chain deployer tier changes (elite / good / spammer / neutral) for the 0x deployers you name, found by the 5-minute ranking refresh — recomputed at computed_at, not changed at that moment.wallet-scopedPRO+full
rhc:dev_activityrhc:dev_activity (dev_buy · dev_sell)The recorded developer of a Robinhood Chain token buying or selling it, from the launchpad creation or (labelled pool_creator) the first pool's creator. Buys and sells only: a developer moving tokens to another wallet is never on this channel, and a developer trading from a different wallet is not linked. Live since 2026-10-05; a reconnect replays only events still in memory.broadcastULTRA+in-memory buffer only (no durable store yet)

RHC frames carry EVM-native fields (lowercase 0x addresses, eth_amount, tx_hash) — do not reuse a Solana deserializer unchanged. The Solana all-DEX firehose (14 programs) is a separate endpoint, wss://madeonsol.com/ws/v1/dex-stream, on Ultra and Business; what teams build on it is covered under real-time DEX data. Since 2026-09-22 it also serves a per-pool view: subscribe with legs: true and each transaction arrives as one dex:route (hops, shape, decoded_complete, the programs we could not decode, the signer's net) plus one dex:leg per pool swap (program, venue, pool, vaults, exact raw amounts in and out, a stable leg_id of signature:instruction[.inner]), and the unchanged dex:trades frame once. Liquidity deposits and withdrawals are never a leg: since 2026-09-23 they have their own opt-in view, liquidity: true (or "only"), one dex:liquidity frame per pool creation, add or remove with raw amounts, vault reserves before and after, the share of reserves on constant-product pools and a material flag for removals of 25 % or more. Only instructions verified against a real transaction are emitted; concentrated pools report depth as unknown, there is no USD value, and replay comes from the in-memory buffer only. Protocol in the API docs.

ShredPrism (ULTRA+) uses a separate low-latency endpoint, wss://madeonsol.com/ws/v1/early, advertised as early_ws_url by the same stream-token call. It serves six supported outer-instruction families: early:deploys, early:locks, early:trades, early:liquidity, early:migrations and early:token_changes. Observations are provisional instruction intent; execution outcomes follow separately. Exact per-family fields, supported instructions, recovery and filters are in the ShredPrism contract, with measured client-side benchmarks on the solution page.

Since 2026-10-05 the DEX socket also carries realtime developer activity: send {"type":"dev_subscribe","filters":{"token_mints":[],"deployers":[],"types":[]}} and receive dev:activity when an attributed token's developer sells, buys or moves their own token (dev_sell, dev_buy, dev_token_transfer_out, dev_token_transfer_in; a transfer is never a sell), followed by dev:activity_enrichment with the same id. Transfer detection is the union of the legacy bounded wallet watch and the broad SPL Token/Token-2022 candidate source for attributed creators while that source is live. transfer_watch_coverage describes only the legacy watch, not total transfer coverage; the ack's transfer_sources reports broad-source state/gaps. Missing creator attribution, recorded source gaps and unsupported mixed swap+standalone-transfer cases can still produce misses. PRO+ can receive the same direct-developer events through the HMAC-signed dev:activity webhook; ULTRA+ gets the low-latency DEX-socket path and identity stitching. Also since 2026-10-05, swaps paid in USDC or USDT are sized by their stable leg on dex:trades: sol_amount is the SOL equivalent, with sol_amount_basis and stable_quote describing how it was derived.

Protocol

seq, id, replay, heartbeat, slots, token.

Everything a reconnect loop needs to know, in the order it will meet it.

Ordering

seq and id on every event frame.

seq is one ordinal per server process, shared by all channels and all customers and assigned before your filters run, so gaps in the seq you receive are normal and are not evidence of loss. id is a stable identity for dedupe across reconnects, derived from the transaction signature or hash where the payload has one. token:price ticks carry neither. The connected frame carries the current seq, an instance id and the replay window; if the instance changes the server restarted and seq reset, so never compare seq across instances. The same event keeps the same id live, from memory and from storage: delivery is at-least-once, so dedupe by id.

Resume

Memory first, then storage, honest about gaps.

Subscribe with resume: {instance, seq, ts}, the last frame your handler finished. Same instance and inside the 20,000-frame buffer (~6-8 min): re-sent from memory. Otherwise each channel is rebuilt from storage from ts (up to 60 min, 2,000 rows per channel, 20,000 total) as seq: null, mode: "durable" frames; channels with no stored source get an explicit gap. replay_end reports sent, complete, retryable, a reason and a watermark per channel. Commit your cursor only on complete: true or on final gaps; after a retryable incomplete recovery, resume again from the old cursor. Recovery is bounded, never a completeness guarantee. The older replay_since_seq / replay_since_ts fields still work, from memory only.

Liveness

Heartbeat every 15 s.

A {"type":"heartbeat"} frame plus a protocol ping every 15 s; a socket that does not pong by the next tick is closed 1006 ping-timeout, so a half-open ghost is gone within ~15–30 s. Miss two heartbeats: reconnect and resume.

Connection slots

PRO 2 · ULTRA 3 · BUSINESS 10.

Enforced in memory per key. A refused reconnect closes 4002 naming how long the holder has been connected; GET /api/v1/stream/sessions lists your live sessions and DELETE /api/v1/stream/sessions/{id} frees a slot yourself. The DEX firehose has its own slots (ULTRA 2, BUSINESS 5).

Named subscriptions

PRO 5 · ULTRA 10 · BUSINESS 20 per connection.

A subscribe with sub_id opens a subscription with its own channels and filters on the same socket; update, unsubscribe and list address it by that id. Frames under it carry sub_id; an event matching several subscriptions is delivered once per subscription (dedupe by sub_id + id). The cap counts the default subscription too; above it the subscribe is refused with too_many_subscriptions.

Credential

The stream token never expires.

Since 2026-08-27 POST /api/v1/stream/token returns the same token on every call; expires_at is always null. It ends only when the plan lapses (cut within ~6 min) or you send {"rotate":true} — the old value then works for 60 s and live sockets get a token_refresh frame. Present as Authorization: Bearer (preferred) or ?token=, masked in our access logs. A 4001 means mint again, never a timer.

Subscribe

Nothing arrives until you subscribe.

Send {"type":"subscribe","channels":[...],"filters":{...}} after connect; the server sends a hint frame after 10 s if no channel is active. Filters are server-side and connection-wide: one filter object applies to every channel on the socket (a later subscribe with filters replaces it), so {"action":"buy"} also drops deployer alerts, whose payload has no buy action. Use a second connection for channels that need different filters. A rejected channel comes back in channels_rejected with the reason, never a silent partial subscribe.

Integration

Three lines from a key to live frames.

curl for the token, wscat for the socket, one JSON line to subscribe. The SDKs wrap the same three steps with auto-reconnect and typed events.

shell · token, connect, subscribe
TOKEN=$(curl -s -X POST https://madeonsol.com/api/v1/stream/token -H "Authorization: Bearer msk_YOUR_KEY" | jq -r .token)
wscat -c wss://madeonsol.com/ws/v1/stream -H "Authorization: Bearer $TOKEN"
> {"type":"subscribe","channels":["kol:trades","sniper:deploys","token:surges"],"filters":{"min_sol":1}}
frames · what comes back
{"type":"connected","seq":48211,"instance":"a1b2c3d4e5f6","replay":{"oldest_seq":28212,"newest_seq":48211,"size":20000}}
{"type":"subscribed","channels":["kol:trades","sniper:deploys","token:surges"],"seq":48211}
{"channel":"kol:trades","event":"kol:trade","seq":48212,"id":"kol:trade:5Kd…","data":{...},"ts":1756382400123}
{"type":"heartbeat","ts":1756382415123}
// reconnect later with the last frame you processed:
{"type":"subscribe","channels":["kol:trades"],"resume":{"instance":"a1b2c3d4e5f6","seq":48212,"ts":1756382400123}}
{"type":"subscribed","channels":["kol:trades"],"resume":{"instance":"a1b2c3d4e5f6","seq":48212,"ts":1756382400123,"accepted":true},...}
{"type":"replay_start","mode":"ring","count":37,"replay_truncated":false,...}
{"type":"replay_end","sent":37,"matched":37,"complete":true,"reason":null,"live_from_seq":48290,"channels":{"kol:trades":{"mode":"ring","sent":37,"matched":37,"complete":true}},...}
typescript · madeonsol 2.28
import { MadeOnSol } from "madeonsol";
const client = new MadeOnSol({ apiKey: "msk_YOUR_KEY" });
const stream = await client.stream.connect();   // getToken() on every (re)connect, auto-backoff
stream.on("kol:trade", (t) => console.log(t.token_symbol, t.action));
stream.on("token:surge", (e) => console.log(e.tier, e.symbol, e.risk_flags));
python · madeonsol-x402 1.30 (pip install "madeonsol-x402[stream]")
from madeonsol_x402 import MadeOnSolClient
client = MadeOnSolClient(api_key="msk_YOUR_KEY")
stream = client.stream()

@stream.on("kol:trade")
async def on_trade(t): print(t["token_symbol"], t["action"])

The alternative

Webhooks, when you cannot hold a socket.

Serverless, cron-shaped or behind a strict egress policy: register a URL instead. The registry accepts 11 event types; rule engines (copy-trade, price alerts, coordination, first-touch) deliver from the rule's own URL with a per-rule secret.

Events

11 registry events

kol:trade · kol:coordination · deployer:alert · deployer:bond · wallet_tracker:event · sniper:deploy · rhc:kol_trade · token:surge · token:revival · dev:activity · rhc:dev_activity

Delivery

Signed, retried, self-reporting.

HMAC-SHA256 in x-madeonsol-signature. 3 retries at 5 s / 30 s / 2 min. Auto-disabled after 10 consecutive failures — and the owner is emailed, not just us. A new webhook starts receiving within ≤ 15 s.

Limits

PRO 3 · ULTRA 10 · BUSINESS 30

Same server-side filters as the stream where the event supports them. The RHC DEX firehose is WebSocket-only; price-alert events are not registry events — they deliver per rule.

Honest limits

What the stream is not.

Read before you design around it.

token:prices

Mint-scoped, capped at 25 / 100 / 250 mints.

filters.mints is required; a subscribe above the cap is rejected, not truncated. Ticks are ~250 ms coalesced pricing updates, not per-trade — per-trade is the ULTRA firehose.

Resume depth

Up to 60 minutes, and not every field.

A resume rebuilds at most 60 minutes and 2,000 rows per channel (the RHC DEX firehose channels 10 minutes and up to 10,000 rows). Some channels are rebuilt partially (fields listed in missing) and two, token:graduations and rhc:new_tokens, only from memory. Past that, backfill from REST. A row is stamped when it is written, not when it commits, so the server holds your committable position a few seconds back and re-scans the last minute on the next resume: a write that commits more than about a minute after it was stamped can still be missed (about 6 minutes while a long-running transaction has the hold-back capped), and the RHC DEX trade channels are bounded by the producer's 600 s freshness rule. Each channel states its own bound in watermark.guarantee. For hours of replay on raw chain data use gRPC from an RPC provider (Helius publishes 24 h) and decode yourself.

RHC price alerts

Event-driven, a few seconds.

RHC price alerts are evaluated off the rhc:dex_trade feed as trades land, with 5 s / 60 s table polls and a tape replay as safety nets. The chain's trade flush (about 2 s today) sets the floor, so do not expect the 250 ms evaluation loop of the Solana alerts.

PRO curation

sniper:deploys is curated on PRO.

PRO receives elite/good-tier deployers only, applied per message at delivery; ULTRA receives every tier plus custom watchlists. See /sniper.

Pricing for context: PRO €43/mo, ULTRA €131/mo (adds the all-DEX firehose), BUSINESS €400/mo (embed license, 10 slots). Competitors' parsed WebSocket starts at $199 (Birdeye), $350 (Codex) and €397 (Solana Tracker), verified 2026-08-16. Showing these feeds to your own users is covered in the data behind a terminal's chart, candles and trade tape.

FAQ

Streaming questions, answered.

Do WebSocket events count against my API quota?+
No. The daily and per-minute limits meter authenticated REST requests; a frame pushed over the stream is not a request and is never written to the request log. The only REST call involved is POST /api/v1/stream/token, which has its own 10-per-minute bucket exempt from the daily and burst pools, and since 2026-08-27 returns the same token forever, so a client calls it once at boot. A PRO key with 10,000 calls/day can receive an unlimited number of pushed events.
How do seq, id and replay work?+
Event frames carry seq and id; token:price ticks carry neither. seq is one ordinal per server process, shared by every channel and every customer and assigned before your filters run, so the seq values you receive have gaps in normal operation: a gap is not evidence of loss. id is stable: the same event has the same id when it is delivered live, replayed from memory or rebuilt from storage, so delivery is at-least-once and you dedupe by id. To recover, keep a cursor {instance, seq, ts} of the last frame your handler finished processing (the handler returned, or its promise settled) and reconnect with subscribe { ..., resume: {instance, seq, ts} }. The subscribed ack echoes the cursor with accepted: true. If the server is the same instance and the cursor is still inside its in-memory buffer (the last 20,000 frames, about ~6-8 min), the missed frames are re-sent from memory. Otherwise (the server restarted, or you were away longer) each channel is rebuilt from storage from your cursor's ts: at most 60 minutes back, 2,000 rows per channel and 20,000 in total. Rebuilt frames carry seq: null and mode: "durable", plus partial: true and missing[] where a field is not stored. Everything is bracketed by replay_start and replay_end, and replay_end states per channel what was sent, whether it is complete and why not. Frames that arrive live meanwhile are held and delivered after replay_end, skipping ids already sent. The older replay_since_seq / replay_since_ts fields still work and replay from memory only; they now report replay_truncated with a reason when the cursor is too old or from a previous server instance. Save your cursor only when a recovery completes: replayed frames arrive channel by channel, so on replay_end complete: true commit last_seq / last_ts, and on complete: false with retryable: true keep the old cursor and resume again after retry_after_ms (duplicates are dropped by id). A resume_ts_hint is only sent when every incomplete channel that a retry could still fill hit the row cap (a permanently missing channel does not block it); without a hint, resume from the cursor you already had. Gaps reported with retryable: false are final; backfill them from REST. When many clients resume at once, a resume can wait up to 20 s and then get reason source_busy with a retry time. How far your cursor may move is also limited by a per-channel watermark (replay_end.channels.<channel>.watermark, and watermark_safe_ts overall): a row is stamped when it is written, not when it commits, so the server only lets you commit across rows whose write had finished, holds the watermark 5 s behind now and re-scans the last 60 s on your next resume. Frames are still delivered as they are read. Recovery is bounded, not a completeness guarantee: each channel states its own bound in watermark.guarantee, a write that commits more than about 65 s after it was stamped can be missed (about 6 minutes instead while holdback_capped_ms is set), and the Robinhood Chain DEX trade channels are bounded by the producer's 600 s freshness rule, so a trade already older than 600 s when it was ingested is not recoverable that way at all. Our SDKs apply all of this for you: they retry a retryable recovery (up to 5 times per connection, with the counter reset on every reconnect; after that the gap says exhausted: true and the next reconnect picks it up) and, on a final gap, report the channels, the reason and the RANGE that may be incomplete before moving the cursor past it. That last step is the library's own decision, not your approval, and onUnrecoverableGap: "stop" turns it off. The number of missing events is never stated, because it cannot be known.
Does the stream token expire?+
No, since 2026-08-27. POST /api/v1/stream/token returns the same token on every call, forever; expires_at and next_refresh_at are always null. It stops working only when the subscription is no longer an active PRO/ULTRA/BUSINESS plan, or when you explicitly send {"rotate": true} — after which the previous value keeps working for 60 seconds and live sockets receive a token_refresh frame. Present it as Authorization: Bearer <token> on the handshake (preferred) or ?token=; an msk_ API key is never accepted as a stream token and is closed with an explicit reason. A 4001 close means mint again, never a timer.
How many connections can I hold?+
PRO 2, ULTRA 3, BUSINESS 10 concurrent connections on the main stream, enforced in memory by the service. PRO was raised from 1 to 2 on 2026-08-16 because with a single slot a reconnecting client evicts its own live socket. When a reconnect is refused the 4002 close reason names how long the holder has been connected; GET /api/v1/stream/sessions lists your live sessions and DELETE /api/v1/stream/sessions/{id} frees a slot without support. The DEX firehose (wss://madeonsol.com/ws/v1/dex-stream) is a separate endpoint with its own slots: ULTRA 2, BUSINESS 5.
What is the heartbeat and when should I reconnect?+
The server sends a {"type":"heartbeat"} frame and a protocol ping every 15 seconds and terminates a socket that does not answer the ping by the next tick (close code 1006, ping-timeout). If you miss two heartbeats, reconnect and pass your resume cursor on the subscribe. Nothing is delivered until you send a subscribe message; the server sends a hint frame after 10 s if no channels are active.
What are the limits of token:prices?+
token:prices is mint-scoped: filters.mints is required and capped per connection at 25 mints on PRO, 100 on ULTRA and 250 on BUSINESS. A subscribe above the cap is rejected outright, never truncated, so you never silently watch fewer mints than you asked for; a later subscribe replaces the watched set. Ticks are the pricing bus's ~250 ms coalesced updates — the same feed the site's charts run on — not per-trade. Per-trade delivery across all 14 DEX programs is the ULTRA DEX firehose.
Can one connection hold several subscriptions with different filters?+
Yes. A subscribe carrying a sub_id (1-64 characters of A-Z a-z 0-9 _ . -) opens a named subscription with its own channels and filters; update {sub_id, filters} replaces its filters, unsubscribe {sub_id} removes it, and list returns every subscription the socket holds. A subscribe without sub_id is the connection's default subscription, unchanged from before. Frames delivered under a named subscription carry sub_id, and an event that matches several subscriptions is delivered once per subscription, each copy stamped with its sub_id, so dedupe by sub_id plus id. Filters of one subscription never affect another. The cap counts every subscription on the connection, the default one included: PRO 5, ULTRA 10, BUSINESS 20; above it the subscribe is refused with a warning (too_many_subscriptions), never silently dropped. Resume works per subscription: on reconnect send every subscribe with the same cursor, the server serves the replays one after another and holds live frames until the last replay_end, and you commit the cursor at the smallest last_seq across them. The SDKs expose this as subscribe({ subId, channels, filters }), updateSubscription, unsubscribe(subId) and listSubscriptions (snake_case in Python).
Should I use webhooks instead?+
Use webhooks when you cannot hold a socket open (serverless, batch jobs). The registry accepts 11 event types (kol:trade, kol:coordination, deployer:alert, deployer:bond, wallet_tracker:event, sniper:deploy, rhc:kol_trade, token:surge, token:revival, dev:activity, rhc:dev_activity); payloads are HMAC-SHA256 signed in the x-madeonsol-signature header, retried 3 times (5 s, 30 s, 2 min) and auto-disabled after 10 consecutive failures, with the owner emailed. PRO 3, ULTRA 10, BUSINESS 30 webhooks. Copy-trade, price-alert, coordination and first-touch rules deliver from the rule's own webhook_url with a per-rule secret, not through this registry; the RHC DEX firehose is WebSocket-only.
How does this compare to other providers' streaming?+
Parsed real-time delivery starts at €43/month here (2 connections, 31 channels) and the full all-DEX firehose at €131/month; Birdeye unlocks WebSocket at $199, Codex at $350, Solana Tracker's Datastream at €397 (all verified 2026-08-16). Helius gRPC offers 24-hour replay and Bitquery Kafka 4 hours — both deeper than our resume window of up to 60 minutes, but on raw or partially decoded data; among parsed WebSocket vendors we found none that publishes a per-event seq and client-side replay. If you need hours of replay on raw chain data, gRPC from an RPC provider is the better tool.

Included with ULTRA+

Your wallets. Six early Solana signal families.

ShredPrism brings launches, wallet trade intent, locks, liquidity, migrations and token changes into a filtered WebSocket feed. Save private wallet lists, follow known tokens and correlate separate execution outcomes. ULTRA starts at €131/month.

Supported instructions only. Observations are provisional; no fixed timing lead is promised.

Explore ShredPrism and its benchmarks →

More for developers

ShredPrism stream

Six early Solana families, private wallet lists and transparent benchmarks. ULTRA+.

Token surge & revival alerts

Momentum fires with risk flags and out-of-sample +1h outcomes.

Early launch signals

ULTRA+ ShredPrism signals for supported pump.fun and LaunchLab instructions, with execution outcomes reported separately.

MCP servers & SDKs

Two MCP servers, 14 packages, one free key.

Full surface: Solana API overview, Robinhood Chain API, endpoint docs and the 9-provider data API comparison.

Start building

Stop polling. Subscribe.

31 channels from PRO at €43/month; the all-DEX firehose from ULTRA at €131/month. Pushed events never spend quota.

See plans & pricing Endpoint docs