madeonsol 2.6.1 → 2.6.3

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,933 +1,936 @@
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
- [![TypeScript](https://img.shields.io/badge/TypeScript-5.4+-blue?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org/)
6
- [![Zero Dependencies](https://img.shields.io/badge/dependencies-0-brightgreen?style=flat-square)](package.json)
7
- [![License: MIT](https://img.shields.io/badge/License-MIT-blue?style=flat-square)](LICENSE)
8
-
9
- Official TypeScript/JavaScript SDK for the **[MadeOnSol](https://madeonsol.com) Solana API** — zero dependencies, fully typed, works in Node.js ≥ 18 and edge runtimes.
10
- > Real-time Solana trading intelligence: track 1,000+ KOL wallets with <3s latency, score 6,700+ Pump.fun deployers by reputation, detect multi-KOL coordination signals, and stream every DEX trade across 9+ programs. Free tier: 200 requests/day at [madeonsol.com/developer](https://madeonsol.com/developer) — no credit card required.
11
-
12
- > **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.
13
- >
14
- > **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.
15
-
16
- > **Build Solana trading bots, analytics dashboards, KOL copy-trading tools, deployer sniper bots, and ecosystem browsers.**
17
-
18
- ## Quick start (10 seconds)
19
-
20
- ```bash
21
- npm install madeonsol
22
- ```
23
-
24
- ```ts
25
- import { MadeOnSol } from "madeonsol";
26
- const client = new MadeOnSol({ apiKey: "msk_..." }); // free key: https://madeonsol.com/developer
27
- const { trades } = await client.kol.feed({ limit: 5, action: "buy" });
28
- ```
29
-
30
- | Feature | Description |
31
- |---|---|
32
- | **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,000+ tracked KOL wallets. **180 days of trade history** retained. |
33
- | **Alpha Wallet Intel** | Leaderboard of 47,000+ scored early-buyer wallets, full wallet profiles, linked-wallet clustering, token cap-table enrichment, and 0–100 buyer quality scores. |
34
- | **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. |
35
- | **Deployer Hunter** | Pump.fun deployer scoring, tier leaderboard, deploy alerts, and bonding intelligence |
36
- | **DEX Trade Stream** | Real-time WebSocket stream of ALL Solana DEX trades filter by token, wallet, program, or trade size (Ultra) |
37
- | **Webhooks** | Push notifications for KOL trades, coordination signals, deployer alerts, and wallet tracker events (Pro/Ultra) |
38
- | **Tool Directory** | Search 950+ Solana tools and dApps indexed on MadeOnSol |
39
-
40
- **Links:** [Full docs](https://madeonsol.com/solana-api) · [Website](https://madeonsol.com) · [API docs](https://madeonsol.com/api-docs)
41
-
42
- ## Authentication
43
-
44
- Get a free API key at [madeonsol.com/developer](https://madeonsol.com/developer). Keys start with `msk_`.
45
-
46
- ---
47
-
48
- ## Install
49
-
50
- ```bash
51
- npm install madeonsol
52
- # or
53
- yarn add madeonsol
54
- # or
55
- pnpm add madeonsol
56
- ```
57
-
58
- Requires **Node.js ≥ 18** (uses native `fetch`). Works out of the box in Cloudflare Workers, Vercel Edge, and Bun.
59
-
60
- ---
61
-
62
- ## Quick start
63
-
64
- ```ts
65
- import { MadeOnSol } from "madeonsol";
66
-
67
- const client = new MadeOnSol({ apiKey: "msk_your_api_key_here" });
68
-
69
- // Latest KOL buy trades
70
- const { trades } = await client.kol.feed({ limit: 10, action: "buy" });
71
- console.log(trades[0].kol_name, "bought", trades[0].token_symbol);
72
-
73
- // Elite deployer leaderboard
74
- const { deployers } = await client.deployer.leaderboard({ tier: "elite" });
75
-
76
- // Recent deploy alerts
77
- const { alerts } = await client.deployer.alerts({ limit: 5 });
78
-
79
- // Search Solana tools
80
- const { tools } = await client.tools.search({ q: "trading", limit: 10 });
81
- ```
82
-
83
- ---
84
-
85
- ## Use cases
86
-
87
- - **Copy-trading bot** — stream KOL buys via `client.kol.feed()` and mirror trades
88
- - **DEX trade sniping** — subscribe to the all-DEX stream filtered by token or wallet
89
- - **Deployer sniper** — monitor `client.deployer.alerts()` for elite-tier launches
90
- - **Coordination detector** — flag tokens with `client.kol.coordination({ min_kols: 3 })`
91
- - **Scout signal** — track first-KOL-touch events filtered to S/A-tier scouts via `client.kol.firstTouches({ preset: "scout" })`
92
- - **Analytics dashboard** — combine leaderboard, PnL, and tool data
93
- - **Telegram/Discord bot** — pipe alerts via webhooks into chat
94
- - **Portfolio tracker** — use `client.kol.wallet()` to follow specific KOL positions
95
-
96
- ---
97
-
98
- ## API Reference
99
-
100
- ### KOL Tracker — `client.kol`
101
-
102
- #### `client.kol.feed(params?)`
103
-
104
- Live feed of trades made by tracked KOL wallets.
105
-
106
- ```ts
107
- const { trades, count } = await client.kol.feed({
108
- limit: 50, // 1–100, default 50
109
- action: "buy", // "buy" | "sell"
110
- kol: "7xKX...", // filter by specific wallet
111
- });
112
- ```
113
-
114
- Returns: `KolFeedResponse` — `{ trades: KolTrade[], count: number }`
115
-
116
- 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.
117
-
118
- ---
119
-
120
- #### `client.kol.leaderboard(params?)`
121
-
122
- KOL PnL leaderboard ranked by realized profit.
123
-
124
- ```ts
125
- const { leaderboard, period } = await client.kol.leaderboard({
126
- period: "7d", // "today" | "7d" | "30d" | "90d" | "180d", default "7d"
127
- });
128
- ```
129
-
130
- > **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.
131
-
132
- Returns: `KolLeaderboardResponse`
133
-
134
- ---
135
-
136
- #### `client.kol.wallet(wallet, params?)`
137
-
138
- Full profile for a single KOL wallet, including trade history and optional per-token PnL breakdown.
139
-
140
- ```ts
141
- const profile = await client.kol.wallet("7xKX...", {
142
- include: "pnl_by_token",
143
- });
144
- ```
145
-
146
- Returns: `KolWalletProfile`
147
-
148
- ---
149
-
150
- #### `client.kol.coordination(params?)`
151
-
152
- 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.
153
-
154
- ```ts
155
- const { coordination, score_version, window_minutes } = await client.kol.coordination({
156
- period: "24h", // "1h" | "6h" | "24h" | "7d", default "24h"
157
- min_kols: 3, // 2–50, default 3
158
- limit: 20, // 1–50, default 20
159
- window_minutes: 15, // v1.1 peak-density window in minutes (1–60)
160
- min_score: 60, // v1.1 filter by composite score (0–100)
161
- include_majors: false, // v1.1 include WIF/BONK/POPCAT
162
- });
163
-
164
- for (const c of coordination) {
165
- console.log(c.token_symbol, "score", c.coordination_score, "peak", c.peak_kols, "exited", c.exited_count);
166
- // c.kols[]: { name, wallet, buy_sol, sell_sol, exited }
167
- }
168
- ```
169
-
170
- Returns: `KolCoordinationResponse` — `{ coordination: CoordinatedToken[], score_version, window_minutes }`
171
-
172
- ---
173
-
174
- #### `client.coordinationAlerts.*` (v1.1)
175
-
176
- 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.**
177
-
178
- ```ts
179
- // Create a rule: ≥5 KOLs, 10-min window, score ≥70, webhook delivery
180
- const { rule, webhook_secret } = await client.coordinationAlerts.create({
181
- name: "strong-clusters",
182
- min_kols: 5,
183
- window_minutes: 10,
184
- min_score: 70,
185
- include_majors: false,
186
- cooldown_min: 30, // don't re-fire same token within 30 min
187
- score_jump_break: 15, // UNLESS score jumps by 15+ (catches conviction surges)
188
- delivery_mode: "webhook", // "websocket" | "webhook" | "both"
189
- webhook_url: "https://example.com/coord-hook",
190
- });
191
- // SAVE webhook_secret used for HMAC-SHA256 signature verification.
192
-
193
- await client.coordinationAlerts.list();
194
- await client.coordinationAlerts.get(rule.id);
195
- await client.coordinationAlerts.update(rule.id, { min_score: 80, is_active: false });
196
- await client.coordinationAlerts.delete(rule.id);
197
- ```
198
-
199
- Webhook signatures: header `X-MadeOnSol-Signature` = `sha256(timestamp + "." + body)` with `webhook_secret` as the HMAC key. Reject deliveries older than ~5 min.
200
-
201
- 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).
202
-
203
- ---
204
-
205
- #### `client.kol.firstTouches(params?)` *(new in 2.2)*
206
-
207
- 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.
208
-
209
- **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).
210
-
211
- ```ts
212
- // S-tier scouts on tokens younger than 1h
213
- const { events } = await client.kol.firstTouches({
214
- preset: "scout",
215
- min_scout_tier: "S",
216
- limit: 20,
217
- });
218
-
219
- for (const e of events) {
220
- console.log(e.first_kol.name, "scouted", e.token_symbol, `(scout_score=${e.first_kol.scout_score}%)`);
221
- }
222
- ```
223
-
224
- 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"`).
225
-
226
- > **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({...})`.
227
-
228
- Returns: `FirstTouchesResponse`
229
-
230
- ---
231
-
232
- #### `client.firstTouchSubscriptions.*` *(Ultra)*
233
-
234
- Create push-delivery rules for first-touch events. Up to 10 active subscriptions per Ultra user.
235
-
236
- ```ts
237
- const { subscription, webhook_secret } = await client.firstTouchSubscriptions.create({
238
- name: "S-tier scouts on pump tokens",
239
- filters: { min_scout_tier: "S", mint_suffix: "pump" },
240
- delivery_mode: "webhook",
241
- webhook_url: "https://my.bot/hooks/scout",
242
- });
243
- // store webhook_secret — shown once
244
-
245
- await client.firstTouchSubscriptions.list();
246
- await client.firstTouchSubscriptions.update(subscription.id, { is_active: false });
247
- await client.firstTouchSubscriptions.delete(subscription.id);
248
- ```
249
-
250
- Same HMAC scheme as coordination alerts. WebSocket channel: `kol:first_touches`.
251
-
252
- ---
253
-
254
- #### `client.kol.token(mint)`
255
-
256
- KOL buy/sell activity for a specific token mint.
257
-
258
- ```ts
259
- const activity = await client.kol.token("EPjFW...");
260
- ```
261
-
262
- Returns: `KolTokenActivity`
263
-
264
- ---
265
-
266
- #### `client.kol.pnl(wallet, params?)`
267
-
268
- Deep per-wallet PnL breakdown with equity curve, risk metrics, and position history.
269
-
270
- ```ts
271
- const pnl = await client.kol.pnl("7xKX...", {
272
- period: "30d", // "7d" | "30d" | "90d" | "180d", default "30d"
273
- });
274
- // All tiers: summary + equity curve + closed positions
275
- // ULTRA: + open positions (tokens bought but not yet sold)
276
- ```
277
-
278
- Returns: `KolPnlResponse`
279
-
280
- ---
281
-
282
- #### `client.kol.trendingTokens(params?)`
283
-
284
- Tokens ranked by KOL buy volume across multiple time windows.
285
-
286
- ```ts
287
- const { tokens } = await client.kol.trendingTokens({
288
- period: "1h", // "5m" | "15m" | "30m" | "1h" | "4h" | "8h" | "12h", default "1h"
289
- min_kols: 2, // minimum distinct KOL buyers
290
- limit: 20, // 1–50, default 20
291
- });
292
- // Available on all tiers; ULTRA unlocks full KOL wallet addresses per token
293
- ```
294
-
295
- Returns: `KolTrendingTokensResponse`
296
-
297
- ---
298
-
299
- ### Alpha Wallet Intelligence — `client.alpha`
300
-
301
- #### `client.alpha.leaderboard(params?)`
302
-
303
- Leaderboard of 47,000+ scored early-buyer wallets ranked by win rate, PnL, or ROI.
304
-
305
- ```ts
306
- const { wallets } = await client.alpha.leaderboard({
307
- period: "30d", // "7d" | "30d" | "90d", default "30d"
308
- sort: "win_rate", // "win_rate" | "pnl" | "roi"
309
- min_tokens: 5,
310
- exclude_bots: true,
311
- });
312
- // Up to 100 results on Free/Pro; ULTRA unlocks 500 + bot signals
313
- ```
314
-
315
- Returns: `AlphaLeaderboardResponse`
316
-
317
- ---
318
-
319
- #### `client.alpha.wallet(wallet)`
320
-
321
- Full profile for an alpha wallet including per-token history and bot signals. ULTRA only.
322
-
323
- ```ts
324
- const profile = await client.alpha.wallet("7xKX...");
325
- ```
326
-
327
- Returns: `AlphaWalletResponse`
328
-
329
- ---
330
-
331
- #### `client.alpha.linked(wallet)`
332
-
333
- Linked-wallet clustering — wallets that co-bought with this address within 2 seconds. ULTRA only.
334
-
335
- ```ts
336
- const { linked } = await client.alpha.linked("7xKX...");
337
- ```
338
-
339
- Returns: `AlphaLinkedResponse`
340
-
341
- ---
342
-
343
- #### `client.alpha.capTable(mint)`
344
-
345
- First buyers for a token enriched with historical win rates, PnL, and KOL identity. PRO/ULTRA.
346
-
347
- ```ts
348
- const { buyers } = await client.alpha.capTable("EPjFW...");
349
- ```
350
-
351
- Returns: `AlphaCapTableResponse`
352
-
353
- ---
354
-
355
- #### `client.alpha.buyerQuality(mint)`
356
-
357
- 0–100 cohort quality score based on the profile of a token's first buyers. All tiers. 5-minute cache.
358
-
359
- ```ts
360
- const { score } = await client.alpha.buyerQuality("EPjFW...");
361
- ```
362
-
363
- Returns: `AlphaBuyerQualityResponse`
364
-
365
- ---
366
-
367
- ### Wallet Tracker — `client.walletTracker`
368
-
369
- #### `client.walletTracker.watchlist()`
370
-
371
- List your tracked wallets and remaining capacity.
372
-
373
- ```ts
374
- const { wallets, capacity } = await client.walletTracker.watchlist();
375
- // capacity: { used, limit } — Free: 10, Pro: 50, Ultra: 100
376
- ```
377
-
378
- Returns: `WatchlistResponse`
379
-
380
- ---
381
-
382
- #### `client.walletTracker.addToWatchlist(wallet, params?)`
383
-
384
- Add a wallet to your watchlist. Tracking begins immediately.
385
-
386
- ```ts
387
- await client.walletTracker.addToWatchlist("7xKX...", { label: "whale" });
388
- ```
389
-
390
- ---
391
-
392
- #### `client.walletTracker.removeFromWatchlist(wallet)`
393
-
394
- Remove a wallet from your watchlist.
395
-
396
- ```ts
397
- await client.walletTracker.removeFromWatchlist("7xKX...");
398
- ```
399
-
400
- ---
401
-
402
- #### `client.walletTracker.updateLabel(wallet, label)`
403
-
404
- Update the label for a tracked wallet.
405
-
406
- ```ts
407
- await client.walletTracker.updateLabel("7xKX...", "smart money");
408
- ```
409
-
410
- ---
411
-
412
- #### `client.walletTracker.trades(params?)`
413
-
414
- Historical swap and transfer events for your watched wallets. 120-day retention.
415
-
416
- ```ts
417
- const { events } = await client.walletTracker.trades({
418
- wallet: "7xKX...", // filter by specific wallet
419
- action: "buy", // "buy" | "sell"
420
- event_type: "swap", // "swap" | "transfer"
421
- limit: 50,
422
- before: "2026-04-01T00:00:00Z", // ISO 8601 cursor
423
- });
424
- ```
425
-
426
- Returns: `WalletTrackerTradesResponse`
427
-
428
- ---
429
-
430
- #### `client.walletTracker.summary(params?)`
431
-
432
- Per-wallet stats across your watchlist: swap counts, SOL bought/sold, last event time.
433
-
434
- ```ts
435
- const { wallets } = await client.walletTracker.summary({
436
- period: "7d", // "24h" | "7d" | "30d", default "7d"
437
- wallet: "7xKX...", // optional: single wallet
438
- });
439
- ```
440
-
441
- Returns: `WalletTrackerSummaryResponse`
442
-
443
- ---
444
-
445
- ### Deployer Hunter — `client.deployer`
446
-
447
- #### `client.deployer.stats()`
448
-
449
- Global statistics across all tracked deployer wallets.
450
-
451
- ```ts
452
- const stats = await client.deployer.stats();
453
- console.log(stats.overall_bonding_rate); // e.g. 0.043
454
- ```
455
-
456
- Returns: `DeployerStats`
457
-
458
- ---
459
-
460
- #### `client.deployer.leaderboard(params?)`
461
-
462
- Deployers ranked by bonding rate or recent performance.
463
-
464
- ```ts
465
- const { deployers } = await client.deployer.leaderboard({
466
- tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
467
- sort: "bonding_rate", // "bonding_rate" | "recent_bond_rate" | "total_bonded" | "last_deploy_at"
468
- limit: 20, // 1–50, default 20
469
- offset: 0,
470
- });
471
- ```
472
-
473
- Returns: `DeployerLeaderboardResponse`
474
-
475
- ---
476
-
477
- #### `client.deployer.profile(wallet)`
478
-
479
- Full profile for a single deployer wallet.
480
-
481
- ```ts
482
- const deployer = await client.deployer.profile("3xAB...");
483
- console.log(deployer.tier, deployer.bonding_rate);
484
- ```
485
-
486
- Returns: `DeployerProfile`
487
-
488
- ---
489
-
490
- #### `client.deployer.tokens(wallet, params?)`
491
-
492
- All tokens deployed by a specific wallet.
493
-
494
- ```ts
495
- const { tokens } = await client.deployer.tokens("3xAB...", {
496
- limit: 20,
497
- offset: 0,
498
- });
499
- ```
500
-
501
- Returns: `DeployerTokensResponse`
502
-
503
- ---
504
-
505
- #### `client.deployer.alerts(params?)`
506
-
507
- Real-time deploy alerts — fired when a tracked deployer launches a new token.
508
-
509
- ```ts
510
- const { alerts } = await client.deployer.alerts({
511
- since: "2025-01-01T00:00:00Z", // ISO 8601
512
- limit: 20,
513
- tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
514
- offset: 0,
515
- });
516
- ```
517
-
518
- Returns: `DeployerAlertsResponse`
519
-
520
- ---
521
-
522
- #### `client.deployer.alertStats(params?)`
523
-
524
- Aggregated alert statistics by tier.
525
-
526
- ```ts
527
- const stats = await client.deployer.alertStats({ period: "7d" });
528
- // "7d" | "30d" | "all", default "all"
529
- ```
530
-
531
- Returns: `DeployerAlertStats`
532
-
533
- ---
534
-
535
- #### `client.deployer.bestTokens(params?)`
536
-
537
- Top-performing tokens from tracked deployers by peak market cap.
538
-
539
- ```ts
540
- const { tokens } = await client.deployer.bestTokens({
541
- period: "7d", // "7d" | "30d" | "all", default "7d"
542
- limit: 5, // 1–20, default 5
543
- });
544
- ```
545
-
546
- Returns: `BestTokensResponse`
547
-
548
- ---
549
-
550
- #### `client.deployer.recentBonds(params?)`
551
-
552
- Most recently bonded tokens from tracked deployers.
553
-
554
- ```ts
555
- const { bonds } = await client.deployer.recentBonds({ limit: 20 });
556
- ```
557
-
558
- Returns: `RecentBondsResponse`
559
-
560
- ---
561
-
562
- ### Token Intelligence — `client.token`
563
-
564
- Per-mint snapshots (price, MC, volume, deployer rep, KOL activity, blacklist flags, **v1.7 velocity windows + MEV-share**) and a filtered directory.
565
-
566
- #### `client.token.get(mint)`
567
-
568
- Comprehensive per-mint snapshot in one call. **ULTRA** also returns individual KOL wallet addresses in `top_buyers[]`.
569
-
570
- ```ts
571
- const { token } = await client.token.get("So11111111111111111111111111111111111111112");
572
- console.log(token.price_usd, token.market_cap);
573
- console.log(token.mc_change_pct?.["1h"]); // v1.7
574
- console.log(token.mev_volume_pct?.["1h"]); // v1.7
575
- ```
576
-
577
- Invalid mints return a 400 with `code: "invalid_mint"`, `reason`, `received_length`, `example`, and `docs` URL — no trial and error.
578
-
579
- 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)
580
-
581
- #### `client.token.batch(mints)`
582
-
583
- Batch lookup up to 50 mints in one round-trip. ~10–20× cheaper than N sequential calls.
584
-
585
- ```ts
586
- const { tokens } = await client.token.batch(["mint1", "mint2", "mint3"]);
587
- ```
588
-
589
- Returns: `TokenBatchResponse`
590
-
591
- #### `client.token.list(params?)` *(new in 2.6 — PRO+)*
592
-
593
- 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.
594
-
595
- **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`.
596
-
597
- **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`.
598
-
599
- ```ts
600
- // Momentum scanner: liquid mints up >20% in 1h, low bot share
601
- const { tokens, pagination } = await client.token.list({
602
- min_liq: 10000,
603
- min_volume_1h_usd: 5000,
604
- max_mev_share_pct: 60,
605
- mc_change_1h_min_pct: 20,
606
- sort: "mc_desc",
607
- limit: 50,
608
- });
609
-
610
- // Cleanest filter for a sane "top by MC" feed
611
- const { tokens } = await client.token.list({
612
- min_liq: 25000,
613
- active_h: 1,
614
- authority_revoked: true,
615
- sort: "mc_desc",
616
- });
617
- ```
618
-
619
- Returns: `TokenListResponse` (with `tokens[]`, `pagination`, `filters` echo)
620
-
621
- #### `client.token.batchBuyerQuality(mints)`
622
-
623
- Batch buyer-quality scoring for up to 50 mints. Shares the same 5-minute LRU cache as `client.alpha.buyerQuality(mint)`.
624
-
625
- Returns: `AlphaBuyerQualityBatchResponse`
626
-
627
- ---
628
-
629
- ### Account — `client.me()` *(new in 2.6)*
630
-
631
- 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/TRADER/PRO/ULTRA).
632
-
633
- ```ts
634
- const me = await client.me();
635
- console.log(`${me.tier}: ${me.quota.daily.remaining}/${me.quota.daily.limit} req left today`);
636
- console.log(`Webhooks: ${me.features.webhooks.used}/${me.features.webhooks.limit}`);
637
- console.log(`Copy-trade wallets: ${me.features.copytrade_wallets.used}/${me.features.copytrade_wallets.limit}`);
638
-
639
- if (me.quota.daily.remaining < 100) {
640
- // self-throttle
641
- }
642
- ```
643
-
644
- Returns: `MeResponse`
645
-
646
- ---
647
-
648
- ### Tool Directory — `client.tools`
649
-
650
- #### `client.tools.search(params?)`
651
-
652
- Search 950+ Solana tools indexed on MadeOnSol.
653
-
654
- ```ts
655
- const { tools, count } = await client.tools.search({
656
- q: "trading bot", // full-text search
657
- category: "trading", // category slug filter
658
- limit: 20, // 1–50, default 20
659
- });
660
- ```
661
-
662
- Returns: `ToolsSearchResponse`
663
-
664
- ---
665
-
666
- ### WebSocket Streaming — `client.stream`
667
-
668
- #### `client.stream.getToken()`
669
-
670
- 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.
671
-
672
- ```ts
673
- const token = await client.stream.getToken();
674
- console.log(token.ws_url); // wss://madeonsol.com/ws/v1/stream
675
- console.log(token.dex_ws_url); // wss://madeonsol.com/ws/v1/dex-stream (Ultra only)
676
- ```
677
-
678
- Returns: `StreamToken` — `{ token, expires_at, ws_url, dex_ws_url?, usage }`
679
-
680
- ---
681
-
682
- ### DEX Firehose (Ultra) — `wss://madeonsol.com/ws/v1/dex-stream`
683
-
684
- 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.
685
-
686
- **Limits:** ULTRA = 2 connections, **10 named subscriptions per connection**, up to **500 trades replay** from in-memory ring buffer. Inbound rate limit: 5 messages/sec (excess emits one error per second).
687
-
688
- #### Quick start
689
-
690
- ```ts
691
- import { WebSocket } from "ws"; // or native WebSocket in browsers/Bun
692
-
693
- const { token, dex_ws_url } = await client.stream.getToken();
694
- const ws = new WebSocket(`${dex_ws_url}?token=${token}`); // token MUST be appended as query param
695
-
696
- ws.on("open", () => {
697
- // Multi-subscription: each sub has its own sub_id and filters
698
- ws.send(JSON.stringify({
699
- type: "subscribe",
700
- sub_id: "fresh-pumpfun",
701
- replay: 50, // backfill up to 500 from ring buffer
702
- filters: {
703
- dex: "pumpfun",
704
- token_age_max_seconds: 300, // first seen in last 5 min
705
- min_sol: 0.5,
706
- action: "buy",
707
- },
708
- }));
709
- });
710
-
711
- ws.on("message", (raw) => {
712
- const msg = JSON.parse(raw.toString());
713
- if (msg.channel === "dex:trades") {
714
- // { sub_id, data: { wallet, mint, action, sol_amount, token_amount, dex, ... }, replay, ts }
715
- console.log(msg.sub_id, msg.data.dex, msg.data.action, msg.data.sol_amount);
716
- }
717
- });
718
- ```
719
-
720
- #### Protocol — client → server
721
-
722
- | `type` | Required fields | Notes |
723
- |---|---|---|
724
- | `subscribe` | `sub_id`, `filters` | Optional `replay: 1–500` |
725
- | `update` | `sub_id`, `filters` | Replaces filters in place — no disconnect needed |
726
- | `unsubscribe` | `sub_id` | Or omit `sub_id` to clear all subs |
727
- | `list` | | Server replies with `{ type: "list", subs: [...] }` |
728
- | `ping` | | Heartbeat server replies `{ type: "pong" }` |
729
-
730
- #### Server client message shapes
731
-
732
- ```ts
733
- { type: "connected", tier: "ULTRA", capabilities: { max_subs: 10, max_replay: 500, dex_names: [...], deployer_tiers: [...] } } // on connect
734
- { type: "subscribed", sub_id: "fresh-pumpfun", filters: { ... } }
735
- { type: "replay_done", sub_id: "fresh-pumpfun", count: 50 } // after backfill
736
- { type: "updated", sub_id: "fresh-pumpfun", filters: { ... } }
737
- { type: "unsubscribed", sub_id: "fresh-pumpfun" }
738
- { type: "list", subs: [{ sub_id, filters }] } // reply to { type: "list" }
739
- { type: "heartbeat", ts: 1712160000000 } // every 30s
740
- { type: "error", sub_id?, message: "..." }
741
- { channel: "dex:trades", sub_id, data: { ... }, replay: false, ts: 1712160000000 }
742
- ```
743
-
744
- #### Filter dimensions
745
-
746
- At least **one targeting filter** is required (otherwise the firehose would dump every trade). Filters compose with AND semantics.
747
-
748
- | Filter | Type | Notes |
749
- |---|---|---|
750
- | `token_mint` / `token_mints` | string / string[] (≤50) | Targeting |
751
- | `wallet` / `wallets` | string / string[] (≤50) | Targeting |
752
- | `dex` | string \| string[] | `pumpfun`, `pumpamm`, `pumpswap`, `raydium`, `jupiter`, `orca`, `meteora`, `launchlab` |
753
- | `program` | string | Raw program ID |
754
- | `deployer_tier` | string \| string[] | `elite`, `good`, `moderate`, `rising`, `cold`, `unranked` (uses Deployer Hunter scoring) |
755
- | `token_age_max_seconds` | number | Only trades on mints first seen within window (uses persisted first-seen table) |
756
- | `market_cap_min_sol` / `market_cap_max_sol` | number | Bounded by current market cap (last trade price × cached supply, 1h TTL) |
757
- | `min_sol` / `max_sol` | number | Trade size bounds |
758
- | `action` | `"buy"` \| `"sell"` | Direction |
759
-
760
- **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.
761
-
762
- #### Multi-sub example
763
-
764
- ```ts
765
- ws.send(JSON.stringify({ type: "subscribe", sub_id: "snipers", filters: { token_age_max_seconds: 60 } }));
766
- ws.send(JSON.stringify({ type: "subscribe", sub_id: "whales", filters: { min_sol: 50 } }));
767
- ws.send(JSON.stringify({ type: "subscribe", sub_id: "kol-mints", filters: { token_mints: ["EPjF...", "So11..."] } }));
768
-
769
- // Tighten the snipers filter without disconnecting
770
- ws.send(JSON.stringify({ type: "update", sub_id: "snipers", filters: { token_age_max_seconds: 30, min_sol: 0.3 } }));
771
-
772
- // Drop whales when you're done
773
- ws.send(JSON.stringify({ type: "unsubscribe", sub_id: "whales" }));
774
- ```
775
-
776
- Each `dex:trades` message echoes the `sub_id` that matched, so you can route them locally without reapplying filter logic client-side.
777
-
778
- ---
779
-
780
- ### Webhooks — `client.webhooks`
781
-
782
- Manage push notification webhooks for real-time events (Pro: 3, Ultra: 10).
783
-
784
- ```ts
785
- // Create a webhook
786
- const webhook = await client.webhooks.create({
787
- url: "https://example.com/hook",
788
- events: ["kol:trade", "deployer:alert"],
789
- filters: { min_sol: 1 },
790
- });
791
-
792
- // List, update, delete
793
- const { webhooks } = await client.webhooks.list();
794
- await client.webhooks.update(webhook.id, { status: "paused" });
795
- await client.webhooks.delete(webhook.id);
796
- await client.webhooks.test(webhook.id);
797
- ```
798
-
799
- ---
800
-
801
- ## Error handling
802
-
803
- All methods throw `MadeOnSolError` on non-2xx responses.
804
-
805
- ```ts
806
- import { MadeOnSol, MadeOnSolError } from "madeonsol";
807
-
808
- try {
809
- const profile = await client.kol.wallet("invalid-wallet");
810
- } catch (err) {
811
- if (err instanceof MadeOnSolError) {
812
- console.error(err.message); // human-readable message
813
- console.error(err.status); // HTTP status code, e.g. 404
814
- console.error(err.body); // raw response body
815
- }
816
- }
817
- ```
818
-
819
- ---
820
-
821
- ## Exported types
822
-
823
- All types are exported from the main entry point:
824
-
825
- ```ts
826
- import type {
827
- // Errors
828
- MadeOnSolError,
829
-
830
- // KOL
831
- KolTrade,
832
- KolFeedParams,
833
- KolFeedResponse,
834
- KolLeaderboardParams,
835
- KolLeaderboardResponse,
836
- KolLeaderboardEntry,
837
- KolWalletParams,
838
- KolWalletProfile,
839
- KolCoordinationParams,
840
- KolCoordinationResponse,
841
- CoordinatedToken,
842
- KolTokenActivity,
843
- KolPnlByToken,
844
-
845
- // Deployer
846
- DeployerStats,
847
- DeployerLeaderboardParams,
848
- DeployerLeaderboardResponse,
849
- DeployerLeaderboardEntry,
850
- DeployerProfile,
851
- DeployerToken,
852
- DeployerTokensParams,
853
- DeployerTokensResponse,
854
- DeployerAlertsParams,
855
- DeployerAlertsResponse,
856
- DeployerAlert,
857
- DeployerAlertStatsParams,
858
- DeployerAlertStats,
859
- BestTokensParams,
860
- BestTokensResponse,
861
- BestToken,
862
- RecentBondsParams,
863
- RecentBondsResponse,
864
- RecentBond,
865
-
866
- // Tools
867
- ToolsSearchParams,
868
- ToolsSearchResponse,
869
- Tool,
870
-
871
- // KOL PnL & Trending
872
- KolPnlResponse,
873
- KolTrendingTokensResponse,
874
- TrendingToken,
875
-
876
- // Alpha Wallet Intelligence
877
- AlphaWalletEntry,
878
- AlphaLeaderboardResponse,
879
- AlphaWalletResponse,
880
- AlphaLinkedResponse,
881
- AlphaCapTableResponse,
882
- AlphaBuyerQualityResponse,
883
-
884
- // Wallet Tracker
885
- WalletEntry,
886
- WatchlistResponse,
887
- WalletTrackerEvent,
888
- WalletTrackerTradesResponse,
889
- WalletTrackerSummaryResponse,
890
-
891
- // Streaming
892
- StreamToken,
893
-
894
- // Webhooks
895
- Webhook,
896
- WebhookCreateParams,
897
- WebhookUpdateParams,
898
- WebhookListResponse,
899
-
900
- // Enums / unions
901
- KolAction,
902
- LeaderboardPeriod,
903
- CoordinationPeriod,
904
- DeployerTier,
905
- DeployerSortField,
906
- AlertPeriod,
907
- BestTokensPeriod,
908
- } from "madeonsol";
909
- ```
910
-
911
- ---
912
-
913
- ## Related
914
-
915
- - [MadeOnSol website](https://madeonsol.com) — Browse 950+ Solana tools
916
- - [API documentation](https://madeonsol.com/solana-api) — Interactive endpoint reference
917
- - [MadeOnSol on GitHub](https://github.com/LamboPoewert/madeonsol) — Main project repository
918
-
919
- ## Also Available
920
-
921
- | Platform | Package |
922
- |---|---|
923
- | Rust | [`madeonsol`](https://crates.io/crates/madeonsol) on crates.io |
924
- | Python (LangChain, CrewAI) | [`madeonsol-x402`](https://pypi.org/project/madeonsol-x402/) on PyPI |
925
- | MCP Server (Claude, Cursor) | [`mcp-server-madeonsol`](https://www.npmjs.com/package/mcp-server-madeonsol) |
926
- | ElizaOS | [`@madeonsol/plugin-madeonsol`](https://www.npmjs.com/package/@madeonsol/plugin-madeonsol) |
927
- | Solana Agent Kit | [`solana-agent-kit-plugin-madeonsol`](https://www.npmjs.com/package/solana-agent-kit-plugin-madeonsol) |
928
-
929
- ---
930
-
931
- ## License
932
-
933
- 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,000+ KOL wallets with <3s latency, score 6,700+ Pump.fun deployers by reputation, detect multi-KOL coordination signals, 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.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.
16
+ >
17
+ > **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.
18
+
19
+ > **Build Solana trading bots, analytics dashboards, KOL copy-trading tools, deployer sniper bots, and ecosystem browsers.**
20
+
21
+ ## Quick start (10 seconds)
22
+
23
+ ```bash
24
+ npm install madeonsol
25
+ ```
26
+
27
+ ```ts
28
+ import { MadeOnSol } from "madeonsol";
29
+ const client = new MadeOnSol({ apiKey: "msk_..." }); // free tier at madeonsol.com/pricing
30
+ const { trades } = await client.kol.feed({ limit: 5, action: "buy" });
31
+ ```
32
+
33
+ | Feature | Description |
34
+ |---|---|
35
+ | **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,000+ tracked KOL wallets. **180 days of trade history** retained. |
36
+ | **Alpha Wallet Intel** | Leaderboard of 47,000+ scored early-buyer wallets, full wallet profiles, linked-wallet clustering, token cap-table enrichment, and 0–100 buyer quality scores. |
37
+ | **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. |
38
+ | **Deployer Hunter** | Pump.fun deployer scoring, tier leaderboard, deploy alerts, and bonding intelligence |
39
+ | **DEX Trade Stream** | Real-time WebSocket stream of ALL Solana DEX trades — filter by token, wallet, program, or trade size (Ultra) |
40
+ | **Webhooks** | Push notifications for KOL trades, coordination signals, deployer alerts, and wallet tracker events (Pro/Ultra) |
41
+ | **Tool Directory** | Search 950+ Solana tools and dApps indexed on MadeOnSol |
42
+
43
+ **Links:** [Full docs](https://madeonsol.com/solana-api) · [Website](https://madeonsol.com) · [API docs](https://madeonsol.com/api-docs)
44
+
45
+ ## Authentication
46
+
47
+ Get a free API key at [madeonsol.com/pricing](https://madeonsol.com/pricing). Keys start with `msk_`.
48
+
49
+ ---
50
+
51
+ ## Install
52
+
53
+ ```bash
54
+ npm install madeonsol
55
+ # or
56
+ yarn add madeonsol
57
+ # or
58
+ pnpm add madeonsol
59
+ ```
60
+
61
+ Requires **Node.js ≥ 18** (uses native `fetch`). Works out of the box in Cloudflare Workers, Vercel Edge, and Bun.
62
+
63
+ ---
64
+
65
+ ## Quick start
66
+
67
+ ```ts
68
+ import { MadeOnSol } from "madeonsol";
69
+
70
+ const client = new MadeOnSol({ apiKey: "msk_your_api_key_here" });
71
+
72
+ // Latest KOL buy trades
73
+ const { trades } = await client.kol.feed({ limit: 10, action: "buy" });
74
+ console.log(trades[0].kol_name, "bought", trades[0].token_symbol);
75
+
76
+ // Elite deployer leaderboard
77
+ const { deployers } = await client.deployer.leaderboard({ tier: "elite" });
78
+
79
+ // Recent deploy alerts
80
+ const { alerts } = await client.deployer.alerts({ limit: 5 });
81
+
82
+ // Search Solana tools
83
+ const { tools } = await client.tools.search({ q: "trading", limit: 10 });
84
+ ```
85
+
86
+ ---
87
+
88
+ ## Use cases
89
+
90
+ - **Copy-trading bot** — stream KOL buys via `client.kol.feed()` and mirror trades
91
+ - **DEX trade sniping** — subscribe to the all-DEX stream filtered by token or wallet
92
+ - **Deployer sniper** — monitor `client.deployer.alerts()` for elite-tier launches
93
+ - **Coordination detector** — flag tokens with `client.kol.coordination({ min_kols: 3 })`
94
+ - **Scout signal** — track first-KOL-touch events filtered to S/A-tier scouts via `client.kol.firstTouches({ preset: "scout" })`
95
+ - **Analytics dashboard** — combine leaderboard, PnL, and tool data
96
+ - **Telegram/Discord bot** — pipe alerts via webhooks into chat
97
+ - **Portfolio tracker** — use `client.kol.wallet()` to follow specific KOL positions
98
+
99
+ ---
100
+
101
+ ## API Reference
102
+
103
+ ### KOL Tracker — `client.kol`
104
+
105
+ #### `client.kol.feed(params?)`
106
+
107
+ Live feed of trades made by tracked KOL wallets.
108
+
109
+ ```ts
110
+ const { trades, count } = await client.kol.feed({
111
+ limit: 50, // 1–100, default 50
112
+ action: "buy", // "buy" | "sell"
113
+ kol: "7xKX...", // filter by specific wallet
114
+ });
115
+ ```
116
+
117
+ Returns: `KolFeedResponse` — `{ trades: KolTrade[], count: number }`
118
+
119
+ 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.
120
+
121
+ ---
122
+
123
+ #### `client.kol.leaderboard(params?)`
124
+
125
+ KOL PnL leaderboard ranked by realized profit.
126
+
127
+ ```ts
128
+ const { leaderboard, period } = await client.kol.leaderboard({
129
+ period: "7d", // "today" | "7d" | "30d" | "90d" | "180d", default "7d"
130
+ });
131
+ ```
132
+
133
+ > **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.
134
+
135
+ Returns: `KolLeaderboardResponse`
136
+
137
+ ---
138
+
139
+ #### `client.kol.wallet(wallet, params?)`
140
+
141
+ Full profile for a single KOL wallet, including trade history and optional per-token PnL breakdown.
142
+
143
+ ```ts
144
+ const profile = await client.kol.wallet("7xKX...", {
145
+ include: "pnl_by_token",
146
+ });
147
+ ```
148
+
149
+ Returns: `KolWalletProfile`
150
+
151
+ ---
152
+
153
+ #### `client.kol.coordination(params?)`
154
+
155
+ 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.
156
+
157
+ ```ts
158
+ const { coordination, score_version, window_minutes } = await client.kol.coordination({
159
+ period: "24h", // "1h" | "6h" | "24h" | "7d", default "24h"
160
+ min_kols: 3, // 2–50, default 3
161
+ limit: 20, // 1–50, default 20
162
+ window_minutes: 15, // v1.1 — peak-density window in minutes (1–60)
163
+ min_score: 60, // v1.1 — filter by composite score (0–100)
164
+ include_majors: false, // v1.1 include WIF/BONK/POPCAT
165
+ });
166
+
167
+ for (const c of coordination) {
168
+ console.log(c.token_symbol, "score", c.coordination_score, "peak", c.peak_kols, "exited", c.exited_count);
169
+ // c.kols[]: { name, wallet, buy_sol, sell_sol, exited }
170
+ }
171
+ ```
172
+
173
+ Returns: `KolCoordinationResponse` — `{ coordination: CoordinatedToken[], score_version, window_minutes }`
174
+
175
+ ---
176
+
177
+ #### `client.coordinationAlerts.*` (v1.1)
178
+
179
+ 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.**
180
+
181
+ ```ts
182
+ // Create a rule: 5 KOLs, 10-min window, score ≥70, webhook delivery
183
+ const { rule, webhook_secret } = await client.coordinationAlerts.create({
184
+ name: "strong-clusters",
185
+ min_kols: 5,
186
+ window_minutes: 10,
187
+ min_score: 70,
188
+ include_majors: false,
189
+ cooldown_min: 30, // don't re-fire same token within 30 min
190
+ score_jump_break: 15, // UNLESS score jumps by 15+ (catches conviction surges)
191
+ delivery_mode: "webhook", // "websocket" | "webhook" | "both"
192
+ webhook_url: "https://example.com/coord-hook",
193
+ });
194
+ // SAVE webhook_secret — used for HMAC-SHA256 signature verification.
195
+
196
+ await client.coordinationAlerts.list();
197
+ await client.coordinationAlerts.get(rule.id);
198
+ await client.coordinationAlerts.update(rule.id, { min_score: 80, is_active: false });
199
+ await client.coordinationAlerts.delete(rule.id);
200
+ ```
201
+
202
+ Webhook signatures: header `X-MadeOnSol-Signature` = `sha256(timestamp + "." + body)` with `webhook_secret` as the HMAC key. Reject deliveries older than ~5 min.
203
+
204
+ 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).
205
+
206
+ ---
207
+
208
+ #### `client.kol.firstTouches(params?)` *(new in 2.2)*
209
+
210
+ 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.
211
+
212
+ **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).
213
+
214
+ ```ts
215
+ // S-tier scouts on tokens younger than 1h
216
+ const { events } = await client.kol.firstTouches({
217
+ preset: "scout",
218
+ min_scout_tier: "S",
219
+ limit: 20,
220
+ });
221
+
222
+ for (const e of events) {
223
+ console.log(e.first_kol.name, "scouted", e.token_symbol, `(scout_score=${e.first_kol.scout_score}%)`);
224
+ }
225
+ ```
226
+
227
+ 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"`).
228
+
229
+ > **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({...})`.
230
+
231
+ Returns: `FirstTouchesResponse`
232
+
233
+ ---
234
+
235
+ #### `client.firstTouchSubscriptions.*` *(Ultra)*
236
+
237
+ Create push-delivery rules for first-touch events. Up to 10 active subscriptions per Ultra user.
238
+
239
+ ```ts
240
+ const { subscription, webhook_secret } = await client.firstTouchSubscriptions.create({
241
+ name: "S-tier scouts on pump tokens",
242
+ filters: { min_scout_tier: "S", mint_suffix: "pump" },
243
+ delivery_mode: "webhook",
244
+ webhook_url: "https://my.bot/hooks/scout",
245
+ });
246
+ // store webhook_secret shown once
247
+
248
+ await client.firstTouchSubscriptions.list();
249
+ await client.firstTouchSubscriptions.update(subscription.id, { is_active: false });
250
+ await client.firstTouchSubscriptions.delete(subscription.id);
251
+ ```
252
+
253
+ Same HMAC scheme as coordination alerts. WebSocket channel: `kol:first_touches`.
254
+
255
+ ---
256
+
257
+ #### `client.kol.token(mint)`
258
+
259
+ KOL buy/sell activity for a specific token mint.
260
+
261
+ ```ts
262
+ const activity = await client.kol.token("EPjFW...");
263
+ ```
264
+
265
+ Returns: `KolTokenActivity`
266
+
267
+ ---
268
+
269
+ #### `client.kol.pnl(wallet, params?)`
270
+
271
+ Deep per-wallet PnL breakdown with equity curve, risk metrics, and position history.
272
+
273
+ ```ts
274
+ const pnl = await client.kol.pnl("7xKX...", {
275
+ period: "30d", // "7d" | "30d" | "90d" | "180d", default "30d"
276
+ });
277
+ // All tiers: summary + equity curve + closed positions
278
+ // ULTRA: + open positions (tokens bought but not yet sold)
279
+ ```
280
+
281
+ Returns: `KolPnlResponse`
282
+
283
+ ---
284
+
285
+ #### `client.kol.trendingTokens(params?)`
286
+
287
+ Tokens ranked by KOL buy volume across multiple time windows.
288
+
289
+ ```ts
290
+ const { tokens } = await client.kol.trendingTokens({
291
+ period: "1h", // "5m" | "15m" | "30m" | "1h" | "4h" | "8h" | "12h", default "1h"
292
+ min_kols: 2, // minimum distinct KOL buyers
293
+ limit: 20, // 1–50, default 20
294
+ });
295
+ // Available on all tiers; ULTRA unlocks full KOL wallet addresses per token
296
+ ```
297
+
298
+ Returns: `KolTrendingTokensResponse`
299
+
300
+ ---
301
+
302
+ ### Alpha Wallet Intelligence — `client.alpha`
303
+
304
+ #### `client.alpha.leaderboard(params?)`
305
+
306
+ Leaderboard of 47,000+ scored early-buyer wallets ranked by win rate, PnL, or ROI.
307
+
308
+ ```ts
309
+ const { wallets } = await client.alpha.leaderboard({
310
+ period: "30d", // "7d" | "30d" | "90d", default "30d"
311
+ sort: "win_rate", // "win_rate" | "pnl" | "roi"
312
+ min_tokens: 5,
313
+ exclude_bots: true,
314
+ });
315
+ // Up to 100 results on Free/Pro; ULTRA unlocks 500 + bot signals
316
+ ```
317
+
318
+ Returns: `AlphaLeaderboardResponse`
319
+
320
+ ---
321
+
322
+ #### `client.alpha.wallet(wallet)`
323
+
324
+ Full profile for an alpha wallet including per-token history and bot signals. ULTRA only.
325
+
326
+ ```ts
327
+ const profile = await client.alpha.wallet("7xKX...");
328
+ ```
329
+
330
+ Returns: `AlphaWalletResponse`
331
+
332
+ ---
333
+
334
+ #### `client.alpha.linked(wallet)`
335
+
336
+ Linked-wallet clustering wallets that co-bought with this address within 2 seconds. ULTRA only.
337
+
338
+ ```ts
339
+ const { linked } = await client.alpha.linked("7xKX...");
340
+ ```
341
+
342
+ Returns: `AlphaLinkedResponse`
343
+
344
+ ---
345
+
346
+ #### `client.alpha.capTable(mint)`
347
+
348
+ First buyers for a token enriched with historical win rates, PnL, and KOL identity. PRO/ULTRA.
349
+
350
+ ```ts
351
+ const { buyers } = await client.alpha.capTable("EPjFW...");
352
+ ```
353
+
354
+ Returns: `AlphaCapTableResponse`
355
+
356
+ ---
357
+
358
+ #### `client.alpha.buyerQuality(mint)`
359
+
360
+ 0–100 cohort quality score based on the profile of a token's first buyers. All tiers. 5-minute cache.
361
+
362
+ ```ts
363
+ const { score } = await client.alpha.buyerQuality("EPjFW...");
364
+ ```
365
+
366
+ Returns: `AlphaBuyerQualityResponse`
367
+
368
+ ---
369
+
370
+ ### Wallet Tracker — `client.walletTracker`
371
+
372
+ #### `client.walletTracker.watchlist()`
373
+
374
+ List your tracked wallets and remaining capacity.
375
+
376
+ ```ts
377
+ const { wallets, capacity } = await client.walletTracker.watchlist();
378
+ // capacity: { used, limit } — Free: 10, Pro: 50, Ultra: 100
379
+ ```
380
+
381
+ Returns: `WatchlistResponse`
382
+
383
+ ---
384
+
385
+ #### `client.walletTracker.addToWatchlist(wallet, params?)`
386
+
387
+ Add a wallet to your watchlist. Tracking begins immediately.
388
+
389
+ ```ts
390
+ await client.walletTracker.addToWatchlist("7xKX...", { label: "whale" });
391
+ ```
392
+
393
+ ---
394
+
395
+ #### `client.walletTracker.removeFromWatchlist(wallet)`
396
+
397
+ Remove a wallet from your watchlist.
398
+
399
+ ```ts
400
+ await client.walletTracker.removeFromWatchlist("7xKX...");
401
+ ```
402
+
403
+ ---
404
+
405
+ #### `client.walletTracker.updateLabel(wallet, label)`
406
+
407
+ Update the label for a tracked wallet.
408
+
409
+ ```ts
410
+ await client.walletTracker.updateLabel("7xKX...", "smart money");
411
+ ```
412
+
413
+ ---
414
+
415
+ #### `client.walletTracker.trades(params?)`
416
+
417
+ Historical swap and transfer events for your watched wallets. 120-day retention.
418
+
419
+ ```ts
420
+ const { events } = await client.walletTracker.trades({
421
+ wallet: "7xKX...", // filter by specific wallet
422
+ action: "buy", // "buy" | "sell"
423
+ event_type: "swap", // "swap" | "transfer"
424
+ limit: 50,
425
+ before: "2026-04-01T00:00:00Z", // ISO 8601 cursor
426
+ });
427
+ ```
428
+
429
+ Returns: `WalletTrackerTradesResponse`
430
+
431
+ ---
432
+
433
+ #### `client.walletTracker.summary(params?)`
434
+
435
+ Per-wallet stats across your watchlist: swap counts, SOL bought/sold, last event time.
436
+
437
+ ```ts
438
+ const { wallets } = await client.walletTracker.summary({
439
+ period: "7d", // "24h" | "7d" | "30d", default "7d"
440
+ wallet: "7xKX...", // optional: single wallet
441
+ });
442
+ ```
443
+
444
+ Returns: `WalletTrackerSummaryResponse`
445
+
446
+ ---
447
+
448
+ ### Deployer Hunter — `client.deployer`
449
+
450
+ #### `client.deployer.stats()`
451
+
452
+ Global statistics across all tracked deployer wallets.
453
+
454
+ ```ts
455
+ const stats = await client.deployer.stats();
456
+ console.log(stats.overall_bonding_rate); // e.g. 0.043
457
+ ```
458
+
459
+ Returns: `DeployerStats`
460
+
461
+ ---
462
+
463
+ #### `client.deployer.leaderboard(params?)`
464
+
465
+ Deployers ranked by bonding rate or recent performance.
466
+
467
+ ```ts
468
+ const { deployers } = await client.deployer.leaderboard({
469
+ tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
470
+ sort: "bonding_rate", // "bonding_rate" | "recent_bond_rate" | "total_bonded" | "last_deploy_at"
471
+ limit: 20, // 1–50, default 20
472
+ offset: 0,
473
+ });
474
+ ```
475
+
476
+ Returns: `DeployerLeaderboardResponse`
477
+
478
+ ---
479
+
480
+ #### `client.deployer.profile(wallet)`
481
+
482
+ Full profile for a single deployer wallet.
483
+
484
+ ```ts
485
+ const deployer = await client.deployer.profile("3xAB...");
486
+ console.log(deployer.tier, deployer.bonding_rate);
487
+ ```
488
+
489
+ Returns: `DeployerProfile`
490
+
491
+ ---
492
+
493
+ #### `client.deployer.tokens(wallet, params?)`
494
+
495
+ All tokens deployed by a specific wallet.
496
+
497
+ ```ts
498
+ const { tokens } = await client.deployer.tokens("3xAB...", {
499
+ limit: 20,
500
+ offset: 0,
501
+ });
502
+ ```
503
+
504
+ Returns: `DeployerTokensResponse`
505
+
506
+ ---
507
+
508
+ #### `client.deployer.alerts(params?)`
509
+
510
+ Real-time deploy alerts fired when a tracked deployer launches a new token.
511
+
512
+ ```ts
513
+ const { alerts } = await client.deployer.alerts({
514
+ since: "2025-01-01T00:00:00Z", // ISO 8601
515
+ limit: 20,
516
+ tier: "elite", // "elite" | "good" | "moderate" | "rising" | "cold"
517
+ offset: 0,
518
+ });
519
+ ```
520
+
521
+ Returns: `DeployerAlertsResponse`
522
+
523
+ ---
524
+
525
+ #### `client.deployer.alertStats(params?)`
526
+
527
+ Aggregated alert statistics by tier.
528
+
529
+ ```ts
530
+ const stats = await client.deployer.alertStats({ period: "7d" });
531
+ // "7d" | "30d" | "all", default "all"
532
+ ```
533
+
534
+ Returns: `DeployerAlertStats`
535
+
536
+ ---
537
+
538
+ #### `client.deployer.bestTokens(params?)`
539
+
540
+ Top-performing tokens from tracked deployers by peak market cap.
541
+
542
+ ```ts
543
+ const { tokens } = await client.deployer.bestTokens({
544
+ period: "7d", // "7d" | "30d" | "all", default "7d"
545
+ limit: 5, // 1–20, default 5
546
+ });
547
+ ```
548
+
549
+ Returns: `BestTokensResponse`
550
+
551
+ ---
552
+
553
+ #### `client.deployer.recentBonds(params?)`
554
+
555
+ Most recently bonded tokens from tracked deployers.
556
+
557
+ ```ts
558
+ const { bonds } = await client.deployer.recentBonds({ limit: 20 });
559
+ ```
560
+
561
+ Returns: `RecentBondsResponse`
562
+
563
+ ---
564
+
565
+ ### Token Intelligence — `client.token`
566
+
567
+ Per-mint snapshots (price, MC, volume, deployer rep, KOL activity, blacklist flags, **v1.7 velocity windows + MEV-share**) and a filtered directory.
568
+
569
+ #### `client.token.get(mint)`
570
+
571
+ Comprehensive per-mint snapshot in one call. **ULTRA** also returns individual KOL wallet addresses in `top_buyers[]`.
572
+
573
+ ```ts
574
+ const { token } = await client.token.get("So11111111111111111111111111111111111111112");
575
+ console.log(token.price_usd, token.market_cap);
576
+ console.log(token.mc_change_pct?.["1h"]); // v1.7
577
+ console.log(token.mev_volume_pct?.["1h"]); // v1.7
578
+ ```
579
+
580
+ Invalid mints return a 400 with `code: "invalid_mint"`, `reason`, `received_length`, `example`, and `docs` URL — no trial and error.
581
+
582
+ 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)
583
+
584
+ #### `client.token.batch(mints)`
585
+
586
+ Batch lookup up to 50 mints in one round-trip. ~10–20× cheaper than N sequential calls.
587
+
588
+ ```ts
589
+ const { tokens } = await client.token.batch(["mint1", "mint2", "mint3"]);
590
+ ```
591
+
592
+ Returns: `TokenBatchResponse`
593
+
594
+ #### `client.token.list(params?)` *(new in 2.6 — PRO+)*
595
+
596
+ 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.
597
+
598
+ **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`.
599
+
600
+ **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`.
601
+
602
+ ```ts
603
+ // Momentum scanner: liquid mints up >20% in 1h, low bot share
604
+ const { tokens, pagination } = await client.token.list({
605
+ min_liq: 10000,
606
+ min_volume_1h_usd: 5000,
607
+ max_mev_share_pct: 60,
608
+ mc_change_1h_min_pct: 20,
609
+ sort: "mc_desc",
610
+ limit: 50,
611
+ });
612
+
613
+ // Cleanest filter for a sane "top by MC" feed
614
+ const { tokens } = await client.token.list({
615
+ min_liq: 25000,
616
+ active_h: 1,
617
+ authority_revoked: true,
618
+ sort: "mc_desc",
619
+ });
620
+ ```
621
+
622
+ Returns: `TokenListResponse` (with `tokens[]`, `pagination`, `filters` echo)
623
+
624
+ #### `client.token.batchBuyerQuality(mints)`
625
+
626
+ Batch buyer-quality scoring for up to 50 mints. Shares the same 5-minute LRU cache as `client.alpha.buyerQuality(mint)`.
627
+
628
+ Returns: `AlphaBuyerQualityBatchResponse`
629
+
630
+ ---
631
+
632
+ ### Account — `client.me()` *(new in 2.6)*
633
+
634
+ 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).
635
+
636
+ ```ts
637
+ const me = await client.me();
638
+ console.log(`${me.tier}: ${me.quota.daily.remaining}/${me.quota.daily.limit} req left today`);
639
+ console.log(`Webhooks: ${me.features.webhooks.used}/${me.features.webhooks.limit}`);
640
+ console.log(`Copy-trade wallets: ${me.features.copytrade_wallets.used}/${me.features.copytrade_wallets.limit}`);
641
+
642
+ if (me.quota.daily.remaining < 100) {
643
+ // self-throttle
644
+ }
645
+ ```
646
+
647
+ Returns: `MeResponse`
648
+
649
+ ---
650
+
651
+ ### Tool Directory — `client.tools`
652
+
653
+ #### `client.tools.search(params?)`
654
+
655
+ Search 950+ Solana tools indexed on MadeOnSol.
656
+
657
+ ```ts
658
+ const { tools, count } = await client.tools.search({
659
+ q: "trading bot", // full-text search
660
+ category: "trading", // category slug filter
661
+ limit: 20, // 1–50, default 20
662
+ });
663
+ ```
664
+
665
+ Returns: `ToolsSearchResponse`
666
+
667
+ ---
668
+
669
+ ### WebSocket Streaming — `client.stream`
670
+
671
+ #### `client.stream.getToken()`
672
+
673
+ 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.
674
+
675
+ ```ts
676
+ const token = await client.stream.getToken();
677
+ console.log(token.ws_url); // wss://madeonsol.com/ws/v1/stream
678
+ console.log(token.dex_ws_url); // wss://madeonsol.com/ws/v1/dex-stream (Ultra only)
679
+ ```
680
+
681
+ Returns: `StreamToken` — `{ token, expires_at, ws_url, dex_ws_url?, usage }`
682
+
683
+ ---
684
+
685
+ ### DEX Firehose (Ultra) — `wss://madeonsol.com/ws/v1/dex-stream`
686
+
687
+ 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.
688
+
689
+ **Limits:** ULTRA = 2 connections, **10 named subscriptions per connection**, up to **500 trades replay** from in-memory ring buffer. Inbound rate limit: 5 messages/sec (excess emits one error per second).
690
+
691
+ #### Quick start
692
+
693
+ ```ts
694
+ import { WebSocket } from "ws"; // or native WebSocket in browsers/Bun
695
+
696
+ const { token, dex_ws_url } = await client.stream.getToken();
697
+ const ws = new WebSocket(`${dex_ws_url}?token=${token}`); // token MUST be appended as query param
698
+
699
+ ws.on("open", () => {
700
+ // Multi-subscription: each sub has its own sub_id and filters
701
+ ws.send(JSON.stringify({
702
+ type: "subscribe",
703
+ sub_id: "fresh-pumpfun",
704
+ replay: 50, // backfill up to 500 from ring buffer
705
+ filters: {
706
+ dex: "pumpfun",
707
+ token_age_max_seconds: 300, // first seen in last 5 min
708
+ min_sol: 0.5,
709
+ action: "buy",
710
+ },
711
+ }));
712
+ });
713
+
714
+ ws.on("message", (raw) => {
715
+ const msg = JSON.parse(raw.toString());
716
+ if (msg.channel === "dex:trades") {
717
+ // { sub_id, data: { wallet, mint, action, sol_amount, token_amount, dex, ... }, replay, ts }
718
+ console.log(msg.sub_id, msg.data.dex, msg.data.action, msg.data.sol_amount);
719
+ }
720
+ });
721
+ ```
722
+
723
+ #### Protocol — client → server
724
+
725
+ | `type` | Required fields | Notes |
726
+ |---|---|---|
727
+ | `subscribe` | `sub_id`, `filters` | Optional `replay: 1–500` |
728
+ | `update` | `sub_id`, `filters` | Replaces filters in place no disconnect needed |
729
+ | `unsubscribe` | `sub_id` | Or omit `sub_id` to clear all subs |
730
+ | `list` | — | Server replies with `{ type: "list", subs: [...] }` |
731
+ | `ping` | — | Heartbeat — server replies `{ type: "pong" }` |
732
+
733
+ #### Server client message shapes
734
+
735
+ ```ts
736
+ { type: "connected", tier: "ULTRA", capabilities: { max_subs: 10, max_replay: 500, dex_names: [...], deployer_tiers: [...] } } // on connect
737
+ { type: "subscribed", sub_id: "fresh-pumpfun", filters: { ... } }
738
+ { type: "replay_done", sub_id: "fresh-pumpfun", count: 50 } // after backfill
739
+ { type: "updated", sub_id: "fresh-pumpfun", filters: { ... } }
740
+ { type: "unsubscribed", sub_id: "fresh-pumpfun" }
741
+ { type: "list", subs: [{ sub_id, filters }] } // reply to { type: "list" }
742
+ { type: "heartbeat", ts: 1712160000000 } // every 30s
743
+ { type: "error", sub_id?, message: "..." }
744
+ { channel: "dex:trades", sub_id, data: { ... }, replay: false, ts: 1712160000000 }
745
+ ```
746
+
747
+ #### Filter dimensions
748
+
749
+ At least **one targeting filter** is required (otherwise the firehose would dump every trade). Filters compose with AND semantics.
750
+
751
+ | Filter | Type | Notes |
752
+ |---|---|---|
753
+ | `token_mint` / `token_mints` | string / string[] (≤50) | Targeting |
754
+ | `wallet` / `wallets` | string / string[] (≤50) | Targeting |
755
+ | `dex` | string \| string[] | `pumpfun`, `pumpamm`, `pumpswap`, `raydium`, `jupiter`, `orca`, `meteora`, `launchlab` |
756
+ | `program` | string | Raw program ID |
757
+ | `deployer_tier` | string \| string[] | `elite`, `good`, `moderate`, `rising`, `cold`, `unranked` (uses Deployer Hunter scoring) |
758
+ | `token_age_max_seconds` | number | Only trades on mints first seen within window (uses persisted first-seen table) |
759
+ | `market_cap_min_sol` / `market_cap_max_sol` | number | Bounded by current market cap (last trade price × cached supply, 1h TTL) |
760
+ | `min_sol` / `max_sol` | number | Trade size bounds |
761
+ | `action` | `"buy"` \| `"sell"` | Direction |
762
+
763
+ **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.
764
+
765
+ #### Multi-sub example
766
+
767
+ ```ts
768
+ ws.send(JSON.stringify({ type: "subscribe", sub_id: "snipers", filters: { token_age_max_seconds: 60 } }));
769
+ ws.send(JSON.stringify({ type: "subscribe", sub_id: "whales", filters: { min_sol: 50 } }));
770
+ ws.send(JSON.stringify({ type: "subscribe", sub_id: "kol-mints", filters: { token_mints: ["EPjF...", "So11..."] } }));
771
+
772
+ // Tighten the snipers filter without disconnecting
773
+ ws.send(JSON.stringify({ type: "update", sub_id: "snipers", filters: { token_age_max_seconds: 30, min_sol: 0.3 } }));
774
+
775
+ // Drop whales when you're done
776
+ ws.send(JSON.stringify({ type: "unsubscribe", sub_id: "whales" }));
777
+ ```
778
+
779
+ Each `dex:trades` message echoes the `sub_id` that matched, so you can route them locally without reapplying filter logic client-side.
780
+
781
+ ---
782
+
783
+ ### Webhooks — `client.webhooks`
784
+
785
+ Manage push notification webhooks for real-time events (Pro: 3, Ultra: 10).
786
+
787
+ ```ts
788
+ // Create a webhook
789
+ const webhook = await client.webhooks.create({
790
+ url: "https://example.com/hook",
791
+ events: ["kol:trade", "deployer:alert"],
792
+ filters: { min_sol: 1 },
793
+ });
794
+
795
+ // List, update, delete
796
+ const { webhooks } = await client.webhooks.list();
797
+ await client.webhooks.update(webhook.id, { status: "paused" });
798
+ await client.webhooks.delete(webhook.id);
799
+ await client.webhooks.test(webhook.id);
800
+ ```
801
+
802
+ ---
803
+
804
+ ## Error handling
805
+
806
+ All methods throw `MadeOnSolError` on non-2xx responses.
807
+
808
+ ```ts
809
+ import { MadeOnSol, MadeOnSolError } from "madeonsol";
810
+
811
+ try {
812
+ const profile = await client.kol.wallet("invalid-wallet");
813
+ } catch (err) {
814
+ if (err instanceof MadeOnSolError) {
815
+ console.error(err.message); // human-readable message
816
+ console.error(err.status); // HTTP status code, e.g. 404
817
+ console.error(err.body); // raw response body
818
+ }
819
+ }
820
+ ```
821
+
822
+ ---
823
+
824
+ ## Exported types
825
+
826
+ All types are exported from the main entry point:
827
+
828
+ ```ts
829
+ import type {
830
+ // Errors
831
+ MadeOnSolError,
832
+
833
+ // KOL
834
+ KolTrade,
835
+ KolFeedParams,
836
+ KolFeedResponse,
837
+ KolLeaderboardParams,
838
+ KolLeaderboardResponse,
839
+ KolLeaderboardEntry,
840
+ KolWalletParams,
841
+ KolWalletProfile,
842
+ KolCoordinationParams,
843
+ KolCoordinationResponse,
844
+ CoordinatedToken,
845
+ KolTokenActivity,
846
+ KolPnlByToken,
847
+
848
+ // Deployer
849
+ DeployerStats,
850
+ DeployerLeaderboardParams,
851
+ DeployerLeaderboardResponse,
852
+ DeployerLeaderboardEntry,
853
+ DeployerProfile,
854
+ DeployerToken,
855
+ DeployerTokensParams,
856
+ DeployerTokensResponse,
857
+ DeployerAlertsParams,
858
+ DeployerAlertsResponse,
859
+ DeployerAlert,
860
+ DeployerAlertStatsParams,
861
+ DeployerAlertStats,
862
+ BestTokensParams,
863
+ BestTokensResponse,
864
+ BestToken,
865
+ RecentBondsParams,
866
+ RecentBondsResponse,
867
+ RecentBond,
868
+
869
+ // Tools
870
+ ToolsSearchParams,
871
+ ToolsSearchResponse,
872
+ Tool,
873
+
874
+ // KOL PnL & Trending
875
+ KolPnlResponse,
876
+ KolTrendingTokensResponse,
877
+ TrendingToken,
878
+
879
+ // Alpha Wallet Intelligence
880
+ AlphaWalletEntry,
881
+ AlphaLeaderboardResponse,
882
+ AlphaWalletResponse,
883
+ AlphaLinkedResponse,
884
+ AlphaCapTableResponse,
885
+ AlphaBuyerQualityResponse,
886
+
887
+ // Wallet Tracker
888
+ WalletEntry,
889
+ WatchlistResponse,
890
+ WalletTrackerEvent,
891
+ WalletTrackerTradesResponse,
892
+ WalletTrackerSummaryResponse,
893
+
894
+ // Streaming
895
+ StreamToken,
896
+
897
+ // Webhooks
898
+ Webhook,
899
+ WebhookCreateParams,
900
+ WebhookUpdateParams,
901
+ WebhookListResponse,
902
+
903
+ // Enums / unions
904
+ KolAction,
905
+ LeaderboardPeriod,
906
+ CoordinationPeriod,
907
+ DeployerTier,
908
+ DeployerSortField,
909
+ AlertPeriod,
910
+ BestTokensPeriod,
911
+ } from "madeonsol";
912
+ ```
913
+
914
+ ---
915
+
916
+ ## Related
917
+
918
+ - [MadeOnSol website](https://madeonsol.com) — Browse 950+ Solana tools
919
+ - [API documentation](https://madeonsol.com/api-docs) — Interactive endpoint reference
920
+ - [MadeOnSol on GitHub](https://github.com/LamboPoewert/madeonsol) — Main project repository
921
+
922
+ ## Also Available
923
+
924
+ | Platform | Package |
925
+ |---|---|
926
+ | Rust | [`madeonsol`](https://crates.io/crates/madeonsol) on crates.io |
927
+ | Python (LangChain, CrewAI) | [`madeonsol-x402`](https://pypi.org/project/madeonsol-x402/) on PyPI |
928
+ | MCP Server (Claude, Cursor) | [`mcp-server-madeonsol`](https://www.npmjs.com/package/mcp-server-madeonsol) |
929
+ | ElizaOS | [`@madeonsol/plugin-madeonsol`](https://www.npmjs.com/package/@madeonsol/plugin-madeonsol) |
930
+ | Solana Agent Kit | [`solana-agent-kit-plugin-madeonsol`](https://www.npmjs.com/package/solana-agent-kit-plugin-madeonsol) |
931
+
932
+ ---
933
+
934
+ ## License
935
+
936
+ MIT © [MadeOnSol](https://madeonsol.com)