madeonsol 2.14.0 → 2.15.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,1222 +1,1239 @@
1
- # madeonsol
2
-
3
- [![npm version](https://img.shields.io/npm/v/madeonsol?style=flat-square)](https://www.npmjs.com/package/madeonsol)
4
- [![npm downloads](https://img.shields.io/npm/dm/madeonsol?style=flat-square)](https://www.npmjs.com/package/madeonsol)
5
- [![GitHub stars](https://img.shields.io/github/stars/LamboPoewert/madeonsol-sdk?style=flat-square&logo=github)](https://github.com/LamboPoewert/madeonsol-sdk)
6
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.4+-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
- [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square)](package.json)
8
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)
9
-
10
- > ⭐ **[Star on GitHub](https://github.com/LamboPoewert/madeonsol-sdk)** if you find this useful · 📂 **[Examples](./examples/)** · 📚 **[API docs](https://madeonsol.com/api-docs)**
11
-
12
- Official TypeScript/JavaScript SDK for the **[MadeOnSol](https://madeonsol.com) Solana API** — zero dependencies, fully typed, works in Node.js ≥ 18 and edge runtimes.
13
- > Real-time Solana trading intelligence: track 1,069 KOL wallets with <3s latency, score 23,000+ Pump.fun deployers, surface deshred deploy signals **~500ms before on-chain confirmation**, detect multi-KOL coordination, score token rug-risk 0–100 with a transparent factor breakdown, push every pump.fun graduation the second it bonds, and stream every DEX trade across 9+ programs. Free tier: 200 requests/day at [madeonsol.com/pricing](https://madeonsol.com/pricing) — no credit card required.
14
-
15
- > **New in 2.14.0** — **OHLCV candles + net flow.** `client.alpha.candles(mint, { tf, limit, from, to })` returns the persisted price/MC trajectory as candlesticks (`1m`/`5m`/`15m`/`1h`/`4h`/`1d`, rolled up on read). **PRO**: OHLCV (`open`/`high`/`low`/`close`/`volume_usd`/`trades`/`market_cap_usd`), last 30 days. **ULTRA**: adds per-bar net flow (`buy_volume_usd`/`sell_volume_usd`/`net_volume_usd`, `buy_count`/`sell_count`, `volume_mev_usd`), liquidity delta (`open_liquidity_usd`/`close_liquidity_usd`) and full history `net_flow_included` flags which set you got. New types: `Candle`, `CandlesResponse`, `CandlesParams`, `CandleTimeframe`.
16
- >
17
- > **New in 2.13.0** — **Token risk score.** `client.alpha.risk(mint)` returns a transparent 0–100 rug-risk/safety score (higher = riskier) for any token: a `band` (`safe`/`caution`/`danger`), an explainable `factors[]` array (each with `key`, `label`, `status`, `points`, `detail`) that sums into the score, and the raw `inputs` it was computed from — mint/freeze authority revocation, liquidity USD + liquidity-to-MC ratio, transfer fee bps, Token-2022 flag, burn detection, launch cohort (SOL + size), deployer bond rate + total deployed, KOL signal, and blacklist status. Plus `score_version` and `as_of`. **PRO/ULTRA only.** New types: `TokenRiskResponse`, `TokenRiskFactor`, `TokenRiskInputs`, `TokenRiskBand`, `TokenRiskStatus`.
18
- >
19
- > **New in 2.12.0** — **Launch cohort, liquidity/MC ratio, deployer tier filter, KOL hold stats, and signal performance.** `TokenResponseBody` (single + batch) gains `liquidity_to_mc_ratio`, `launch_cohort_sol`, and `launch_cohort_size`. `client.token.list()` adds `min_liq_mc_ratio`, `max_liq_mc_ratio`, and `deployer_tier` filter params; list items gain `liquidity_to_mc_ratio` and `deployer_tier`. `KolLeaderboardEntry` gains `median_hold_minutes_30d` and `percentile_early_entry_30d`. New top-level method `client.getSignalPerformance(name)` calls `GET /signals/{name}/performance`.
20
- >
21
- > **New in 2.11.1** — **Deployer runner-rate fields.** Sniper deploys, deployer alerts/profiles, and leaderboard rows now carry `runner_rate` (fraction of the deployer's labeled tokens that ran peak ≥60min after deploy vs dumped) and `labeled_tokens` (confidence denominator; gate on ≥3).
22
- >
23
- > **New in 2.11** — **Graduation events + dump-cluster detection.** Subscribe `token:graduations` for every pump.fun bond in real time — tracked deployer or not — with typed `GraduationEvent` payloads (mint, deployer tier, time-to-bond, MC at bond). Buyer-quality `breakdown` adds `dump_cluster_count` (out-of-sample validated: 3+ such wallets in the first-20 94% dump vs 61% base) and `recycled_early_buyer_count` (high count with zero cluster leans runner). DEX firehose: replay buffer deepened to ~5 minutes; mint-scoped subs now receive in-band `dex:graduations` frames — the bond lands on the same connection as your position's trade flow.
24
-
25
- > **New in 2.9** — **Deshred Sniper Alerts.** `client.sniper.recent()` surfaces new pump.fun deploys reconstructed from shred-level data ~500ms before the chain confirms them a measured head start over any confirmed-stream feed. PRO sees elite/good deployers; ULTRA sees every tier and maintains a custom deployer watchlist (`client.sniper.addToWatchlist()`). Use the `sniper:deploys` WebSocket channel or `sniper:deploy` webhook for live push instead of polling.
26
- >
27
- > **New in 2.8** — **Price alerts, scout leaderboard, wallet derived stats.** `client.priceAlerts.*` CRUD for token MC dip/recovery alerts delivered via webhook or WebSocket (PRO=5, ULTRA=25). `client.kol.scoutLeaderboard()` top scouts ranked by first-touch follow-on rate. `client.kol.coordinationHistory()` and `client.token.peakHistory()` expose the historical record. `client.wallet.stats()` now returns a `derived` block: `win_rate`, `roi`, `verdict`, and `biggest_miss`.
28
- >
29
- > **New in 2.7** — **Universal Wallet API.** `client.wallet.stats()`, `client.wallet.pnl()`, `client.wallet.positions()`, `client.wallet.trades()` — FIFO cost-basis PnL, open positions hydrated with live prices, and cursor-paginated raw trades for **any** Solana wallet (not just curated KOLs). PRO+. Server-side cache (5min/1h/24h based on activity) cache hits don't count against your quota.
30
- >
31
- > **New in 2.6.1** *(2026-05-13)* — **Velocity types fixed.** Velocity fields are now correctly typed as `mc_change_pct`, `volume_usd`, `mev_volume_pct` — each its own object keyed by `5m`/`15m`/`1h`/`2h`/`4h` to match the actual API response. The 2.6.0 shape (`velocity[window].mc_change_pct`) was wrong; clients reading it would get `undefined`. Patch is type-only no runtime breaking changes.
32
- >
33
- > **New in 2.6.0** *(2026-05-12)* — **Token directory + self-inspection.** `client.token.list({ min_liq, min_volume_1h_usd, max_mev_share_pct, mc_change_1h_min_pct, sort, ... })` — browse and filter every active mint, with default `min_liq=2000` to skip phantom-MC dust. `client.me()` — read your tier, daily/burst quota state, and per-feature usage in one call (no header parsing). Velocity / MEV-share fields added to every `TokenResponseBody`: `mc_change_pct`, `volume_usd`, `mev_volume_pct` (each keyed by `5m`/`15m`/`1h`/`2h`/`4h`) plus `history_age_seconds` on the parent. `/token/{mint}` 400s now ship `code`, `reason`, `received_length`, `example`, and `docs` URL stop guessing why a mint failed. Deprecated `avg_entry_mc_usd` / `entry_mc_samples` removed from leaderboard types. All other 2.5.x APIs unchanged.
34
-
35
- > **Build Solana trading bots, analytics dashboards, KOL copy-trading tools, deshred sniper bots, and ecosystem browsers.**
36
-
37
- ## Quick start (10 seconds)
38
-
39
- ```bash
40
- npm install madeonsol
41
- ```
42
-
43
- ```ts
44
- import { MadeOnSol } from "madeonsol";
45
- const client = new MadeOnSol({ apiKey: "msk_..." }); // free tier at madeonsol.com/pricing
46
- const { trades } = await client.kol.feed({ limit: 5, action: "buy" });
47
- ```
48
-
49
- | Feature | Description |
50
- |---|---|
51
- | **KOL Tracker** | Real-time trade feed, PnL leaderboard with five time windows (today, 7d, 30d, 90d, 180d), coordination detection, per-wallet profiles, and deep PnL analytics for 1,069 tracked KOL wallets. **180 days of trade history** retained. |
52
- | **Deshred Sniper** | Deploy feed reconstructed from shred-level data — surfaces new pump.fun launches **~500ms before on-chain confirmation**. PRO: elite/good deployers. ULTRA: all tiers + custom watchlist. Use WebSocket/webhook for live push. |
53
- | **Alpha Wallet Intel** | Leaderboard of 1M+ scored early-buyer wallets, full wallet profiles, linked-wallet clustering, token cap-table enrichment, and 0–100 buyer quality scores with dump-cluster wallet detection. |
54
- | **Token Risk Score** | Transparent 0–100 rug-risk/safety score per token with a `safe`/`caution`/`danger` band, explainable factor breakdown, and the raw inputs (authorities, liquidity, transfer fee, launch cohort, deployer bond rate, KOL signal, blacklist). PRO/ULTRA. |
55
- | **Universal Wallet** | FIFO cost-basis PnL, open positions (hydrated with live prices), and raw trade history for **any** Solana wallet not just curated KOLs. 90-day window, server-side cache. PRO+. |
56
- | **Price Alerts** | Token MC dip/recovery alerts delivered via WebSocket or HMAC-signed webhook. PRO: 5 rules, ULTRA: 25. |
57
- | **Wallet Tracker** | Monitor any Solana wallet for swaps and transfers. Track up to 10/50/100 wallets (Free/Pro/Ultra). Full wallets, counterparties, and tx_signatures on every tier. 120-day event retention. WS events on ULTRA. |
58
- | **Deployer Hunter** | 23,000+ pump.fun deployers scored by bonding rate tier leaderboard, deploy alerts, deployer profiles, and best-tokens feed. |
59
- | **DEX Trade Stream** | Real-time WebSocket stream of ALL Solana DEX trades across 9+ programs filter by token, wallet, DEX, deployer tier, or trade size. ~5 min replay + in-band graduation frames on mint-scoped subs. ULTRA. |
60
- | **Webhooks** | Push notifications for KOL trades, coordination signals, deployer alerts, and wallet tracker events (Pro/Ultra) |
61
- | **Tool Directory** | Search 1,070+ Solana tools and dApps indexed on MadeOnSol |
62
-
63
- **Links:** [Full docs](https://madeonsol.com/solana-api) · [Website](https://madeonsol.com) · [API docs](https://madeonsol.com/api-docs)
64
-
65
- ## Authentication
66
-
67
- Get a free API key at [madeonsol.com/pricing](https://madeonsol.com/pricing). Keys start with `msk_`.
68
-
69
- ---
70
-
71
- ## Install
72
-
73
- ```bash
74
- npm install madeonsol
75
- # or
76
- yarn add madeonsol
77
- # or
78
- pnpm add madeonsol
79
- ```
80
-
81
- Requires **Node.js ≥ 18** (uses native `fetch`). Works out of the box in Cloudflare Workers, Vercel Edge, and Bun.
82
-
83
- ---
84
-
85
- ## Quick start
86
-
87
- ```ts
88
- import { MadeOnSol } from "madeonsol";
89
-
90
- const client = new MadeOnSol({ apiKey: "msk_your_api_key_here" });
91
-
92
- // Latest KOL buy trades
93
- const { trades } = await client.kol.feed({ limit: 10, action: "buy" });
94
- console.log(trades[0].kol_name, "bought", trades[0].token_symbol);
95
-
96
- // Deshred sniper — ~500ms before on-chain confirmation (PRO/ULTRA)
97
- const { deploys } = await client.sniper.recent({ limit: 20, min_bond_rate: 0.5 });
98
- console.log(deploys[0].token_name, "deployed by", deploys[0].deployer_tier, "tier deployer");
99
-
100
- // Multi-KOL coordination signal
101
- const { coordination } = await client.kol.coordination({ min_kols: 3, min_score: 70 });
102
-
103
- // FIFO PnL for any wallet (PRO+)
104
- const pnl = await client.wallet.pnl("ASVz...ybJk");
105
- console.log(`Realized: ${pnl.summary.realized_sol} SOL · Win rate: ${(pnl.summary.win_rate! * 100).toFixed(1)}%`);
106
-
107
- // Search Solana tools
108
- const { tools } = await client.tools.search({ q: "trading", limit: 10 });
109
- ```
110
-
111
- ---
112
-
113
- ## Use cases
114
-
115
- - **Copy-trading bot** — stream KOL buys via `client.kol.feed()` and mirror trades
116
- - **Deshred sniper** — `client.sniper.recent()` or subscribe to `sniper:deploys` WebSocket for ~500ms pre-confirm deploy signals
117
- - **DEX trade sniping** — subscribe to the all-DEX stream filtered by token, wallet, or deployer tier
118
- - **Graduation sniper / position manager** — subscribe `token:graduations` for every pump.fun bond in real time, or hold a mint-scoped firehose sub and get the bond in-band with your position's trade flow
119
- - **Coordination detector** — flag tokens with `client.kol.coordination({ min_kols: 3, min_score: 70 })`
120
- - **Scout signal** — track first-KOL-touch events filtered to S/A-tier scouts via `client.kol.firstTouches({ preset: "scout" })`
121
- - **Rug-risk gate** — score a token with `client.alpha.risk(mint)` and skip anything in the `danger` band before buying
122
- - **Wallet analyser** — `client.wallet.pnl()` for FIFO cost-basis PnL on any Solana wallet
123
- - **Price alert bot** — `client.priceAlerts.create()` for MC dip/recovery alerts delivered via webhook
124
- - **Analytics dashboard** — combine leaderboard, PnL, token velocity, and tool data
125
- - **Telegram/Discord bot** — pipe alerts via webhooks into chat
126
- - **Portfolio tracker** — use `client.kol.wallet()` to follow specific KOL positions
127
-
128
- ---
129
-
130
- ## API Reference
131
-
132
- ### KOL Tracker — `client.kol`
133
-
134
- #### `client.kol.feed(params?)`
135
-
136
- Live feed of trades made by tracked KOL wallets.
137
-
138
- ```ts
139
- const { trades, count } = await client.kol.feed({
140
- limit: 50, // 1–100, default 50
141
- action: "buy", // "buy" | "sell"
142
- kol: "7xKX...", // filter by specific wallet
143
- });
144
- ```
145
-
146
- Returns: `KolFeedResponse` — `{ trades: KolTrade[], count: number }`
147
-
148
- Each `KolTrade` includes `market_cap_usd_at_trade` and `price_usd_at_trade` — the token's MC and price at the exact moment the swap fired, sourced from our in-memory price tracker (real-time, faster than Dexscreener spot). Use these to surface "KOL bought $X SOL of token at $Y MC" without a second lookup.
149
-
150
- ---
151
-
152
- #### `client.kol.leaderboard(params?)`
153
-
154
- KOL PnL leaderboard ranked by realized profit.
155
-
156
- ```ts
157
- const { leaderboard, period } = await client.kol.leaderboard({
158
- period: "7d", // "today" | "7d" | "30d" | "90d" | "180d", default "7d"
159
- });
160
- ```
161
-
162
- > **180-day retention** — KOL trade data is retained for 180 days (extended from 31 on 2026-04-07). The 90d and 180d windows fill up over time as the trade table accumulates.
163
-
164
- Each `KolLeaderboardEntry` includes `median_hold_minutes_30d` (median position hold duration in minutes over the last 30 days) and `percentile_early_entry_30d` (early-entry percentile rank 0–100 over the last 30 days).
165
-
166
- Returns: `KolLeaderboardResponse`
167
-
168
- ---
169
-
170
- #### `client.kol.wallet(wallet, params?)`
171
-
172
- Full profile for a single KOL wallet, including trade history and optional per-token PnL breakdown.
173
-
174
- ```ts
175
- const profile = await client.kol.wallet("7xKX...", {
176
- include: "pnl_by_token",
177
- });
178
- ```
179
-
180
- Returns: `KolWalletProfile`
181
-
182
- ---
183
-
184
- #### `client.kol.coordination(params?)`
185
-
186
- Detect tokens where multiple KOLs are buying simultaneously — a strong signal of coordinated pumps. **v1.1** adds peak-density windows, exit tracking, and a composite 0–100 coordination score.
187
-
188
- ```ts
189
- const { coordination, score_version, window_minutes } = await client.kol.coordination({
190
- period: "24h", // "1h" | "6h" | "24h" | "7d", default "24h"
191
- min_kols: 3, // 2–50, default 3
192
- limit: 20, // 1–50, default 20
193
- window_minutes: 15, // v1.1 peak-density window in minutes (1–60)
194
- min_score: 60, // v1.1 filter by composite score (0–100)
195
- include_majors: false, // v1.1 — include WIF/BONK/POPCAT
196
- });
197
-
198
- for (const c of coordination) {
199
- console.log(c.token_symbol, "score", c.coordination_score, "peak", c.peak_kols, "exited", c.exited_count);
200
- // c.kols[]: { name, wallet, buy_sol, sell_sol, exited }
201
- }
202
- ```
203
-
204
- Returns: `KolCoordinationResponse` — `{ coordination: CoordinatedToken[], score_version, window_minutes }`
205
-
206
- ---
207
-
208
- #### `client.coordinationAlerts.*` (v1.1)
209
-
210
- Create **real-time push alerts** that fire the moment a new coordination cluster forms. Alerts are evaluated per-trade by the signal-evaluator service (sub-second latency), delivered via WebSocket channel `kol:coordination` and/or HMAC-signed webhook. **PRO: 5 rules, ULTRA: 20 rules.**
211
-
212
- ```ts
213
- // Create a rule: ≥5 KOLs, 10-min window, score ≥70, webhook delivery
214
- const { rule, webhook_secret } = await client.coordinationAlerts.create({
215
- name: "strong-clusters",
216
- min_kols: 5,
217
- window_minutes: 10,
218
- min_score: 70,
219
- include_majors: false,
220
- cooldown_min: 30, // don't re-fire same token within 30 min
221
- score_jump_break: 15, // UNLESS score jumps by 15+ (catches conviction surges)
222
- delivery_mode: "webhook", // "websocket" | "webhook" | "both"
223
- webhook_url: "https://example.com/coord-hook",
224
- });
225
- // SAVE webhook_secret — used for HMAC-SHA256 signature verification.
226
-
227
- await client.coordinationAlerts.list();
228
- await client.coordinationAlerts.get(rule.id);
229
- await client.coordinationAlerts.update(rule.id, { min_score: 80, is_active: false });
230
- await client.coordinationAlerts.delete(rule.id);
231
- ```
232
-
233
- Webhook signatures: header `X-MadeOnSol-Signature` = `sha256(timestamp + "." + body)` with `webhook_secret` as the HMAC key. Reject deliveries older than ~5 min.
234
-
235
- WebSocket delivery: subscribe to channel `kol:coordination` on `wss://madeonsol.com/ws/v1/stream` events are user-scoped (you only receive your own rule fires).
236
-
237
- ---
238
-
239
- #### `client.priceAlerts.*` *(new in 2.8)*
240
-
241
- **Sub-second token MC dip/recovery alerts.** Set a drop threshold on any token — when MC drops below baseline, a `price_alert:dip` event fires. Optionally track recovery. **PRO: 5 alerts, ULTRA: 25 alerts.**
242
-
243
- ```ts
244
- // Create: alert when token drops 20%, then notify when it recovers 15% from the dip low
245
- const { alert, webhook_secret } = await client.priceAlerts.create({
246
- token_mint: "So11111111111111111111111111111111111111112",
247
- drop_pct: 20,
248
- recovery_pct: 15,
249
- name: "SOL dip tracker",
250
- delivery_mode: "webhook",
251
- webhook_url: "https://example.com/dip-hook",
252
- });
253
-
254
- await client.priceAlerts.list();
255
- await client.priceAlerts.get(alert.id);
256
- await client.priceAlerts.update(alert.id, { name: "Renamed", is_active: false });
257
- await client.priceAlerts.delete(alert.id);
258
-
259
- // Event history (30-day retention)
260
- const { events } = await client.priceAlerts.events({ event_type: "dip", limit: 50 });
261
- ```
262
-
263
- Alert lifecycle: `watching` -> `dipped` -> `recovered` (terminal). One-shot per alert. Baseline MC captured at creation time. 30-day auto-expiry. Thresholds immutable — delete and recreate to change.
264
-
265
- WebSocket: subscribe to channel `price_alert:events` user-scoped. Webhook: per-alert HMAC-SHA256 signed (same scheme as coordination alerts).
266
-
267
- ---
268
-
269
- #### `client.sniper.*` — Deshred Sniper Alerts *(new in 2.9)*
270
-
271
- **The fastest path to a new pump.fun launch.** Deploys are reconstructed from shred-level (**deshred**) data and surface in the feed **~500ms before the chain confirms them** — a measured head start versus any confirmed-stream feed. **PRO** sees elite + good deployers; **ULTRA** sees every tier and can keep a custom deployer watchlist.
272
-
273
- ```ts
274
- // Newest-first deshred deploy feed (PRO: elite/good · ULTRA: all tiers)
275
- const { deploys } = await client.sniper.recent({ limit: 50, min_bond_rate: 0.5 });
276
-
277
- // Audit one deployer's recent launches (ULTRA)
278
- await client.sniper.byDeployer("7dEx...4pQ8");
279
-
280
- // Custom watchlist — get deploys from only the deployers you track, any tier (ULTRA, max 50)
281
- await client.sniper.addToWatchlist({ wallets: ["7dEx...4pQ8", "9aBc...2zZ1"], label: "alpha devs" });
282
- await client.sniper.watchlist();
283
- const { deploys: tracked } = await client.sniper.recent({ watchlist: true });
284
- await client.sniper.removeFromWatchlist("7dEx...4pQ8");
285
- ```
286
-
287
- Detection is pre-execution, so payloads carry no MC/logs/balances — `confirmed_on_chain` is `"deshred"`. For **live** push (not polling), use the `sniper:deploy` webhook event or the `sniper:deploys` WebSocket channel. ~1–3% of detected deploys may abandon before settlement.
288
-
289
- ---
290
-
291
- #### `client.kol.scoutLeaderboard(params?)` *(new in 2.8)*
292
-
293
- Scout leaderboard: top KOLs ranked by scout score, first-touch frequency, and swarm attraction rate. **ULTRA only.**
294
-
295
- ```ts
296
- const data = await client.kol.scoutLeaderboard({ limit: 20, scout_tier: "S", sort: "scout_score" });
297
- ```
298
-
299
- ---
300
-
301
- #### `client.kol.coordinationHistory(params?)` *(new in 2.8)*
302
-
303
- Historical coordination alert fires — past events with token, score, KOL count. **ULTRA only.**
304
-
305
- ```ts
306
- const data = await client.kol.coordinationHistory({ limit: 50, min_score: 70 });
307
- ```
308
-
309
- ---
310
-
311
- #### `client.token.kolConsensus(mint)` *(new in 2.8)*
312
-
313
- KOL consensus on a token: how many bought/sold, exit rate, net flow, median entry MC. **ULTRA** gets individual wallet arrays.
314
-
315
- ```ts
316
- const consensus = await client.token.kolConsensus("4sVahM4U8js62mQV58ABSkNRhf6Ztc7Xs2LXUznNpump");
317
- ```
318
-
319
- ---
320
-
321
- #### `client.token.peakHistory(mint)` *(new in 2.8)*
322
-
323
- Peak MC history: ATH, decline from peak, MC at bond and at 1h/6h/24h/7d after bond.
324
-
325
- ```ts
326
- const peak = await client.token.peakHistory("4sVahM4U8js62mQV58ABSkNRhf6Ztc7Xs2LXUznNpump");
327
- ```
328
-
329
- ---
330
-
331
- #### `client.kol.firstTouches(params?)` *(new in 2.2)*
332
-
333
- Recent first-KOL-touch events on tokens — every time a tracked KOL was the first to buy a given mint. Filterable by **scout tier** (S/A/B/C from the per-KOL `mv_kol_scout_score` view), KOL winrate, token age, mint suffix, etc.
334
-
335
- **Backtested signal:** top scouts attract ≥3 follow-on KOLs within 4h ~50% of the time vs ~14% baseline (38d / 491k buys / 72,549 events). The full leaderboard is at [madeonsol.com/kol/scouts](https://madeonsol.com/kol/scouts).
336
-
337
- ```ts
338
- // S-tier scouts on tokens younger than 1h
339
- const { events } = await client.kol.firstTouches({
340
- preset: "scout",
341
- min_scout_tier: "S",
342
- limit: 20,
343
- });
344
-
345
- for (const e of events) {
346
- console.log(e.first_kol.name, "scouted", e.token_symbol, `(scout_score=${e.first_kol.scout_score}%)`);
347
- }
348
- ```
349
-
350
- Filter knobs: `since`, `before`, `limit`, `kol`, `min_kol_winrate_7d`, `min_scout_tier`, `min_n_touches`, `strategy`, `token_age_max_min`, `min_first_buy_sol`, `mint_suffix`, `preset` (`"scout"` or `"fresh_launch"`), `include` (e.g. `"followers_4h"`).
351
-
352
- > **Don't poll — push.** Median lead time before the second KOL is **12 seconds**, so REST polling will lose the swarm. Subscribe to the `kol:first_touches` WebSocket channel (PRO+) or, on Ultra, create an HMAC-signed webhook subscription via `client.firstTouchSubscriptions.create({...})`.
353
-
354
- Returns: `FirstTouchesResponse`
355
-
356
- ---
357
-
358
- #### `client.firstTouchSubscriptions.*` *(Ultra)*
359
-
360
- Create push-delivery rules for first-touch events. Up to 10 active subscriptions per Ultra user.
361
-
362
- ```ts
363
- const { subscription, webhook_secret } = await client.firstTouchSubscriptions.create({
364
- name: "S-tier scouts on pump tokens",
365
- filters: { min_scout_tier: "S", mint_suffix: "pump" },
366
- delivery_mode: "webhook",
367
- webhook_url: "https://my.bot/hooks/scout",
368
- });
369
- // store webhook_secret — shown once
370
-
371
- await client.firstTouchSubscriptions.list();
372
- await client.firstTouchSubscriptions.update(subscription.id, { is_active: false });
373
- await client.firstTouchSubscriptions.delete(subscription.id);
374
- ```
375
-
376
- Same HMAC scheme as coordination alerts. WebSocket channel: `kol:first_touches`.
377
-
378
- ---
379
-
380
- #### `client.kol.token(mint)`
381
-
382
- KOL buy/sell activity for a specific token mint.
383
-
384
- ```ts
385
- const activity = await client.kol.token("EPjFW...");
386
- ```
387
-
388
- Returns: `KolTokenActivity`
389
-
390
- ---
391
-
392
- #### `client.kol.pnl(wallet, params?)`
393
-
394
- Deep per-wallet PnL breakdown with equity curve, risk metrics, and position history.
395
-
396
- ```ts
397
- const pnl = await client.kol.pnl("7xKX...", {
398
- period: "30d", // "7d" | "30d" | "90d" | "180d", default "30d"
399
- });
400
- // All tiers: summary + equity curve + closed positions
401
- // ULTRA: + open positions (tokens bought but not yet sold)
402
- ```
403
-
404
- Returns: `KolPnlResponse`
405
-
406
- ---
407
-
408
- #### `client.kol.trendingTokens(params?)`
409
-
410
- Tokens ranked by KOL buy volume across multiple time windows.
411
-
412
- ```ts
413
- const { tokens } = await client.kol.trendingTokens({
414
- period: "1h", // "5m" | "15m" | "30m" | "1h" | "4h" | "8h" | "12h", default "1h"
415
- min_kols: 2, // minimum distinct KOL buyers
416
- limit: 20, // 1–50, default 20
417
- });
418
- // Available on all tiers; ULTRA unlocks full KOL wallet addresses per token
419
- ```
420
-
421
- Returns: `KolTrendingTokensResponse`
422
-
423
- ---
424
-
425
- ### Alpha Wallet Intelligence — `client.alpha`
426
-
427
- #### `client.alpha.leaderboard(params?)`
428
-
429
- Leaderboard of 1M+ scored early-buyer wallets ranked by win rate, PnL, or ROI.
430
-
431
- ```ts
432
- const { wallets } = await client.alpha.leaderboard({
433
- period: "30d", // "7d" | "30d" | "90d", default "30d"
434
- sort: "win_rate", // "win_rate" | "pnl" | "roi"
435
- min_tokens: 5,
436
- exclude_bots: true,
437
- });
438
- // Up to 100 results on Free/Pro; ULTRA unlocks 500 + bot signals
439
- ```
440
-
441
- Returns: `AlphaLeaderboardResponse`
442
-
443
- ---
444
-
445
- #### `client.alpha.wallet(wallet)`
446
-
447
- Full profile for an alpha wallet including per-token history and bot signals. ULTRA only.
448
-
449
- ```ts
450
- const profile = await client.alpha.wallet("7xKX...");
451
- ```
452
-
453
- Returns: `AlphaWalletResponse`
454
-
455
- ---
456
-
457
- #### `client.alpha.linked(wallet)`
458
-
459
- Linked-wallet clustering — wallets that co-bought with this address within 2 seconds. ULTRA only.
460
-
461
- ```ts
462
- const { linked } = await client.alpha.linked("7xKX...");
463
- ```
464
-
465
- Returns: `AlphaLinkedResponse`
466
-
467
- ---
468
-
469
- #### `client.alpha.capTable(mint)`
470
-
471
- First buyers for a token enriched with historical win rates, PnL, and KOL identity. PRO/ULTRA.
472
-
473
- ```ts
474
- const { buyers } = await client.alpha.capTable("EPjFW...");
475
- ```
476
-
477
- Returns: `AlphaCapTableResponse`
478
-
479
- ---
480
-
481
- #### `client.alpha.buyerQuality(mint)`
482
-
483
- 0–100 cohort quality score based on the profile of a token's first buyers. All tiers. 5-minute cache.
484
-
485
- ```ts
486
- const { score } = await client.alpha.buyerQuality("EPjFW...");
487
- ```
488
-
489
- Returns: `AlphaBuyerQualityResponse`
490
-
491
- ---
492
-
493
- #### `client.alpha.risk(mint)`
494
-
495
- Transparent 0–100 token rug-risk/safety score (higher = riskier). Returns a `band` (`safe`/`caution`/`danger`), an explainable `factors[]` array that sums into `risk_score`, and the raw `inputs` (mint/freeze authority revocation, liquidity USD + liquidity-to-MC ratio, transfer fee bps, Token-2022 flag, burn detection, launch cohort SOL + size, deployer bond rate + total deployed, KOL signal, blacklist status). PRO/ULTRA — BASIC receives HTTP 403.
496
-
497
- ```ts
498
- const { risk_score, band, factors } = await client.alpha.risk("EPjFW...");
499
- if (band === "danger") return; // skip risky tokens
500
- ```
501
-
502
- Returns: `TokenRiskResponse`
503
-
504
- ---
505
-
506
- #### `client.alpha.candles(mint, params?)`
507
-
508
- OHLCV candlestick time-series — the persisted price/MC trajectory, rolled up to any timeframe on read. **PRO**: OHLCV (last 30 days). **ULTRA**: + per-bar net flow (buy/sell volume, `net_volume_usd`, counts, MEV volume), liquidity delta, and full retained history. Params: `tf` (`1m`|`5m`|`15m`|`1h`|`4h`|`1d`, default `1h`), `limit` (1–1000, default 200), `from`/`to` (ISO8601). `net_flow_included` flags whether the ULTRA fields are populated.
509
-
510
- ```ts
511
- const { candles, net_flow_included } = await client.alpha.candles("EPjFW...", { tf: "5m", limit: 100 });
512
- const last = candles.at(-1);
513
- console.log(last.close, net_flow_included ? `net flow $${last.net_volume_usd}` : "(ULTRA for net flow)");
514
- ```
515
-
516
- Returns: `CandlesResponse`
517
-
518
- ---
519
-
520
- ### Wallet Tracker — `client.walletTracker`
521
-
522
- #### `client.walletTracker.watchlist()`
523
-
524
- List your tracked wallets and remaining capacity.
525
-
526
- ```ts
527
- const { wallets, capacity } = await client.walletTracker.watchlist();
528
- // capacity: { used, limit } Free: 10, Pro: 50, Ultra: 100
529
- ```
530
-
531
- Returns: `WatchlistResponse`
532
-
533
- ---
534
-
535
- #### `client.walletTracker.addToWatchlist(wallet, params?)`
536
-
537
- Add a wallet to your watchlist. Tracking begins immediately.
538
-
539
- ```ts
540
- await client.walletTracker.addToWatchlist("7xKX...", { label: "whale" });
541
- ```
542
-
543
- ---
544
-
545
- #### `client.walletTracker.removeFromWatchlist(wallet)`
546
-
547
- Remove a wallet from your watchlist.
548
-
549
- ```ts
550
- await client.walletTracker.removeFromWatchlist("7xKX...");
551
- ```
552
-
553
- ---
554
-
555
- #### `client.walletTracker.updateLabel(wallet, label)`
556
-
557
- Update the label for a tracked wallet.
558
-
559
- ```ts
560
- await client.walletTracker.updateLabel("7xKX...", "smart money");
561
- ```
562
-
563
- ---
564
-
565
- #### `client.walletTracker.trades(params?)`
566
-
567
- Historical swap and transfer events for your watched wallets. 120-day retention.
568
-
569
- ```ts
570
- const { events } = await client.walletTracker.trades({
571
- wallet: "7xKX...", // filter by specific wallet
572
- action: "buy", // "buy" | "sell"
573
- event_type: "swap", // "swap" | "transfer"
574
- limit: 50,
575
- before: "2026-04-01T00:00:00Z", // ISO 8601 cursor
576
- });
577
- ```
578
-
579
- Returns: `WalletTrackerTradesResponse`
580
-
581
- ---
582
-
583
- #### `client.walletTracker.summary(params?)`
584
-
585
- Per-wallet stats across your watchlist: swap counts, SOL bought/sold, last event time.
586
-
587
- ```ts
588
- const { wallets } = await client.walletTracker.summary({
589
- period: "7d", // "24h" | "7d" | "30d", default "7d"
590
- wallet: "7xKX...", // optional: single wallet
591
- });
592
- ```
593
-
594
- Returns: `WalletTrackerSummaryResponse`
595
-
596
- ---
597
-
598
- ### Universal Wallet — `client.wallet` *(new in 2.7)*
599
-
600
- Per-wallet endpoints that work on **any** Solana wallet, not just curated KOLs. FIFO cost-basis PnL over the last 90 days. PRO+ on every method. Results are cached server-side in `wallet_analyses` with dynamic TTL (5min / 1h / 24h based on last activity); cache hits don't count against your daily quota.
601
-
602
- **Cost-basis honesty:** observable only inside the 90-day data window. Wallets that sold tokens bought before that window have the overflow silently discarded rather than fabricated. `notes.cost_basis_observable_from` makes the cutoff visible per call.
603
-
604
- #### `client.wallet.stats(address)`
605
-
606
- Aggregate stats over 90d plus cross-product flags (KOL / alpha / deployer). Includes enrichments: top traded tokens with realized PnL, trading style, deployer tier mix, recent trades. **v2.8** adds `derived` block: win rate, ROI, best/worst trade, biggest miss (token sold that later mooned), and AI-classified verdict.
607
-
608
- ```ts
609
- const { stats, flags, derived } = await client.wallet.stats("ASVz...ybJk");
610
- console.log(`${flags.kol_name ?? address}: ${stats?.total_trades} trades`);
611
- if (derived?.verdict) {
612
- console.log(`${derived.verdict.label}: ${derived.verdict.description}`);
613
- }
614
- if (derived?.biggest_miss) {
615
- console.log(`Biggest miss: ${derived.biggest_miss.token_symbol} missed +${derived.biggest_miss.missed_sol.toFixed(1)} SOL`);
616
- }
617
- ```
618
-
619
- Returns: `WalletStatsResponse` (404 if the wallet has no trades and no flag-table presence).
620
-
621
- ---
622
-
623
- #### `client.wallet.pnl(address)`
624
-
625
- Full FIFO cost-basis PnL: realized + unrealized SOL, profit factor, max drawdown, avg + median hold minutes, daily UTC PnL curve, closed positions sorted by pnl desc (with ROI %, hold time, win/loss), and open positions hydrated with live current prices from the market-cap tracker.
626
-
627
- ```ts
628
- const pnl = await client.wallet.pnl("ASVz...ybJk");
629
- console.log(`Realized: ${pnl.summary.realized_sol} SOL · Unrealized: ${pnl.summary.unrealized_sol} SOL`);
630
- console.log(`Win rate: ${(pnl.summary.win_rate! * 100).toFixed(1)}% · PF: ${pnl.summary.profit_factor}`);
631
- for (const c of pnl.closed_positions.slice(0, 5)) {
632
- const sign = c.pnl_sol > 0 ? "+" : "";
633
- console.log(` ${c.token_mint.slice(0,8)}… ${sign}${c.pnl_sol} SOL (${c.roi_pct}% ROI, ${c.hold_minutes}m hold)`);
634
- }
635
- ```
636
-
637
- Returns: `WalletPnlResponse`. Cache hits include `cache_hit: true` + `computed_at`; misses include `ttl_seconds`.
638
-
639
- ---
640
-
641
- #### `client.wallet.positions(address)`
642
-
643
- Open positions only — lighter slice of `pnl()`. Shares the same cache, so calling this right after `pnl()` is an immediate hit.
644
-
645
- ```ts
646
- const { positions } = await client.wallet.positions("ASVz...ybJk");
647
- for (const p of positions) {
648
- const u = p.unrealized_sol;
649
- console.log(` ${p.token_mint.slice(0,8)}… cost ${p.cost_basis_sol} SOL unrealized ${u ?? "—"} SOL (${p.unrealized_pct ?? "—"}%)`);
650
- }
651
- ```
652
-
653
- Returns: `WalletPositionsResponse`. Mints without a current price return `unrealized_sol: null` rather than fabricated zero.
654
-
655
- ---
656
-
657
- #### `client.wallet.trades(address, params?)`
658
-
659
- Cursor-paginated raw trades. Default window is the last 90 days; override via `since` / `until` (Unix epoch seconds). Default limit 100, max 500.
660
-
661
- ```ts
662
- let cursor: string | undefined;
663
- while (true) {
664
- const page = await client.wallet.trades("ASVz...ybJk", { limit: 200, cursor, action: "buy" });
665
- for (const t of page.trades) processBuy(t);
666
- if (!page.has_more) break;
667
- cursor = page.next_cursor!;
668
- }
669
- ```
670
-
671
- Params:
672
- - `limit` — 1-500, default 100
673
- - `cursor` — from `next_cursor` of previous response
674
- - `action` `"buy"` or `"sell"`
675
- - `token_mint` — filter to one token
676
- - `since` / `until` — Unix epoch seconds (default last 90d)
677
-
678
- Returns: `WalletTradesResponse` with `trades[]` + `next_cursor` + `has_more` + `filters` echo.
679
-
680
- ---
681
-
682
- ### Deployer Hunter — `client.deployer`
683
-
684
- #### `client.deployer.stats()`
685
-
686
- Global statistics across all tracked deployer wallets.
687
-
688
- ```ts
689
- const stats = await client.deployer.stats();
690
- console.log(stats.overall_bonding_rate); // e.g. 0.043
691
- ```
692
-
693
- Returns: `DeployerStats`
694
-
695
- ---
696
-
697
- #### `client.deployer.leaderboard(params?)`
698
-
699
- Deployers ranked by bonding rate or recent performance.
700
-
701
- ```ts
702
- const { deployers } = await client.deployer.leaderboard({
703
- tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
704
- sort: "bonding_rate", // "bonding_rate" | "recent_bond_rate" | "total_bonded" | "last_deploy_at"
705
- limit: 20, // 1–50, default 20
706
- offset: 0,
707
- });
708
- ```
709
-
710
- Returns: `DeployerLeaderboardResponse`
711
-
712
- ---
713
-
714
- #### `client.deployer.profile(wallet)`
715
-
716
- Full profile for a single deployer wallet.
717
-
718
- ```ts
719
- const deployer = await client.deployer.profile("3xAB...");
720
- console.log(deployer.tier, deployer.bonding_rate);
721
- ```
722
-
723
- Returns: `DeployerProfile`
724
-
725
- ---
726
-
727
- #### `client.deployer.tokens(wallet, params?)`
728
-
729
- All tokens deployed by a specific wallet.
730
-
731
- ```ts
732
- const { tokens } = await client.deployer.tokens("3xAB...", {
733
- limit: 20,
734
- offset: 0,
735
- });
736
- ```
737
-
738
- Returns: `DeployerTokensResponse`
739
-
740
- ---
741
-
742
- #### `client.deployer.alerts(params?)`
743
-
744
- Real-time deploy alerts fired when a tracked deployer launches a new token.
745
-
746
- ```ts
747
- const { alerts } = await client.deployer.alerts({
748
- since: "2025-01-01T00:00:00Z", // ISO 8601
749
- limit: 20,
750
- tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
751
- offset: 0,
752
- });
753
- ```
754
-
755
- Returns: `DeployerAlertsResponse`
756
-
757
- ---
758
-
759
- #### `client.deployer.alertStats(params?)`
760
-
761
- Aggregated alert statistics by tier.
762
-
763
- ```ts
764
- const stats = await client.deployer.alertStats({ period: "7d" });
765
- // "7d" | "30d" | "all", default "all"
766
- ```
767
-
768
- Returns: `DeployerAlertStats`
769
-
770
- ---
771
-
772
- #### `client.deployer.bestTokens(params?)`
773
-
774
- Top-performing tokens from tracked deployers by peak market cap.
775
-
776
- ```ts
777
- const { tokens } = await client.deployer.bestTokens({
778
- period: "7d", // "7d" | "30d" | "all", default "7d"
779
- limit: 5, // 1–20, default 5
780
- });
781
- ```
782
-
783
- Returns: `BestTokensResponse`
784
-
785
- ---
786
-
787
- #### `client.deployer.recentBonds(params?)`
788
-
789
- Most recently bonded tokens from tracked deployers.
790
-
791
- ```ts
792
- const { bonds } = await client.deployer.recentBonds({ limit: 20 });
793
- ```
794
-
795
- Returns: `RecentBondsResponse`
796
-
797
- ---
798
-
799
- ### Token Intelligence — `client.token`
800
-
801
- Per-mint snapshots (price, MC, volume, deployer rep, KOL activity, blacklist flags, **v1.7 velocity windows + MEV-share**) and a filtered directory.
802
-
803
- #### `client.token.get(mint)`
804
-
805
- Comprehensive per-mint snapshot in one call. **ULTRA** also returns individual KOL wallet addresses in `top_buyers[]`.
806
-
807
- ```ts
808
- const { token } = await client.token.get("So11111111111111111111111111111111111111112");
809
- console.log(token.price_usd, token.market_cap);
810
- console.log(token.mc_change_pct?.["1h"]); // v1.7
811
- console.log(token.mev_volume_pct?.["1h"]); // v1.7
812
- ```
813
-
814
- Invalid mints return a 400 with `code: "invalid_mint"`, `reason`, `received_length`, `example`, and `docs` URL — no trial and error.
815
-
816
- Returns: `TokenResponse` (with `mc_change_pct` / `volume_usd` / `mev_volume_pct` (each keyed by 5m/15m/1h/2h/4h) + `history_age_seconds` as of 1.7). **New in 2.12:** also returns `liquidity_to_mc_ratio` (liquidity_usd / market_cap), `launch_cohort_sol` (total SOL spent by the first-20 buyers), and `launch_cohort_size` (count of first-20 buyers, 0–20).
817
-
818
- #### `client.token.batch(mints)`
819
-
820
- Batch lookup up to 50 mints in one round-trip. ~10–20× cheaper than N sequential calls. Each item returns the same shape as `get()` — including `liquidity_to_mc_ratio`, `launch_cohort_sol`, and `launch_cohort_size` *(new in 2.12)*.
821
-
822
- ```ts
823
- const { tokens } = await client.token.batch(["mint1", "mint2", "mint3"]);
824
- ```
825
-
826
- Returns: `TokenBatchResponse`
827
-
828
- #### `client.token.list(params?)` *(new in 2.6 — PRO+)*
829
-
830
- Filtered, sortable token directory. Default `min_liq=2000` trims the long tail of phantom-MC tokens from low-liquidity pools; pass `min_liq=0` to opt out.
831
-
832
- **Server-side filters** (cheap, indexed): `min_mc`, `max_mc`, `min_liq`, `active_h`, `primary_dex` (`pumpfun`/`pumpswap`/`raydium`/`meteora`/`orca`/`raydium_clmm`), `authority_revoked`, `exclude_token2022`, `min_lp_burnt_pct`, `deployer_tier` (`elite`/`good`/`moderate`/`rising`/`cold`/`unranked`), `min_liq_mc_ratio`, `max_liq_mc_ratio`.
833
-
834
- **Computed post-filters** (over-fetches 3×): `min_volume_1h_usd`, `max_mev_share_pct`, `mc_change_1h_min_pct`, `mc_change_1h_max_pct`. When any of these are set, `pagination.post_filtered` is `true` and page size may be smaller than `limit`.
835
-
836
- Each item in `tokens[]` includes `liquidity_to_mc_ratio` and `deployer_tier` *(new in 2.12)*.
837
-
838
- ```ts
839
- // Momentum scanner: liquid mints up >20% in 1h, low bot share
840
- const { tokens, pagination } = await client.token.list({
841
- min_liq: 10000,
842
- min_volume_1h_usd: 5000,
843
- max_mev_share_pct: 60,
844
- mc_change_1h_min_pct: 20,
845
- sort: "mc_desc",
846
- limit: 50,
847
- });
848
-
849
- // Cleanest filter for a sane "top by MC" feed
850
- const { tokens } = await client.token.list({
851
- min_liq: 25000,
852
- active_h: 1,
853
- authority_revoked: true,
854
- sort: "mc_desc",
855
- });
856
- ```
857
-
858
- Returns: `TokenListResponse` (with `tokens[]`, `pagination`, `filters` echo)
859
-
860
- #### `client.token.batchBuyerQuality(mints)`
861
-
862
- Batch buyer-quality scoring for up to 50 mints. Shares the same 5-minute LRU cache as `client.alpha.buyerQuality(mint)`.
863
-
864
- Returns: `AlphaBuyerQualityBatchResponse`
865
-
866
- ---
867
-
868
- ### Account — `client.me()` *(new in 2.6)*
869
-
870
- Inspect your tier, quota state, and feature usage in one call. Reads from the same in-memory counters that drive rate-limit enforcement, so `quota.daily.remaining` is authoritative — no header parsing needed. Works on every tier (BASIC/PRO/ULTRA).
871
-
872
- ```ts
873
- const me = await client.me();
874
- console.log(`${me.tier}: ${me.quota.daily.remaining}/${me.quota.daily.limit} req left today`);
875
- console.log(`Webhooks: ${me.features.webhooks.used}/${me.features.webhooks.limit}`);
876
- console.log(`Copy-trade wallets: ${me.features.copytrade_wallets.used}/${me.features.copytrade_wallets.limit}`);
877
-
878
- if (me.quota.daily.remaining < 100) {
879
- // self-throttle
880
- }
881
- ```
882
-
883
- Returns: `MeResponse`
884
-
885
- ---
886
-
887
- ### Signal Performance `client.getSignalPerformance(name)` *(new in 2.12)*
888
-
889
- Performance stats for a named signal: hit rate, precision, sample count, and lookback window.
890
-
891
- ```ts
892
- const perf = await client.getSignalPerformance("kol_coordination");
893
- console.log(perf.precision, perf.hit_rate);
894
- ```
895
-
896
- Params: `name` — signal name (e.g. `"kol_coordination"`, `"first_touch_scout"`, `"deployer_elite"`).
897
-
898
- Returns: `Promise<unknown>` — shape varies by signal name; see `/api-docs` for the full schema.
899
-
900
- ---
901
-
902
- ### Tool Directory — `client.tools`
903
-
904
- #### `client.tools.search(params?)`
905
-
906
- Search 950+ Solana tools indexed on MadeOnSol.
907
-
908
- ```ts
909
- const { tools, count } = await client.tools.search({
910
- q: "trading bot", // full-text search
911
- category: "trading", // category slug filter
912
- limit: 20, // 1–50, default 20
913
- });
914
- ```
915
-
916
- Returns: `ToolsSearchResponse`
917
-
918
- ---
919
-
920
- ### WebSocket Streaming — `client.stream`
921
-
922
- #### `client.stream.getToken()`
923
-
924
- Generate a 24-hour WebSocket streaming token. Pro/Ultra subscribers get `ws_url` for KOL/deployer event streaming. Ultra subscribers also get `dex_ws_url` for the all-DEX trade stream.
925
-
926
- ```ts
927
- const token = await client.stream.getToken();
928
- console.log(token.ws_url); // wss://madeonsol.com/ws/v1/stream
929
- console.log(token.dex_ws_url); // wss://madeonsol.com/ws/v1/dex-stream (Ultra only)
930
- ```
931
-
932
- Returns: `StreamToken` — `{ token, expires_at, ws_url, dex_ws_url?, usage }`
933
-
934
- #### `client.stream.connect()` *(new in 2.10)*
935
-
936
- Open a **managed** stream — token fetch + 24h refresh, auto-reconnect (backoff + jitter), heartbeat liveness, and typed events are handled for you. No need to touch `getToken()` or `ws` directly.
937
-
938
- ```ts
939
- const stream = client.stream.connect();
940
- stream.on("kol:trade", (t) => console.log(t.token_symbol, t.action));
941
- stream.on("deployer:alert", (a) => console.log("new deploy", a.token_mint));
942
- stream.subscribe(["kol:trades", "deployer:alerts"]);
943
- // stream.unsubscribe([...]) / stream.close() when done
944
- ```
945
-
946
- Channels: `kol:trades`, `kol:coordination`, `kol:first_touches`, `deployer:alerts`, `wallet_tracker:events`, `copytrade:signals`, `price_alert:events`, `sniper:deploys`, `token:graduations` (every pump.fun graduation in real time, tracked deployer or not — typed `GraduationEvent`). Lifecycle: `open`, `close`, `reconnect`, `heartbeat`, `error`. Node 22+ uses the global `WebSocket`; on Node < 22 also `npm i ws`.
947
-
948
- ---
949
-
950
- ### DEX Firehose (Ultra) — `wss://madeonsol.com/ws/v1/dex-stream`
951
-
952
- Real-time trades across **9+ Solana DEX programs** (Pump.fun, PumpAMM, PumpSwap, Raydium AMM/CPMM/CAMM, Jupiter v6, Orca Whirlpool, Meteora DBC/DAMM, LaunchLab/bonk.fun) on a single normalized WebSocket. Server-side filters drop everything you don't care about before it hits your socket.
953
-
954
- **Limits:** ULTRA = 2 connections, **10 named subscriptions per connection**, up to **500 trades replay** from a server-side buffer holding ~5 minutes of firehose history (not connection-scoped — covers trades from before you connected; newest-first, sort by `block_time`). Inbound rate limit: 5 messages/sec (excess emits one error per second).
955
-
956
- #### Quick start
957
-
958
- ```ts
959
- import { WebSocket } from "ws"; // or native WebSocket in browsers/Bun
960
-
961
- const { token, dex_ws_url } = await client.stream.getToken();
962
- const ws = new WebSocket(`${dex_ws_url}?token=${token}`); // token MUST be appended as query param
963
-
964
- ws.on("open", () => {
965
- // Multi-subscription: each sub has its own sub_id and filters
966
- ws.send(JSON.stringify({
967
- type: "subscribe",
968
- sub_id: "fresh-pumpfun",
969
- replay: 50, // backfill up to 500 from ring buffer
970
- filters: {
971
- dex: "pumpfun",
972
- token_age_max_seconds: 300, // first seen in last 5 min
973
- min_sol: 0.5,
974
- action: "buy",
975
- },
976
- }));
977
- });
978
-
979
- ws.on("message", (raw) => {
980
- const msg = JSON.parse(raw.toString());
981
- if (msg.channel === "dex:trades") {
982
- // { sub_id, data: { wallet, mint, action, sol_amount, token_amount, dex, ... }, replay, ts }
983
- console.log(msg.sub_id, msg.data.dex, msg.data.action, msg.data.sol_amount);
984
- }
985
- });
986
- ```
987
-
988
- #### Protocol — client → server
989
-
990
- | `type` | Required fields | Notes |
991
- |---|---|---|
992
- | `subscribe` | `sub_id`, `filters` | Optional `replay: 1–500` |
993
- | `update` | `sub_id`, `filters` | Replaces filters in place — no disconnect needed |
994
- | `unsubscribe` | `sub_id` | Or omit `sub_id` to clear all subs |
995
- | `list` | — | Server replies with `{ type: "list", subs: [...] }` |
996
- | `ping` | — | Heartbeat — server replies `{ type: "pong" }` |
997
-
998
- #### Server client message shapes
999
-
1000
- ```ts
1001
- { type: "connected", tier: "ULTRA", capabilities: { max_subs: 10, max_replay: 500, dex_names: [...], deployer_tiers: [...] } } // on connect
1002
- { type: "subscribed", sub_id: "fresh-pumpfun", filters: { ... } }
1003
- { type: "replay_done", sub_id: "fresh-pumpfun", count: 50 } // after backfill
1004
- { type: "updated", sub_id: "fresh-pumpfun", filters: { ... } }
1005
- { type: "unsubscribed", sub_id: "fresh-pumpfun" }
1006
- { type: "list", subs: [{ sub_id, filters }] } // reply to { type: "list" }
1007
- { type: "heartbeat", ts: 1712160000000 } // every 30s
1008
- { type: "error", sub_id?, message: "..." }
1009
- { channel: "dex:trades", sub_id, data: { ... }, replay: false, ts: 1712160000000 }
1010
- ```
1011
-
1012
- #### Filter dimensions
1013
-
1014
- At least **one targeting filter** is required (otherwise the firehose would dump every trade). Filters compose with AND semantics.
1015
-
1016
- | Filter | Type | Notes |
1017
- |---|---|---|
1018
- | `token_mint` / `token_mints` | string / string[] (≤50) | Targeting |
1019
- | `wallet` / `wallets` | string / string[] (≤50) | Targeting |
1020
- | `dex` | string \| string[] | `pumpfun`, `pumpamm`, `pumpswap`, `raydium`, `jupiter`, `orca`, `meteora`, `launchlab` |
1021
- | `program` | string | Raw program ID |
1022
- | `deployer_tier` | string \| string[] | `elite`, `good`, `moderate`, `rising`, `cold`, `unranked` (uses Deployer Hunter scoring) |
1023
- | `token_age_max_seconds` | number | Only trades on mints first seen within window (uses persisted first-seen table) |
1024
- | `market_cap_min_sol` / `market_cap_max_sol` | number | Bounded by current market cap (last trade price × cached supply, 1h TTL) |
1025
- | `min_sol` / `max_sol` | number | Trade size bounds |
1026
- | `action` | `"buy"` \| `"sell"` | Direction |
1027
-
1028
- **Async filters** (`token_age`, `deployer_tier`, `market_cap`) evaluate against live state and are **skipped on replay**. The first trade for an unseen mint may be skipped while the supply fetch is in flight.
1029
-
1030
- #### Multi-sub example
1031
-
1032
- ```ts
1033
- ws.send(JSON.stringify({ type: "subscribe", sub_id: "snipers", filters: { token_age_max_seconds: 60 } }));
1034
- ws.send(JSON.stringify({ type: "subscribe", sub_id: "whales", filters: { min_sol: 50 } }));
1035
- ws.send(JSON.stringify({ type: "subscribe", sub_id: "kol-mints", filters: { token_mints: ["EPjF...", "So11..."] } }));
1036
-
1037
- // Tighten the snipers filter without disconnecting
1038
- ws.send(JSON.stringify({ type: "update", sub_id: "snipers", filters: { token_age_max_seconds: 30, min_sol: 0.3 } }));
1039
-
1040
- // Drop whales when you're done
1041
- ws.send(JSON.stringify({ type: "unsubscribe", sub_id: "whales" }));
1042
- ```
1043
-
1044
- Each `dex:trades` message echoes the `sub_id` that matched, so you can route them locally without reapplying filter logic client-side.
1045
-
1046
- ---
1047
-
1048
- ### Copy-Trade — `client.copytrade` *(new in 2.10)*
1049
-
1050
- Mirror N source wallets into actionable signals (delivered via webhook/WebSocket). PRO/ULTRA PRO: 3 rules × 5 wallets, ULTRA: 20 × 50.
1051
-
1052
- ```ts
1053
- const { subscription, webhook_secret } = await client.copytrade.create({
1054
- name: "whale mirror",
1055
- source_wallets: ["WalletA…", "WalletB…"],
1056
- sizing_mode: "fixed",
1057
- sizing_amount: 0.5, // SOL per mirrored buy
1058
- only_action: "buy",
1059
- delivery_mode: "webhook",
1060
- webhook_url: "https://you.example/hook",
1061
- });
1062
-
1063
- await client.copytrade.subscriptions(); // list rules
1064
- await client.copytrade.update(subscription.id, { is_active: false });
1065
- await client.copytrade.signals({ limit: 50 }); // 7-day fired-signal history
1066
- await client.copytrade.delete(subscription.id);
1067
- ```
1068
-
1069
- ### Webhooks — `client.webhooks`
1070
-
1071
- Manage push notification webhooks for real-time events (Pro: 3, Ultra: 10).
1072
-
1073
- ```ts
1074
- // Create a webhook
1075
- const webhook = await client.webhooks.create({
1076
- url: "https://example.com/hook",
1077
- events: ["kol:trade", "deployer:alert"],
1078
- filters: { min_sol: 1 },
1079
- });
1080
-
1081
- // List, update, delete
1082
- const { webhooks } = await client.webhooks.list();
1083
- await client.webhooks.update(webhook.id, { status: "paused" });
1084
- await client.webhooks.delete(webhook.id);
1085
- await client.webhooks.test(webhook.id);
1086
- ```
1087
-
1088
- ---
1089
-
1090
- ## Error handling
1091
-
1092
- All methods throw `MadeOnSolError` on non-2xx responses.
1093
-
1094
- ```ts
1095
- import { MadeOnSol, MadeOnSolError } from "madeonsol";
1096
-
1097
- try {
1098
- const profile = await client.kol.wallet("invalid-wallet");
1099
- } catch (err) {
1100
- if (err instanceof MadeOnSolError) {
1101
- console.error(err.message); // human-readable message
1102
- console.error(err.status); // HTTP status code, e.g. 404
1103
- console.error(err.body); // raw response body
1104
- }
1105
- }
1106
- ```
1107
-
1108
- ---
1109
-
1110
- ## Exported types
1111
-
1112
- All types are exported from the main entry point:
1113
-
1114
- ```ts
1115
- import type {
1116
- // Errors
1117
- MadeOnSolError,
1118
-
1119
- // KOL
1120
- KolTrade,
1121
- KolFeedParams,
1122
- KolFeedResponse,
1123
- KolLeaderboardParams,
1124
- KolLeaderboardResponse,
1125
- KolLeaderboardEntry,
1126
- KolWalletParams,
1127
- KolWalletProfile,
1128
- KolCoordinationParams,
1129
- KolCoordinationResponse,
1130
- CoordinatedToken,
1131
- KolTokenActivity,
1132
- KolPnlByToken,
1133
-
1134
- // Deployer
1135
- DeployerStats,
1136
- DeployerLeaderboardParams,
1137
- DeployerLeaderboardResponse,
1138
- DeployerLeaderboardEntry,
1139
- DeployerProfile,
1140
- DeployerToken,
1141
- DeployerTokensParams,
1142
- DeployerTokensResponse,
1143
- DeployerAlertsParams,
1144
- DeployerAlertsResponse,
1145
- DeployerAlert,
1146
- DeployerAlertStatsParams,
1147
- DeployerAlertStats,
1148
- BestTokensParams,
1149
- BestTokensResponse,
1150
- BestToken,
1151
- RecentBondsParams,
1152
- RecentBondsResponse,
1153
- RecentBond,
1154
-
1155
- // Tools
1156
- ToolsSearchParams,
1157
- ToolsSearchResponse,
1158
- Tool,
1159
-
1160
- // KOL PnL & Trending
1161
- KolPnlResponse,
1162
- KolTrendingTokensResponse,
1163
- TrendingToken,
1164
-
1165
- // Alpha Wallet Intelligence
1166
- AlphaWalletEntry,
1167
- AlphaLeaderboardResponse,
1168
- AlphaWalletResponse,
1169
- AlphaLinkedResponse,
1170
- AlphaCapTableResponse,
1171
- AlphaBuyerQualityResponse,
1172
-
1173
- // Wallet Tracker
1174
- WalletEntry,
1175
- WatchlistResponse,
1176
- WalletTrackerEvent,
1177
- WalletTrackerTradesResponse,
1178
- WalletTrackerSummaryResponse,
1179
-
1180
- // Streaming
1181
- StreamToken,
1182
-
1183
- // Webhooks
1184
- Webhook,
1185
- WebhookCreateParams,
1186
- WebhookUpdateParams,
1187
- WebhookListResponse,
1188
-
1189
- // Enums / unions
1190
- KolAction,
1191
- LeaderboardPeriod,
1192
- CoordinationPeriod,
1193
- DeployerTier,
1194
- DeployerSortField,
1195
- AlertPeriod,
1196
- BestTokensPeriod,
1197
- } from "madeonsol";
1198
- ```
1199
-
1200
- ---
1201
-
1202
- ## Related
1203
-
1204
- - [MadeOnSol website](https://madeonsol.com) — Browse 950+ Solana tools
1205
- - [API documentation](https://madeonsol.com/api-docs) — Interactive endpoint reference
1206
- - [MadeOnSol on GitHub](https://github.com/LamboPoewert/madeonsol) — Main project repository
1207
-
1208
- ## Also Available
1209
-
1210
- | Platform | Package |
1211
- |---|---|
1212
- | Rust | [`madeonsol`](https://crates.io/crates/madeonsol) on crates.io |
1213
- | Python (LangChain, CrewAI) | [`madeonsol-x402`](https://pypi.org/project/madeonsol-x402/) on PyPI |
1214
- | MCP Server (Claude, Cursor) | [`mcp-server-madeonsol`](https://www.npmjs.com/package/mcp-server-madeonsol) · [Smithery](https://smithery.ai/servers/madeonsol/solana-kol-intelligence) · [Glama](https://glama.ai/mcp/servers/LamboPoewert/mcp-server-madeonsol) |
1215
- | ElizaOS | [`@madeonsol/plugin-madeonsol`](https://www.npmjs.com/package/@madeonsol/plugin-madeonsol) |
1216
- | Solana Agent Kit | [`solana-agent-kit-plugin-madeonsol`](https://www.npmjs.com/package/solana-agent-kit-plugin-madeonsol) |
1217
-
1218
- ---
1219
-
1220
- ## License
1221
-
1222
- MIT © [MadeOnSol](https://madeonsol.com)
1
+ # madeonsol
2
+
3
+ [![npm version](https://img.shields.io/npm/v/madeonsol?style=flat-square)](https://www.npmjs.com/package/madeonsol)
4
+ [![npm downloads](https://img.shields.io/npm/dm/madeonsol?style=flat-square)](https://www.npmjs.com/package/madeonsol)
5
+ [![GitHub stars](https://img.shields.io/github/stars/LamboPoewert/madeonsol-sdk?style=flat-square&logo=github)](https://github.com/LamboPoewert/madeonsol-sdk)
6
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5.4+-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
7
+ [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square)](package.json)
8
+ [![License: MIT](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)
9
+
10
+ > ⭐ **[Star on GitHub](https://github.com/LamboPoewert/madeonsol-sdk)** if you find this useful · 📂 **[Examples](./examples/)** · 📚 **[API docs](https://madeonsol.com/api-docs)**
11
+
12
+ Official TypeScript/JavaScript SDK for the **[MadeOnSol](https://madeonsol.com) Solana API** — zero dependencies, fully typed, works in Node.js ≥ 18 and edge runtimes.
13
+ > Real-time Solana trading intelligence: track 1,069 KOL wallets with <3s latency, score 23,000+ Pump.fun deployers, surface deshred deploy signals **~500ms before on-chain confirmation**, detect multi-KOL coordination, score token rug-risk 0–100 with a transparent factor breakdown, push every pump.fun graduation the second it bonds, and stream every DEX trade across 9+ programs. Free tier: 200 requests/day at [madeonsol.com/pricing](https://madeonsol.com/pricing) — no credit card required.
14
+
15
+ > **New in 2.15.0** — **Token flow + deployer SOL balance.** `client.alpha.tokenFlow(mint, { window })` (`GET /tokens/{mint}/flow`, `window` `1h` default or `24h`, **PRO+**) returns aggregated buy/sell flow for a token: `unique_wallets`/`unique_buyers`/`unique_sellers`, `buy_count`/`sell_count`/`total_trades`, `buy_sol`/`sell_sol`/`net_sol` (buy − sell), and `trades_per_wallet`, plus the window `from` timestamp. New types: `TokenFlowResponse`, `TokenFlowParams`, `TokenFlowWindow`. Deployer-alert objects (`DeployerAlert`) now also carry `deployer_sol_balance` (the deployer wallet's SOL balance at alert time, `number | null`).
16
+ >
17
+ > **New in 2.14.0** — **OHLCV candles + net flow.** `client.alpha.candles(mint, { tf, limit, from, to })` returns the persisted price/MC trajectory as candlesticks (`1m`/`5m`/`15m`/`1h`/`4h`/`1d`, rolled up on read). **PRO**: OHLCV (`open`/`high`/`low`/`close`/`volume_usd`/`trades`/`market_cap_usd`), last 30 days. **ULTRA**: adds per-bar net flow (`buy_volume_usd`/`sell_volume_usd`/`net_volume_usd`, `buy_count`/`sell_count`, `volume_mev_usd`), liquidity delta (`open_liquidity_usd`/`close_liquidity_usd`) and full history `net_flow_included` flags which set you got. New types: `Candle`, `CandlesResponse`, `CandlesParams`, `CandleTimeframe`.
18
+ >
19
+ > **New in 2.13.0** — **Token risk score.** `client.alpha.risk(mint)` returns a transparent 0–100 rug-risk/safety score (higher = riskier) for any token: a `band` (`safe`/`caution`/`danger`), an explainable `factors[]` array (each with `key`, `label`, `status`, `points`, `detail`) that sums into the score, and the raw `inputs` it was computed from mint/freeze authority revocation, liquidity USD + liquidity-to-MC ratio, transfer fee bps, Token-2022 flag, burn detection, launch cohort (SOL + size), deployer bond rate + total deployed, KOL signal, and blacklist status. Plus `score_version` and `as_of`. **PRO/ULTRA only.** New types: `TokenRiskResponse`, `TokenRiskFactor`, `TokenRiskInputs`, `TokenRiskBand`, `TokenRiskStatus`.
20
+ >
21
+ > **New in 2.12.0** — **Launch cohort, liquidity/MC ratio, deployer tier filter, KOL hold stats, and signal performance.** `TokenResponseBody` (single + batch) gains `liquidity_to_mc_ratio`, `launch_cohort_sol`, and `launch_cohort_size`. `client.token.list()` adds `min_liq_mc_ratio`, `max_liq_mc_ratio`, and `deployer_tier` filter params; list items gain `liquidity_to_mc_ratio` and `deployer_tier`. `KolLeaderboardEntry` gains `median_hold_minutes_30d` and `percentile_early_entry_30d`. New top-level method `client.getSignalPerformance(name)` calls `GET /signals/{name}/performance`.
22
+ >
23
+ > **New in 2.11.1** — **Deployer runner-rate fields.** Sniper deploys, deployer alerts/profiles, and leaderboard rows now carry `runner_rate` (fraction of the deployer's labeled tokens that ran peak ≥60min after deploy — vs dumped) and `labeled_tokens` (confidence denominator; gate on ≥3).
24
+ >
25
+ > **New in 2.11** — **Graduation events + dump-cluster detection.** Subscribe `token:graduations` for every pump.fun bond in real time tracked deployer or not with typed `GraduationEvent` payloads (mint, deployer tier, time-to-bond, MC at bond). Buyer-quality `breakdown` adds `dump_cluster_count` (out-of-sample validated: 3+ such wallets in the first-20 94% dump vs 61% base) and `recycled_early_buyer_count` (high count with zero cluster leans runner). DEX firehose: replay buffer deepened to ~5 minutes; mint-scoped subs now receive in-band `dex:graduations` frames the bond lands on the same connection as your position's trade flow.
26
+
27
+ > **New in 2.9** — **Deshred Sniper Alerts.** `client.sniper.recent()` surfaces new pump.fun deploys reconstructed from shred-level data ~500ms before the chain confirms thema measured head start over any confirmed-stream feed. PRO sees elite/good deployers; ULTRA sees every tier and maintains a custom deployer watchlist (`client.sniper.addToWatchlist()`). Use the `sniper:deploys` WebSocket channel or `sniper:deploy` webhook for live push instead of polling.
28
+ >
29
+ > **New in 2.8** — **Price alerts, scout leaderboard, wallet derived stats.** `client.priceAlerts.*` — CRUD for token MC dip/recovery alerts delivered via webhook or WebSocket (PRO=5, ULTRA=25). `client.kol.scoutLeaderboard()` — top scouts ranked by first-touch follow-on rate. `client.kol.coordinationHistory()` and `client.token.peakHistory()` expose the historical record. `client.wallet.stats()` now returns a `derived` block: `win_rate`, `roi`, `verdict`, and `biggest_miss`.
30
+ >
31
+ > **New in 2.7** — **Universal Wallet API.** `client.wallet.stats()`, `client.wallet.pnl()`, `client.wallet.positions()`, `client.wallet.trades()` — FIFO cost-basis PnL, open positions hydrated with live prices, and cursor-paginated raw trades for **any** Solana wallet (not just curated KOLs). PRO+. Server-side cache (5min/1h/24h based on activity) cache hits don't count against your quota.
32
+ >
33
+ > **New in 2.6.1** *(2026-05-13)* — **Velocity types fixed.** Velocity fields are now correctly typed as `mc_change_pct`, `volume_usd`, `mev_volume_pct` each its own object keyed by `5m`/`15m`/`1h`/`2h`/`4h` to match the actual API response. The 2.6.0 shape (`velocity[window].mc_change_pct`) was wrong; clients reading it would get `undefined`. Patch is type-only no runtime breaking changes.
34
+ >
35
+ > **New in 2.6.0** *(2026-05-12)* — **Token directory + self-inspection.** `client.token.list({ min_liq, min_volume_1h_usd, max_mev_share_pct, mc_change_1h_min_pct, sort, ... })` — browse and filter every active mint, with default `min_liq=2000` to skip phantom-MC dust. `client.me()` — read your tier, daily/burst quota state, and per-feature usage in one call (no header parsing). Velocity / MEV-share fields added to every `TokenResponseBody`: `mc_change_pct`, `volume_usd`, `mev_volume_pct` (each keyed by `5m`/`15m`/`1h`/`2h`/`4h`) plus `history_age_seconds` on the parent. `/token/{mint}` 400s now ship `code`, `reason`, `received_length`, `example`, and `docs` URL — stop guessing why a mint failed. Deprecated `avg_entry_mc_usd` / `entry_mc_samples` removed from leaderboard types. All other 2.5.x APIs unchanged.
36
+
37
+ > **Build Solana trading bots, analytics dashboards, KOL copy-trading tools, deshred sniper bots, and ecosystem browsers.**
38
+
39
+ ## Quick start (10 seconds)
40
+
41
+ ```bash
42
+ npm install madeonsol
43
+ ```
44
+
45
+ ```ts
46
+ import { MadeOnSol } from "madeonsol";
47
+ const client = new MadeOnSol({ apiKey: "msk_..." }); // free tier at madeonsol.com/pricing
48
+ const { trades } = await client.kol.feed({ limit: 5, action: "buy" });
49
+ ```
50
+
51
+ | Feature | Description |
52
+ |---|---|
53
+ | **KOL Tracker** | Real-time trade feed, PnL leaderboard with five time windows (today, 7d, 30d, 90d, 180d), coordination detection, per-wallet profiles, and deep PnL analytics for 1,069 tracked KOL wallets. **180 days of trade history** retained. |
54
+ | **Deshred Sniper** | Deploy feed reconstructed from shred-level data surfaces new pump.fun launches **~500ms before on-chain confirmation**. PRO: elite/good deployers. ULTRA: all tiers + custom watchlist. Use WebSocket/webhook for live push. |
55
+ | **Alpha Wallet Intel** | Leaderboard of 1M+ scored early-buyer wallets, full wallet profiles, linked-wallet clustering, token cap-table enrichment, and 0–100 buyer quality scores with dump-cluster wallet detection. |
56
+ | **Token Risk Score** | Transparent 0–100 rug-risk/safety score per token with a `safe`/`caution`/`danger` band, explainable factor breakdown, and the raw inputs (authorities, liquidity, transfer fee, launch cohort, deployer bond rate, KOL signal, blacklist). PRO/ULTRA. |
57
+ | **Universal Wallet** | FIFO cost-basis PnL, open positions (hydrated with live prices), and raw trade history for **any** Solana wallet not just curated KOLs. 90-day window, server-side cache. PRO+. |
58
+ | **Price Alerts** | Token MC dip/recovery alerts delivered via WebSocket or HMAC-signed webhook. PRO: 5 rules, ULTRA: 25. |
59
+ | **Wallet Tracker** | Monitor any Solana wallet for swaps and transfers. Track up to 10/50/100 wallets (Free/Pro/Ultra). Full wallets, counterparties, and tx_signatures on every tier. 120-day event retention. WS events on ULTRA. |
60
+ | **Deployer Hunter** | 23,000+ pump.fun deployers scored by bonding rate — tier leaderboard, deploy alerts, deployer profiles, and best-tokens feed. |
61
+ | **DEX Trade Stream** | Real-time WebSocket stream of ALL Solana DEX trades across 9+ programs — filter by token, wallet, DEX, deployer tier, or trade size. ~5 min replay + in-band graduation frames on mint-scoped subs. ULTRA. |
62
+ | **Webhooks** | Push notifications for KOL trades, coordination signals, deployer alerts, and wallet tracker events (Pro/Ultra) |
63
+ | **Tool Directory** | Search 1,070+ Solana tools and dApps indexed on MadeOnSol |
64
+
65
+ **Links:** [Full docs](https://madeonsol.com/solana-api) · [Website](https://madeonsol.com) · [API docs](https://madeonsol.com/api-docs)
66
+
67
+ ## Authentication
68
+
69
+ Get a free API key at [madeonsol.com/pricing](https://madeonsol.com/pricing). Keys start with `msk_`.
70
+
71
+ ---
72
+
73
+ ## Install
74
+
75
+ ```bash
76
+ npm install madeonsol
77
+ # or
78
+ yarn add madeonsol
79
+ # or
80
+ pnpm add madeonsol
81
+ ```
82
+
83
+ Requires **Node.js ≥ 18** (uses native `fetch`). Works out of the box in Cloudflare Workers, Vercel Edge, and Bun.
84
+
85
+ ---
86
+
87
+ ## Quick start
88
+
89
+ ```ts
90
+ import { MadeOnSol } from "madeonsol";
91
+
92
+ const client = new MadeOnSol({ apiKey: "msk_your_api_key_here" });
93
+
94
+ // Latest KOL buy trades
95
+ const { trades } = await client.kol.feed({ limit: 10, action: "buy" });
96
+ console.log(trades[0].kol_name, "bought", trades[0].token_symbol);
97
+
98
+ // Deshred sniper ~500ms before on-chain confirmation (PRO/ULTRA)
99
+ const { deploys } = await client.sniper.recent({ limit: 20, min_bond_rate: 0.5 });
100
+ console.log(deploys[0].token_name, "deployed by", deploys[0].deployer_tier, "tier deployer");
101
+
102
+ // Multi-KOL coordination signal
103
+ const { coordination } = await client.kol.coordination({ min_kols: 3, min_score: 70 });
104
+
105
+ // FIFO PnL for any wallet (PRO+)
106
+ const pnl = await client.wallet.pnl("ASVz...ybJk");
107
+ console.log(`Realized: ${pnl.summary.realized_sol} SOL · Win rate: ${(pnl.summary.win_rate! * 100).toFixed(1)}%`);
108
+
109
+ // Search Solana tools
110
+ const { tools } = await client.tools.search({ q: "trading", limit: 10 });
111
+ ```
112
+
113
+ ---
114
+
115
+ ## Use cases
116
+
117
+ - **Copy-trading bot** — stream KOL buys via `client.kol.feed()` and mirror trades
118
+ - **Deshred sniper** — `client.sniper.recent()` or subscribe to `sniper:deploys` WebSocket for ~500ms pre-confirm deploy signals
119
+ - **DEX trade sniping** — subscribe to the all-DEX stream filtered by token, wallet, or deployer tier
120
+ - **Graduation sniper / position manager** — subscribe `token:graduations` for every pump.fun bond in real time, or hold a mint-scoped firehose sub and get the bond in-band with your position's trade flow
121
+ - **Coordination detector** — flag tokens with `client.kol.coordination({ min_kols: 3, min_score: 70 })`
122
+ - **Scout signal** — track first-KOL-touch events filtered to S/A-tier scouts via `client.kol.firstTouches({ preset: "scout" })`
123
+ - **Rug-risk gate** — score a token with `client.alpha.risk(mint)` and skip anything in the `danger` band before buying
124
+ - **Wallet analyser** — `client.wallet.pnl()` for FIFO cost-basis PnL on any Solana wallet
125
+ - **Price alert bot** — `client.priceAlerts.create()` for MC dip/recovery alerts delivered via webhook
126
+ - **Analytics dashboard** — combine leaderboard, PnL, token velocity, and tool data
127
+ - **Telegram/Discord bot** — pipe alerts via webhooks into chat
128
+ - **Portfolio tracker** — use `client.kol.wallet()` to follow specific KOL positions
129
+
130
+ ---
131
+
132
+ ## API Reference
133
+
134
+ ### KOL Tracker — `client.kol`
135
+
136
+ #### `client.kol.feed(params?)`
137
+
138
+ Live feed of trades made by tracked KOL wallets.
139
+
140
+ ```ts
141
+ const { trades, count } = await client.kol.feed({
142
+ limit: 50, // 1–100, default 50
143
+ action: "buy", // "buy" | "sell"
144
+ kol: "7xKX...", // filter by specific wallet
145
+ });
146
+ ```
147
+
148
+ Returns: `KolFeedResponse` `{ trades: KolTrade[], count: number }`
149
+
150
+ Each `KolTrade` includes `market_cap_usd_at_trade` and `price_usd_at_trade` — the token's MC and price at the exact moment the swap fired, sourced from our in-memory price tracker (real-time, faster than Dexscreener spot). Use these to surface "KOL bought $X SOL of token at $Y MC" without a second lookup.
151
+
152
+ ---
153
+
154
+ #### `client.kol.leaderboard(params?)`
155
+
156
+ KOL PnL leaderboard ranked by realized profit.
157
+
158
+ ```ts
159
+ const { leaderboard, period } = await client.kol.leaderboard({
160
+ period: "7d", // "today" | "7d" | "30d" | "90d" | "180d", default "7d"
161
+ });
162
+ ```
163
+
164
+ > **180-day retention** KOL trade data is retained for 180 days (extended from 31 on 2026-04-07). The 90d and 180d windows fill up over time as the trade table accumulates.
165
+
166
+ Each `KolLeaderboardEntry` includes `median_hold_minutes_30d` (median position hold duration in minutes over the last 30 days) and `percentile_early_entry_30d` (early-entry percentile rank 0–100 over the last 30 days).
167
+
168
+ Returns: `KolLeaderboardResponse`
169
+
170
+ ---
171
+
172
+ #### `client.kol.wallet(wallet, params?)`
173
+
174
+ Full profile for a single KOL wallet, including trade history and optional per-token PnL breakdown.
175
+
176
+ ```ts
177
+ const profile = await client.kol.wallet("7xKX...", {
178
+ include: "pnl_by_token",
179
+ });
180
+ ```
181
+
182
+ Returns: `KolWalletProfile`
183
+
184
+ ---
185
+
186
+ #### `client.kol.coordination(params?)`
187
+
188
+ Detect tokens where multiple KOLs are buying simultaneously — a strong signal of coordinated pumps. **v1.1** adds peak-density windows, exit tracking, and a composite 0–100 coordination score.
189
+
190
+ ```ts
191
+ const { coordination, score_version, window_minutes } = await client.kol.coordination({
192
+ period: "24h", // "1h" | "6h" | "24h" | "7d", default "24h"
193
+ min_kols: 3, // 2–50, default 3
194
+ limit: 20, // 1–50, default 20
195
+ window_minutes: 15, // v1.1 — peak-density window in minutes (1–60)
196
+ min_score: 60, // v1.1 — filter by composite score (0–100)
197
+ include_majors: false, // v1.1 — include WIF/BONK/POPCAT
198
+ });
199
+
200
+ for (const c of coordination) {
201
+ console.log(c.token_symbol, "score", c.coordination_score, "peak", c.peak_kols, "exited", c.exited_count);
202
+ // c.kols[]: { name, wallet, buy_sol, sell_sol, exited }
203
+ }
204
+ ```
205
+
206
+ Returns: `KolCoordinationResponse` — `{ coordination: CoordinatedToken[], score_version, window_minutes }`
207
+
208
+ ---
209
+
210
+ #### `client.coordinationAlerts.*` (v1.1)
211
+
212
+ Create **real-time push alerts** that fire the moment a new coordination cluster forms. Alerts are evaluated per-trade by the signal-evaluator service (sub-second latency), delivered via WebSocket channel `kol:coordination` and/or HMAC-signed webhook. **PRO: 5 rules, ULTRA: 20 rules.**
213
+
214
+ ```ts
215
+ // Create a rule: ≥5 KOLs, 10-min window, score ≥70, webhook delivery
216
+ const { rule, webhook_secret } = await client.coordinationAlerts.create({
217
+ name: "strong-clusters",
218
+ min_kols: 5,
219
+ window_minutes: 10,
220
+ min_score: 70,
221
+ include_majors: false,
222
+ cooldown_min: 30, // don't re-fire same token within 30 min
223
+ score_jump_break: 15, // UNLESS score jumps by 15+ (catches conviction surges)
224
+ delivery_mode: "webhook", // "websocket" | "webhook" | "both"
225
+ webhook_url: "https://example.com/coord-hook",
226
+ });
227
+ // SAVE webhook_secret — used for HMAC-SHA256 signature verification.
228
+
229
+ await client.coordinationAlerts.list();
230
+ await client.coordinationAlerts.get(rule.id);
231
+ await client.coordinationAlerts.update(rule.id, { min_score: 80, is_active: false });
232
+ await client.coordinationAlerts.delete(rule.id);
233
+ ```
234
+
235
+ Webhook signatures: header `X-MadeOnSol-Signature` = `sha256(timestamp + "." + body)` with `webhook_secret` as the HMAC key. Reject deliveries older than ~5 min.
236
+
237
+ WebSocket delivery: subscribe to channel `kol:coordination` on `wss://madeonsol.com/ws/v1/stream` — events are user-scoped (you only receive your own rule fires).
238
+
239
+ ---
240
+
241
+ #### `client.priceAlerts.*` *(new in 2.8)*
242
+
243
+ **Sub-second token MC dip/recovery alerts.** Set a drop threshold on any token — when MC drops below baseline, a `price_alert:dip` event fires. Optionally track recovery. **PRO: 5 alerts, ULTRA: 25 alerts.**
244
+
245
+ ```ts
246
+ // Create: alert when token drops 20%, then notify when it recovers 15% from the dip low
247
+ const { alert, webhook_secret } = await client.priceAlerts.create({
248
+ token_mint: "So11111111111111111111111111111111111111112",
249
+ drop_pct: 20,
250
+ recovery_pct: 15,
251
+ name: "SOL dip tracker",
252
+ delivery_mode: "webhook",
253
+ webhook_url: "https://example.com/dip-hook",
254
+ });
255
+
256
+ await client.priceAlerts.list();
257
+ await client.priceAlerts.get(alert.id);
258
+ await client.priceAlerts.update(alert.id, { name: "Renamed", is_active: false });
259
+ await client.priceAlerts.delete(alert.id);
260
+
261
+ // Event history (30-day retention)
262
+ const { events } = await client.priceAlerts.events({ event_type: "dip", limit: 50 });
263
+ ```
264
+
265
+ Alert lifecycle: `watching` -> `dipped` -> `recovered` (terminal). One-shot per alert. Baseline MC captured at creation time. 30-day auto-expiry. Thresholds immutable delete and recreate to change.
266
+
267
+ WebSocket: subscribe to channel `price_alert:events` — user-scoped. Webhook: per-alert HMAC-SHA256 signed (same scheme as coordination alerts).
268
+
269
+ ---
270
+
271
+ #### `client.sniper.*` Deshred Sniper Alerts *(new in 2.9)*
272
+
273
+ **The fastest path to a new pump.fun launch.** Deploys are reconstructed from shred-level (**deshred**) data and surface in the feed **~500ms before the chain confirms them** — a measured head start versus any confirmed-stream feed. **PRO** sees elite + good deployers; **ULTRA** sees every tier and can keep a custom deployer watchlist.
274
+
275
+ ```ts
276
+ // Newest-first deshred deploy feed (PRO: elite/good · ULTRA: all tiers)
277
+ const { deploys } = await client.sniper.recent({ limit: 50, min_bond_rate: 0.5 });
278
+
279
+ // Audit one deployer's recent launches (ULTRA)
280
+ await client.sniper.byDeployer("7dEx...4pQ8");
281
+
282
+ // Custom watchlist — get deploys from only the deployers you track, any tier (ULTRA, max 50)
283
+ await client.sniper.addToWatchlist({ wallets: ["7dEx...4pQ8", "9aBc...2zZ1"], label: "alpha devs" });
284
+ await client.sniper.watchlist();
285
+ const { deploys: tracked } = await client.sniper.recent({ watchlist: true });
286
+ await client.sniper.removeFromWatchlist("7dEx...4pQ8");
287
+ ```
288
+
289
+ Detection is pre-execution, so payloads carry no MC/logs/balances — `confirmed_on_chain` is `"deshred"`. For **live** push (not polling), use the `sniper:deploy` webhook event or the `sniper:deploys` WebSocket channel. ~1–3% of detected deploys may abandon before settlement.
290
+
291
+ ---
292
+
293
+ #### `client.kol.scoutLeaderboard(params?)` *(new in 2.8)*
294
+
295
+ Scout leaderboard: top KOLs ranked by scout score, first-touch frequency, and swarm attraction rate. **ULTRA only.**
296
+
297
+ ```ts
298
+ const data = await client.kol.scoutLeaderboard({ limit: 20, scout_tier: "S", sort: "scout_score" });
299
+ ```
300
+
301
+ ---
302
+
303
+ #### `client.kol.coordinationHistory(params?)` *(new in 2.8)*
304
+
305
+ Historical coordination alert fires — past events with token, score, KOL count. **ULTRA only.**
306
+
307
+ ```ts
308
+ const data = await client.kol.coordinationHistory({ limit: 50, min_score: 70 });
309
+ ```
310
+
311
+ ---
312
+
313
+ #### `client.token.kolConsensus(mint)` *(new in 2.8)*
314
+
315
+ KOL consensus on a token: how many bought/sold, exit rate, net flow, median entry MC. **ULTRA** gets individual wallet arrays.
316
+
317
+ ```ts
318
+ const consensus = await client.token.kolConsensus("4sVahM4U8js62mQV58ABSkNRhf6Ztc7Xs2LXUznNpump");
319
+ ```
320
+
321
+ ---
322
+
323
+ #### `client.token.peakHistory(mint)` *(new in 2.8)*
324
+
325
+ Peak MC history: ATH, decline from peak, MC at bond and at 1h/6h/24h/7d after bond.
326
+
327
+ ```ts
328
+ const peak = await client.token.peakHistory("4sVahM4U8js62mQV58ABSkNRhf6Ztc7Xs2LXUznNpump");
329
+ ```
330
+
331
+ ---
332
+
333
+ #### `client.kol.firstTouches(params?)` *(new in 2.2)*
334
+
335
+ Recent first-KOL-touch events on tokens every time a tracked KOL was the first to buy a given mint. Filterable by **scout tier** (S/A/B/C from the per-KOL `mv_kol_scout_score` view), KOL winrate, token age, mint suffix, etc.
336
+
337
+ **Backtested signal:** top scouts attract ≥3 follow-on KOLs within 4h ~50% of the time vs ~14% baseline (38d / 491k buys / 72,549 events). The full leaderboard is at [madeonsol.com/kol/scouts](https://madeonsol.com/kol/scouts).
338
+
339
+ ```ts
340
+ // S-tier scouts on tokens younger than 1h
341
+ const { events } = await client.kol.firstTouches({
342
+ preset: "scout",
343
+ min_scout_tier: "S",
344
+ limit: 20,
345
+ });
346
+
347
+ for (const e of events) {
348
+ console.log(e.first_kol.name, "scouted", e.token_symbol, `(scout_score=${e.first_kol.scout_score}%)`);
349
+ }
350
+ ```
351
+
352
+ Filter knobs: `since`, `before`, `limit`, `kol`, `min_kol_winrate_7d`, `min_scout_tier`, `min_n_touches`, `strategy`, `token_age_max_min`, `min_first_buy_sol`, `mint_suffix`, `preset` (`"scout"` or `"fresh_launch"`), `include` (e.g. `"followers_4h"`).
353
+
354
+ > **Don't poll — push.** Median lead time before the second KOL is **12 seconds**, so REST polling will lose the swarm. Subscribe to the `kol:first_touches` WebSocket channel (PRO+) or, on Ultra, create an HMAC-signed webhook subscription via `client.firstTouchSubscriptions.create({...})`.
355
+
356
+ Returns: `FirstTouchesResponse`
357
+
358
+ ---
359
+
360
+ #### `client.firstTouchSubscriptions.*` *(Ultra)*
361
+
362
+ Create push-delivery rules for first-touch events. Up to 10 active subscriptions per Ultra user.
363
+
364
+ ```ts
365
+ const { subscription, webhook_secret } = await client.firstTouchSubscriptions.create({
366
+ name: "S-tier scouts on pump tokens",
367
+ filters: { min_scout_tier: "S", mint_suffix: "pump" },
368
+ delivery_mode: "webhook",
369
+ webhook_url: "https://my.bot/hooks/scout",
370
+ });
371
+ // store webhook_secret — shown once
372
+
373
+ await client.firstTouchSubscriptions.list();
374
+ await client.firstTouchSubscriptions.update(subscription.id, { is_active: false });
375
+ await client.firstTouchSubscriptions.delete(subscription.id);
376
+ ```
377
+
378
+ Same HMAC scheme as coordination alerts. WebSocket channel: `kol:first_touches`.
379
+
380
+ ---
381
+
382
+ #### `client.kol.token(mint)`
383
+
384
+ KOL buy/sell activity for a specific token mint.
385
+
386
+ ```ts
387
+ const activity = await client.kol.token("EPjFW...");
388
+ ```
389
+
390
+ Returns: `KolTokenActivity`
391
+
392
+ ---
393
+
394
+ #### `client.kol.pnl(wallet, params?)`
395
+
396
+ Deep per-wallet PnL breakdown with equity curve, risk metrics, and position history.
397
+
398
+ ```ts
399
+ const pnl = await client.kol.pnl("7xKX...", {
400
+ period: "30d", // "7d" | "30d" | "90d" | "180d", default "30d"
401
+ });
402
+ // All tiers: summary + equity curve + closed positions
403
+ // ULTRA: + open positions (tokens bought but not yet sold)
404
+ ```
405
+
406
+ Returns: `KolPnlResponse`
407
+
408
+ ---
409
+
410
+ #### `client.kol.trendingTokens(params?)`
411
+
412
+ Tokens ranked by KOL buy volume across multiple time windows.
413
+
414
+ ```ts
415
+ const { tokens } = await client.kol.trendingTokens({
416
+ period: "1h", // "5m" | "15m" | "30m" | "1h" | "4h" | "8h" | "12h", default "1h"
417
+ min_kols: 2, // minimum distinct KOL buyers
418
+ limit: 20, // 1–50, default 20
419
+ });
420
+ // Available on all tiers; ULTRA unlocks full KOL wallet addresses per token
421
+ ```
422
+
423
+ Returns: `KolTrendingTokensResponse`
424
+
425
+ ---
426
+
427
+ ### Alpha Wallet Intelligence — `client.alpha`
428
+
429
+ #### `client.alpha.leaderboard(params?)`
430
+
431
+ Leaderboard of 1M+ scored early-buyer wallets ranked by win rate, PnL, or ROI.
432
+
433
+ ```ts
434
+ const { wallets } = await client.alpha.leaderboard({
435
+ period: "30d", // "7d" | "30d" | "90d", default "30d"
436
+ sort: "win_rate", // "win_rate" | "pnl" | "roi"
437
+ min_tokens: 5,
438
+ exclude_bots: true,
439
+ });
440
+ // Up to 100 results on Free/Pro; ULTRA unlocks 500 + bot signals
441
+ ```
442
+
443
+ Returns: `AlphaLeaderboardResponse`
444
+
445
+ ---
446
+
447
+ #### `client.alpha.wallet(wallet)`
448
+
449
+ Full profile for an alpha wallet including per-token history and bot signals. ULTRA only.
450
+
451
+ ```ts
452
+ const profile = await client.alpha.wallet("7xKX...");
453
+ ```
454
+
455
+ Returns: `AlphaWalletResponse`
456
+
457
+ ---
458
+
459
+ #### `client.alpha.linked(wallet)`
460
+
461
+ Linked-wallet clustering — wallets that co-bought with this address within 2 seconds. ULTRA only.
462
+
463
+ ```ts
464
+ const { linked } = await client.alpha.linked("7xKX...");
465
+ ```
466
+
467
+ Returns: `AlphaLinkedResponse`
468
+
469
+ ---
470
+
471
+ #### `client.alpha.capTable(mint)`
472
+
473
+ First buyers for a token enriched with historical win rates, PnL, and KOL identity. PRO/ULTRA.
474
+
475
+ ```ts
476
+ const { buyers } = await client.alpha.capTable("EPjFW...");
477
+ ```
478
+
479
+ Returns: `AlphaCapTableResponse`
480
+
481
+ ---
482
+
483
+ #### `client.alpha.buyerQuality(mint)`
484
+
485
+ 0–100 cohort quality score based on the profile of a token's first buyers. All tiers. 5-minute cache.
486
+
487
+ ```ts
488
+ const { score } = await client.alpha.buyerQuality("EPjFW...");
489
+ ```
490
+
491
+ Returns: `AlphaBuyerQualityResponse`
492
+
493
+ ---
494
+
495
+ #### `client.alpha.risk(mint)`
496
+
497
+ Transparent 0–100 token rug-risk/safety score (higher = riskier). Returns a `band` (`safe`/`caution`/`danger`), an explainable `factors[]` array that sums into `risk_score`, and the raw `inputs` (mint/freeze authority revocation, liquidity USD + liquidity-to-MC ratio, transfer fee bps, Token-2022 flag, burn detection, launch cohort SOL + size, deployer bond rate + total deployed, KOL signal, blacklist status). PRO/ULTRA — BASIC receives HTTP 403.
498
+
499
+ ```ts
500
+ const { risk_score, band, factors } = await client.alpha.risk("EPjFW...");
501
+ if (band === "danger") return; // skip risky tokens
502
+ ```
503
+
504
+ Returns: `TokenRiskResponse`
505
+
506
+ ---
507
+
508
+ #### `client.alpha.candles(mint, params?)`
509
+
510
+ OHLCV candlestick time-series — the persisted price/MC trajectory, rolled up to any timeframe on read. **PRO**: OHLCV (last 30 days). **ULTRA**: + per-bar net flow (buy/sell volume, `net_volume_usd`, counts, MEV volume), liquidity delta, and full retained history. Params: `tf` (`1m`|`5m`|`15m`|`1h`|`4h`|`1d`, default `1h`), `limit` (1–1000, default 200), `from`/`to` (ISO8601). `net_flow_included` flags whether the ULTRA fields are populated.
511
+
512
+ ```ts
513
+ const { candles, net_flow_included } = await client.alpha.candles("EPjFW...", { tf: "5m", limit: 100 });
514
+ const last = candles.at(-1);
515
+ console.log(last.close, net_flow_included ? `net flow $${last.net_volume_usd}` : "(ULTRA for net flow)");
516
+ ```
517
+
518
+ Returns: `CandlesResponse`
519
+
520
+ ---
521
+
522
+ #### `client.alpha.tokenFlow(mint, params?)`
523
+
524
+ Aggregated buy/sell flow for a token over a rolling window. **PRO+** (keyed). Params: `window` (`1h` default, or `24h`). Returns unique wallet/buyer/seller counts, buy/sell counts and SOL volumes, `net_sol` (`buy_sol − sell_sol`), and `trades_per_wallet`, plus the window `from` timestamp.
525
+
526
+ ```ts
527
+ const flow = await client.alpha.tokenFlow("EPjFW...", { window: "24h" });
528
+ console.log(`${flow.unique_wallets} wallets · net ${flow.net_sol} SOL`);
529
+ ```
530
+
531
+ Returns: `TokenFlowResponse`
532
+
533
+ ---
534
+
535
+ ### Wallet Tracker — `client.walletTracker`
536
+
537
+ #### `client.walletTracker.watchlist()`
538
+
539
+ List your tracked wallets and remaining capacity.
540
+
541
+ ```ts
542
+ const { wallets, capacity } = await client.walletTracker.watchlist();
543
+ // capacity: { used, limit } — Free: 10, Pro: 50, Ultra: 100
544
+ ```
545
+
546
+ Returns: `WatchlistResponse`
547
+
548
+ ---
549
+
550
+ #### `client.walletTracker.addToWatchlist(wallet, params?)`
551
+
552
+ Add a wallet to your watchlist. Tracking begins immediately.
553
+
554
+ ```ts
555
+ await client.walletTracker.addToWatchlist("7xKX...", { label: "whale" });
556
+ ```
557
+
558
+ ---
559
+
560
+ #### `client.walletTracker.removeFromWatchlist(wallet)`
561
+
562
+ Remove a wallet from your watchlist.
563
+
564
+ ```ts
565
+ await client.walletTracker.removeFromWatchlist("7xKX...");
566
+ ```
567
+
568
+ ---
569
+
570
+ #### `client.walletTracker.updateLabel(wallet, label)`
571
+
572
+ Update the label for a tracked wallet.
573
+
574
+ ```ts
575
+ await client.walletTracker.updateLabel("7xKX...", "smart money");
576
+ ```
577
+
578
+ ---
579
+
580
+ #### `client.walletTracker.trades(params?)`
581
+
582
+ Historical swap and transfer events for your watched wallets. 120-day retention.
583
+
584
+ ```ts
585
+ const { events } = await client.walletTracker.trades({
586
+ wallet: "7xKX...", // filter by specific wallet
587
+ action: "buy", // "buy" | "sell"
588
+ event_type: "swap", // "swap" | "transfer"
589
+ limit: 50,
590
+ before: "2026-04-01T00:00:00Z", // ISO 8601 cursor
591
+ });
592
+ ```
593
+
594
+ Returns: `WalletTrackerTradesResponse`
595
+
596
+ ---
597
+
598
+ #### `client.walletTracker.summary(params?)`
599
+
600
+ Per-wallet stats across your watchlist: swap counts, SOL bought/sold, last event time.
601
+
602
+ ```ts
603
+ const { wallets } = await client.walletTracker.summary({
604
+ period: "7d", // "24h" | "7d" | "30d", default "7d"
605
+ wallet: "7xKX...", // optional: single wallet
606
+ });
607
+ ```
608
+
609
+ Returns: `WalletTrackerSummaryResponse`
610
+
611
+ ---
612
+
613
+ ### Universal Wallet — `client.wallet` *(new in 2.7)*
614
+
615
+ Per-wallet endpoints that work on **any** Solana wallet, not just curated KOLs. FIFO cost-basis PnL over the last 90 days. PRO+ on every method. Results are cached server-side in `wallet_analyses` with dynamic TTL (5min / 1h / 24h based on last activity); cache hits don't count against your daily quota.
616
+
617
+ **Cost-basis honesty:** observable only inside the 90-day data window. Wallets that sold tokens bought before that window have the overflow silently discarded rather than fabricated. `notes.cost_basis_observable_from` makes the cutoff visible per call.
618
+
619
+ #### `client.wallet.stats(address)`
620
+
621
+ Aggregate stats over 90d plus cross-product flags (KOL / alpha / deployer). Includes enrichments: top traded tokens with realized PnL, trading style, deployer tier mix, recent trades. **v2.8** adds `derived` block: win rate, ROI, best/worst trade, biggest miss (token sold that later mooned), and AI-classified verdict.
622
+
623
+ ```ts
624
+ const { stats, flags, derived } = await client.wallet.stats("ASVz...ybJk");
625
+ console.log(`${flags.kol_name ?? address}: ${stats?.total_trades} trades`);
626
+ if (derived?.verdict) {
627
+ console.log(`${derived.verdict.label}: ${derived.verdict.description}`);
628
+ }
629
+ if (derived?.biggest_miss) {
630
+ console.log(`Biggest miss: ${derived.biggest_miss.token_symbol} missed +${derived.biggest_miss.missed_sol.toFixed(1)} SOL`);
631
+ }
632
+ ```
633
+
634
+ Returns: `WalletStatsResponse` (404 if the wallet has no trades and no flag-table presence).
635
+
636
+ ---
637
+
638
+ #### `client.wallet.pnl(address)`
639
+
640
+ Full FIFO cost-basis PnL: realized + unrealized SOL, profit factor, max drawdown, avg + median hold minutes, daily UTC PnL curve, closed positions sorted by pnl desc (with ROI %, hold time, win/loss), and open positions hydrated with live current prices from the market-cap tracker.
641
+
642
+ ```ts
643
+ const pnl = await client.wallet.pnl("ASVz...ybJk");
644
+ console.log(`Realized: ${pnl.summary.realized_sol} SOL · Unrealized: ${pnl.summary.unrealized_sol} SOL`);
645
+ console.log(`Win rate: ${(pnl.summary.win_rate! * 100).toFixed(1)}% · PF: ${pnl.summary.profit_factor}`);
646
+ for (const c of pnl.closed_positions.slice(0, 5)) {
647
+ const sign = c.pnl_sol > 0 ? "+" : "";
648
+ console.log(` ${c.token_mint.slice(0,8)}… ${sign}${c.pnl_sol} SOL (${c.roi_pct}% ROI, ${c.hold_minutes}m hold)`);
649
+ }
650
+ ```
651
+
652
+ Returns: `WalletPnlResponse`. Cache hits include `cache_hit: true` + `computed_at`; misses include `ttl_seconds`.
653
+
654
+ ---
655
+
656
+ #### `client.wallet.positions(address)`
657
+
658
+ Open positions only — lighter slice of `pnl()`. Shares the same cache, so calling this right after `pnl()` is an immediate hit.
659
+
660
+ ```ts
661
+ const { positions } = await client.wallet.positions("ASVz...ybJk");
662
+ for (const p of positions) {
663
+ const u = p.unrealized_sol;
664
+ console.log(` ${p.token_mint.slice(0,8)}… cost ${p.cost_basis_sol} SOL unrealized ${u ?? "—"} SOL (${p.unrealized_pct ?? ""}%)`);
665
+ }
666
+ ```
667
+
668
+ Returns: `WalletPositionsResponse`. Mints without a current price return `unrealized_sol: null` rather than fabricated zero.
669
+
670
+ ---
671
+
672
+ #### `client.wallet.trades(address, params?)`
673
+
674
+ Cursor-paginated raw trades. Default window is the last 90 days; override via `since` / `until` (Unix epoch seconds). Default limit 100, max 500.
675
+
676
+ ```ts
677
+ let cursor: string | undefined;
678
+ while (true) {
679
+ const page = await client.wallet.trades("ASVz...ybJk", { limit: 200, cursor, action: "buy" });
680
+ for (const t of page.trades) processBuy(t);
681
+ if (!page.has_more) break;
682
+ cursor = page.next_cursor!;
683
+ }
684
+ ```
685
+
686
+ Params:
687
+ - `limit` — 1-500, default 100
688
+ - `cursor` — from `next_cursor` of previous response
689
+ - `action` `"buy"` or `"sell"`
690
+ - `token_mint` filter to one token
691
+ - `since` / `until` — Unix epoch seconds (default last 90d)
692
+
693
+ Returns: `WalletTradesResponse` with `trades[]` + `next_cursor` + `has_more` + `filters` echo.
694
+
695
+ ---
696
+
697
+ ### Deployer Hunter — `client.deployer`
698
+
699
+ #### `client.deployer.stats()`
700
+
701
+ Global statistics across all tracked deployer wallets.
702
+
703
+ ```ts
704
+ const stats = await client.deployer.stats();
705
+ console.log(stats.overall_bonding_rate); // e.g. 0.043
706
+ ```
707
+
708
+ Returns: `DeployerStats`
709
+
710
+ ---
711
+
712
+ #### `client.deployer.leaderboard(params?)`
713
+
714
+ Deployers ranked by bonding rate or recent performance.
715
+
716
+ ```ts
717
+ const { deployers } = await client.deployer.leaderboard({
718
+ tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
719
+ sort: "bonding_rate", // "bonding_rate" | "recent_bond_rate" | "total_bonded" | "last_deploy_at"
720
+ limit: 20, // 1–50, default 20
721
+ offset: 0,
722
+ });
723
+ ```
724
+
725
+ Returns: `DeployerLeaderboardResponse`
726
+
727
+ ---
728
+
729
+ #### `client.deployer.profile(wallet)`
730
+
731
+ Full profile for a single deployer wallet.
732
+
733
+ ```ts
734
+ const deployer = await client.deployer.profile("3xAB...");
735
+ console.log(deployer.tier, deployer.bonding_rate);
736
+ ```
737
+
738
+ Returns: `DeployerProfile`
739
+
740
+ ---
741
+
742
+ #### `client.deployer.tokens(wallet, params?)`
743
+
744
+ All tokens deployed by a specific wallet.
745
+
746
+ ```ts
747
+ const { tokens } = await client.deployer.tokens("3xAB...", {
748
+ limit: 20,
749
+ offset: 0,
750
+ });
751
+ ```
752
+
753
+ Returns: `DeployerTokensResponse`
754
+
755
+ ---
756
+
757
+ #### `client.deployer.alerts(params?)`
758
+
759
+ Real-time deploy alerts — fired when a tracked deployer launches a new token.
760
+
761
+ ```ts
762
+ const { alerts } = await client.deployer.alerts({
763
+ since: "2025-01-01T00:00:00Z", // ISO 8601
764
+ limit: 20,
765
+ tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
766
+ offset: 0,
767
+ });
768
+ ```
769
+
770
+ Each `DeployerAlert` carries the deploy details plus `deployer_sol_balance` — the deployer wallet's SOL balance at alert time (`number | null` when unknown).
771
+
772
+ Returns: `DeployerAlertsResponse`
773
+
774
+ ---
775
+
776
+ #### `client.deployer.alertStats(params?)`
777
+
778
+ Aggregated alert statistics by tier.
779
+
780
+ ```ts
781
+ const stats = await client.deployer.alertStats({ period: "7d" });
782
+ // "7d" | "30d" | "all", default "all"
783
+ ```
784
+
785
+ Returns: `DeployerAlertStats`
786
+
787
+ ---
788
+
789
+ #### `client.deployer.bestTokens(params?)`
790
+
791
+ Top-performing tokens from tracked deployers by peak market cap.
792
+
793
+ ```ts
794
+ const { tokens } = await client.deployer.bestTokens({
795
+ period: "7d", // "7d" | "30d" | "all", default "7d"
796
+ limit: 5, // 1–20, default 5
797
+ });
798
+ ```
799
+
800
+ Returns: `BestTokensResponse`
801
+
802
+ ---
803
+
804
+ #### `client.deployer.recentBonds(params?)`
805
+
806
+ Most recently bonded tokens from tracked deployers.
807
+
808
+ ```ts
809
+ const { bonds } = await client.deployer.recentBonds({ limit: 20 });
810
+ ```
811
+
812
+ Returns: `RecentBondsResponse`
813
+
814
+ ---
815
+
816
+ ### Token Intelligence `client.token`
817
+
818
+ Per-mint snapshots (price, MC, volume, deployer rep, KOL activity, blacklist flags, **v1.7 velocity windows + MEV-share**) and a filtered directory.
819
+
820
+ #### `client.token.get(mint)`
821
+
822
+ Comprehensive per-mint snapshot in one call. **ULTRA** also returns individual KOL wallet addresses in `top_buyers[]`.
823
+
824
+ ```ts
825
+ const { token } = await client.token.get("So11111111111111111111111111111111111111112");
826
+ console.log(token.price_usd, token.market_cap);
827
+ console.log(token.mc_change_pct?.["1h"]); // v1.7
828
+ console.log(token.mev_volume_pct?.["1h"]); // v1.7
829
+ ```
830
+
831
+ Invalid mints return a 400 with `code: "invalid_mint"`, `reason`, `received_length`, `example`, and `docs` URL — no trial and error.
832
+
833
+ Returns: `TokenResponse` (with `mc_change_pct` / `volume_usd` / `mev_volume_pct` (each keyed by 5m/15m/1h/2h/4h) + `history_age_seconds` as of 1.7). **New in 2.12:** also returns `liquidity_to_mc_ratio` (liquidity_usd / market_cap), `launch_cohort_sol` (total SOL spent by the first-20 buyers), and `launch_cohort_size` (count of first-20 buyers, 0–20).
834
+
835
+ #### `client.token.batch(mints)`
836
+
837
+ Batch lookup up to 50 mints in one round-trip. ~10–20× cheaper than N sequential calls. Each item returns the same shape as `get()` — including `liquidity_to_mc_ratio`, `launch_cohort_sol`, and `launch_cohort_size` *(new in 2.12)*.
838
+
839
+ ```ts
840
+ const { tokens } = await client.token.batch(["mint1", "mint2", "mint3"]);
841
+ ```
842
+
843
+ Returns: `TokenBatchResponse`
844
+
845
+ #### `client.token.list(params?)` *(new in 2.6 — PRO+)*
846
+
847
+ Filtered, sortable token directory. Default `min_liq=2000` trims the long tail of phantom-MC tokens from low-liquidity pools; pass `min_liq=0` to opt out.
848
+
849
+ **Server-side filters** (cheap, indexed): `min_mc`, `max_mc`, `min_liq`, `active_h`, `primary_dex` (`pumpfun`/`pumpswap`/`raydium`/`meteora`/`orca`/`raydium_clmm`), `authority_revoked`, `exclude_token2022`, `min_lp_burnt_pct`, `deployer_tier` (`elite`/`good`/`moderate`/`rising`/`cold`/`unranked`), `min_liq_mc_ratio`, `max_liq_mc_ratio`.
850
+
851
+ **Computed post-filters** (over-fetches 3×): `min_volume_1h_usd`, `max_mev_share_pct`, `mc_change_1h_min_pct`, `mc_change_1h_max_pct`. When any of these are set, `pagination.post_filtered` is `true` and page size may be smaller than `limit`.
852
+
853
+ Each item in `tokens[]` includes `liquidity_to_mc_ratio` and `deployer_tier` *(new in 2.12)*.
854
+
855
+ ```ts
856
+ // Momentum scanner: liquid mints up >20% in 1h, low bot share
857
+ const { tokens, pagination } = await client.token.list({
858
+ min_liq: 10000,
859
+ min_volume_1h_usd: 5000,
860
+ max_mev_share_pct: 60,
861
+ mc_change_1h_min_pct: 20,
862
+ sort: "mc_desc",
863
+ limit: 50,
864
+ });
865
+
866
+ // Cleanest filter for a sane "top by MC" feed
867
+ const { tokens } = await client.token.list({
868
+ min_liq: 25000,
869
+ active_h: 1,
870
+ authority_revoked: true,
871
+ sort: "mc_desc",
872
+ });
873
+ ```
874
+
875
+ Returns: `TokenListResponse` (with `tokens[]`, `pagination`, `filters` echo)
876
+
877
+ #### `client.token.batchBuyerQuality(mints)`
878
+
879
+ Batch buyer-quality scoring for up to 50 mints. Shares the same 5-minute LRU cache as `client.alpha.buyerQuality(mint)`.
880
+
881
+ Returns: `AlphaBuyerQualityBatchResponse`
882
+
883
+ ---
884
+
885
+ ### Account — `client.me()` *(new in 2.6)*
886
+
887
+ Inspect your tier, quota state, and feature usage in one call. Reads from the same in-memory counters that drive rate-limit enforcement, so `quota.daily.remaining` is authoritative — no header parsing needed. Works on every tier (BASIC/PRO/ULTRA).
888
+
889
+ ```ts
890
+ const me = await client.me();
891
+ console.log(`${me.tier}: ${me.quota.daily.remaining}/${me.quota.daily.limit} req left today`);
892
+ console.log(`Webhooks: ${me.features.webhooks.used}/${me.features.webhooks.limit}`);
893
+ console.log(`Copy-trade wallets: ${me.features.copytrade_wallets.used}/${me.features.copytrade_wallets.limit}`);
894
+
895
+ if (me.quota.daily.remaining < 100) {
896
+ // self-throttle
897
+ }
898
+ ```
899
+
900
+ Returns: `MeResponse`
901
+
902
+ ---
903
+
904
+ ### Signal Performance — `client.getSignalPerformance(name)` *(new in 2.12)*
905
+
906
+ Performance stats for a named signal: hit rate, precision, sample count, and lookback window.
907
+
908
+ ```ts
909
+ const perf = await client.getSignalPerformance("kol_coordination");
910
+ console.log(perf.precision, perf.hit_rate);
911
+ ```
912
+
913
+ Params: `name` — signal name (e.g. `"kol_coordination"`, `"first_touch_scout"`, `"deployer_elite"`).
914
+
915
+ Returns: `Promise<unknown>` — shape varies by signal name; see `/api-docs` for the full schema.
916
+
917
+ ---
918
+
919
+ ### Tool Directory — `client.tools`
920
+
921
+ #### `client.tools.search(params?)`
922
+
923
+ Search 950+ Solana tools indexed on MadeOnSol.
924
+
925
+ ```ts
926
+ const { tools, count } = await client.tools.search({
927
+ q: "trading bot", // full-text search
928
+ category: "trading", // category slug filter
929
+ limit: 20, // 1–50, default 20
930
+ });
931
+ ```
932
+
933
+ Returns: `ToolsSearchResponse`
934
+
935
+ ---
936
+
937
+ ### WebSocket Streaming — `client.stream`
938
+
939
+ #### `client.stream.getToken()`
940
+
941
+ Generate a 24-hour WebSocket streaming token. Pro/Ultra subscribers get `ws_url` for KOL/deployer event streaming. Ultra subscribers also get `dex_ws_url` for the all-DEX trade stream.
942
+
943
+ ```ts
944
+ const token = await client.stream.getToken();
945
+ console.log(token.ws_url); // wss://madeonsol.com/ws/v1/stream
946
+ console.log(token.dex_ws_url); // wss://madeonsol.com/ws/v1/dex-stream (Ultra only)
947
+ ```
948
+
949
+ Returns: `StreamToken` — `{ token, expires_at, ws_url, dex_ws_url?, usage }`
950
+
951
+ #### `client.stream.connect()` *(new in 2.10)*
952
+
953
+ Open a **managed** stream — token fetch + 24h refresh, auto-reconnect (backoff + jitter), heartbeat liveness, and typed events are handled for you. No need to touch `getToken()` or `ws` directly.
954
+
955
+ ```ts
956
+ const stream = client.stream.connect();
957
+ stream.on("kol:trade", (t) => console.log(t.token_symbol, t.action));
958
+ stream.on("deployer:alert", (a) => console.log("new deploy", a.token_mint));
959
+ stream.subscribe(["kol:trades", "deployer:alerts"]);
960
+ // stream.unsubscribe([...]) / stream.close() when done
961
+ ```
962
+
963
+ Channels: `kol:trades`, `kol:coordination`, `kol:first_touches`, `deployer:alerts`, `wallet_tracker:events`, `copytrade:signals`, `price_alert:events`, `sniper:deploys`, `token:graduations` (every pump.fun graduation in real time, tracked deployer or not — typed `GraduationEvent`). Lifecycle: `open`, `close`, `reconnect`, `heartbeat`, `error`. Node 22+ uses the global `WebSocket`; on Node < 22 also `npm i ws`.
964
+
965
+ ---
966
+
967
+ ### DEX Firehose (Ultra) — `wss://madeonsol.com/ws/v1/dex-stream`
968
+
969
+ Real-time trades across **9+ Solana DEX programs** (Pump.fun, PumpAMM, PumpSwap, Raydium AMM/CPMM/CAMM, Jupiter v6, Orca Whirlpool, Meteora DBC/DAMM, LaunchLab/bonk.fun) on a single normalized WebSocket. Server-side filters drop everything you don't care about before it hits your socket.
970
+
971
+ **Limits:** ULTRA = 2 connections, **10 named subscriptions per connection**, up to **500 trades replay** from a server-side buffer holding ~5 minutes of firehose history (not connection-scoped — covers trades from before you connected; newest-first, sort by `block_time`). Inbound rate limit: 5 messages/sec (excess emits one error per second).
972
+
973
+ #### Quick start
974
+
975
+ ```ts
976
+ import { WebSocket } from "ws"; // or native WebSocket in browsers/Bun
977
+
978
+ const { token, dex_ws_url } = await client.stream.getToken();
979
+ const ws = new WebSocket(`${dex_ws_url}?token=${token}`); // token MUST be appended as query param
980
+
981
+ ws.on("open", () => {
982
+ // Multi-subscription: each sub has its own sub_id and filters
983
+ ws.send(JSON.stringify({
984
+ type: "subscribe",
985
+ sub_id: "fresh-pumpfun",
986
+ replay: 50, // backfill up to 500 from ring buffer
987
+ filters: {
988
+ dex: "pumpfun",
989
+ token_age_max_seconds: 300, // first seen in last 5 min
990
+ min_sol: 0.5,
991
+ action: "buy",
992
+ },
993
+ }));
994
+ });
995
+
996
+ ws.on("message", (raw) => {
997
+ const msg = JSON.parse(raw.toString());
998
+ if (msg.channel === "dex:trades") {
999
+ // { sub_id, data: { wallet, mint, action, sol_amount, token_amount, dex, ... }, replay, ts }
1000
+ console.log(msg.sub_id, msg.data.dex, msg.data.action, msg.data.sol_amount);
1001
+ }
1002
+ });
1003
+ ```
1004
+
1005
+ #### Protocol client server
1006
+
1007
+ | `type` | Required fields | Notes |
1008
+ |---|---|---|
1009
+ | `subscribe` | `sub_id`, `filters` | Optional `replay: 1–500` |
1010
+ | `update` | `sub_id`, `filters` | Replaces filters in place — no disconnect needed |
1011
+ | `unsubscribe` | `sub_id` | Or omit `sub_id` to clear all subs |
1012
+ | `list` | — | Server replies with `{ type: "list", subs: [...] }` |
1013
+ | `ping` | — | Heartbeat — server replies `{ type: "pong" }` |
1014
+
1015
+ #### Server → client message shapes
1016
+
1017
+ ```ts
1018
+ { type: "connected", tier: "ULTRA", capabilities: { max_subs: 10, max_replay: 500, dex_names: [...], deployer_tiers: [...] } } // on connect
1019
+ { type: "subscribed", sub_id: "fresh-pumpfun", filters: { ... } }
1020
+ { type: "replay_done", sub_id: "fresh-pumpfun", count: 50 } // after backfill
1021
+ { type: "updated", sub_id: "fresh-pumpfun", filters: { ... } }
1022
+ { type: "unsubscribed", sub_id: "fresh-pumpfun" }
1023
+ { type: "list", subs: [{ sub_id, filters }] } // reply to { type: "list" }
1024
+ { type: "heartbeat", ts: 1712160000000 } // every 30s
1025
+ { type: "error", sub_id?, message: "..." }
1026
+ { channel: "dex:trades", sub_id, data: { ... }, replay: false, ts: 1712160000000 }
1027
+ ```
1028
+
1029
+ #### Filter dimensions
1030
+
1031
+ At least **one targeting filter** is required (otherwise the firehose would dump every trade). Filters compose with AND semantics.
1032
+
1033
+ | Filter | Type | Notes |
1034
+ |---|---|---|
1035
+ | `token_mint` / `token_mints` | string / string[] (≤50) | Targeting |
1036
+ | `wallet` / `wallets` | string / string[] (≤50) | Targeting |
1037
+ | `dex` | string \| string[] | `pumpfun`, `pumpamm`, `pumpswap`, `raydium`, `jupiter`, `orca`, `meteora`, `launchlab` |
1038
+ | `program` | string | Raw program ID |
1039
+ | `deployer_tier` | string \| string[] | `elite`, `good`, `moderate`, `rising`, `cold`, `unranked` (uses Deployer Hunter scoring) |
1040
+ | `token_age_max_seconds` | number | Only trades on mints first seen within window (uses persisted first-seen table) |
1041
+ | `market_cap_min_sol` / `market_cap_max_sol` | number | Bounded by current market cap (last trade price × cached supply, 1h TTL) |
1042
+ | `min_sol` / `max_sol` | number | Trade size bounds |
1043
+ | `action` | `"buy"` \| `"sell"` | Direction |
1044
+
1045
+ **Async filters** (`token_age`, `deployer_tier`, `market_cap`) evaluate against live state and are **skipped on replay**. The first trade for an unseen mint may be skipped while the supply fetch is in flight.
1046
+
1047
+ #### Multi-sub example
1048
+
1049
+ ```ts
1050
+ ws.send(JSON.stringify({ type: "subscribe", sub_id: "snipers", filters: { token_age_max_seconds: 60 } }));
1051
+ ws.send(JSON.stringify({ type: "subscribe", sub_id: "whales", filters: { min_sol: 50 } }));
1052
+ ws.send(JSON.stringify({ type: "subscribe", sub_id: "kol-mints", filters: { token_mints: ["EPjF...", "So11..."] } }));
1053
+
1054
+ // Tighten the snipers filter without disconnecting
1055
+ ws.send(JSON.stringify({ type: "update", sub_id: "snipers", filters: { token_age_max_seconds: 30, min_sol: 0.3 } }));
1056
+
1057
+ // Drop whales when you're done
1058
+ ws.send(JSON.stringify({ type: "unsubscribe", sub_id: "whales" }));
1059
+ ```
1060
+
1061
+ Each `dex:trades` message echoes the `sub_id` that matched, so you can route them locally without reapplying filter logic client-side.
1062
+
1063
+ ---
1064
+
1065
+ ### Copy-Trade — `client.copytrade` *(new in 2.10)*
1066
+
1067
+ Mirror N source wallets into actionable signals (delivered via webhook/WebSocket). PRO/ULTRA — PRO: 3 rules × 5 wallets, ULTRA: 20 × 50.
1068
+
1069
+ ```ts
1070
+ const { subscription, webhook_secret } = await client.copytrade.create({
1071
+ name: "whale mirror",
1072
+ source_wallets: ["WalletA…", "WalletB…"],
1073
+ sizing_mode: "fixed",
1074
+ sizing_amount: 0.5, // SOL per mirrored buy
1075
+ only_action: "buy",
1076
+ delivery_mode: "webhook",
1077
+ webhook_url: "https://you.example/hook",
1078
+ });
1079
+
1080
+ await client.copytrade.subscriptions(); // list rules
1081
+ await client.copytrade.update(subscription.id, { is_active: false });
1082
+ await client.copytrade.signals({ limit: 50 }); // 7-day fired-signal history
1083
+ await client.copytrade.delete(subscription.id);
1084
+ ```
1085
+
1086
+ ### Webhooks — `client.webhooks`
1087
+
1088
+ Manage push notification webhooks for real-time events (Pro: 3, Ultra: 10).
1089
+
1090
+ ```ts
1091
+ // Create a webhook
1092
+ const webhook = await client.webhooks.create({
1093
+ url: "https://example.com/hook",
1094
+ events: ["kol:trade", "deployer:alert"],
1095
+ filters: { min_sol: 1 },
1096
+ });
1097
+
1098
+ // List, update, delete
1099
+ const { webhooks } = await client.webhooks.list();
1100
+ await client.webhooks.update(webhook.id, { status: "paused" });
1101
+ await client.webhooks.delete(webhook.id);
1102
+ await client.webhooks.test(webhook.id);
1103
+ ```
1104
+
1105
+ ---
1106
+
1107
+ ## Error handling
1108
+
1109
+ All methods throw `MadeOnSolError` on non-2xx responses.
1110
+
1111
+ ```ts
1112
+ import { MadeOnSol, MadeOnSolError } from "madeonsol";
1113
+
1114
+ try {
1115
+ const profile = await client.kol.wallet("invalid-wallet");
1116
+ } catch (err) {
1117
+ if (err instanceof MadeOnSolError) {
1118
+ console.error(err.message); // human-readable message
1119
+ console.error(err.status); // HTTP status code, e.g. 404
1120
+ console.error(err.body); // raw response body
1121
+ }
1122
+ }
1123
+ ```
1124
+
1125
+ ---
1126
+
1127
+ ## Exported types
1128
+
1129
+ All types are exported from the main entry point:
1130
+
1131
+ ```ts
1132
+ import type {
1133
+ // Errors
1134
+ MadeOnSolError,
1135
+
1136
+ // KOL
1137
+ KolTrade,
1138
+ KolFeedParams,
1139
+ KolFeedResponse,
1140
+ KolLeaderboardParams,
1141
+ KolLeaderboardResponse,
1142
+ KolLeaderboardEntry,
1143
+ KolWalletParams,
1144
+ KolWalletProfile,
1145
+ KolCoordinationParams,
1146
+ KolCoordinationResponse,
1147
+ CoordinatedToken,
1148
+ KolTokenActivity,
1149
+ KolPnlByToken,
1150
+
1151
+ // Deployer
1152
+ DeployerStats,
1153
+ DeployerLeaderboardParams,
1154
+ DeployerLeaderboardResponse,
1155
+ DeployerLeaderboardEntry,
1156
+ DeployerProfile,
1157
+ DeployerToken,
1158
+ DeployerTokensParams,
1159
+ DeployerTokensResponse,
1160
+ DeployerAlertsParams,
1161
+ DeployerAlertsResponse,
1162
+ DeployerAlert,
1163
+ DeployerAlertStatsParams,
1164
+ DeployerAlertStats,
1165
+ BestTokensParams,
1166
+ BestTokensResponse,
1167
+ BestToken,
1168
+ RecentBondsParams,
1169
+ RecentBondsResponse,
1170
+ RecentBond,
1171
+
1172
+ // Tools
1173
+ ToolsSearchParams,
1174
+ ToolsSearchResponse,
1175
+ Tool,
1176
+
1177
+ // KOL PnL & Trending
1178
+ KolPnlResponse,
1179
+ KolTrendingTokensResponse,
1180
+ TrendingToken,
1181
+
1182
+ // Alpha Wallet Intelligence
1183
+ AlphaWalletEntry,
1184
+ AlphaLeaderboardResponse,
1185
+ AlphaWalletResponse,
1186
+ AlphaLinkedResponse,
1187
+ AlphaCapTableResponse,
1188
+ AlphaBuyerQualityResponse,
1189
+
1190
+ // Wallet Tracker
1191
+ WalletEntry,
1192
+ WatchlistResponse,
1193
+ WalletTrackerEvent,
1194
+ WalletTrackerTradesResponse,
1195
+ WalletTrackerSummaryResponse,
1196
+
1197
+ // Streaming
1198
+ StreamToken,
1199
+
1200
+ // Webhooks
1201
+ Webhook,
1202
+ WebhookCreateParams,
1203
+ WebhookUpdateParams,
1204
+ WebhookListResponse,
1205
+
1206
+ // Enums / unions
1207
+ KolAction,
1208
+ LeaderboardPeriod,
1209
+ CoordinationPeriod,
1210
+ DeployerTier,
1211
+ DeployerSortField,
1212
+ AlertPeriod,
1213
+ BestTokensPeriod,
1214
+ } from "madeonsol";
1215
+ ```
1216
+
1217
+ ---
1218
+
1219
+ ## Related
1220
+
1221
+ - [MadeOnSol website](https://madeonsol.com) — Browse 950+ Solana tools
1222
+ - [API documentation](https://madeonsol.com/api-docs) — Interactive endpoint reference
1223
+ - [MadeOnSol on GitHub](https://github.com/LamboPoewert/madeonsol) — Main project repository
1224
+
1225
+ ## Also Available
1226
+
1227
+ | Platform | Package |
1228
+ |---|---|
1229
+ | Rust | [`madeonsol`](https://crates.io/crates/madeonsol) on crates.io |
1230
+ | Python (LangChain, CrewAI) | [`madeonsol-x402`](https://pypi.org/project/madeonsol-x402/) on PyPI |
1231
+ | MCP Server (Claude, Cursor) | [`mcp-server-madeonsol`](https://www.npmjs.com/package/mcp-server-madeonsol) · [Smithery](https://smithery.ai/servers/madeonsol/solana-kol-intelligence) · [Glama](https://glama.ai/mcp/servers/LamboPoewert/mcp-server-madeonsol) |
1232
+ | ElizaOS | [`@madeonsol/plugin-madeonsol`](https://www.npmjs.com/package/@madeonsol/plugin-madeonsol) |
1233
+ | Solana Agent Kit | [`solana-agent-kit-plugin-madeonsol`](https://www.npmjs.com/package/solana-agent-kit-plugin-madeonsol) |
1234
+
1235
+ ---
1236
+
1237
+ ## License
1238
+
1239
+ MIT © [MadeOnSol](https://madeonsol.com)