PageSourceSearch

https://defade.org/api-docs

html defade.org collected 2026-10-08 12:41:25 UTC 162,923 bytes, 2,073 lines download raw bytes

1<!DOCTYPE html>
2<html lang="en">
3<head>
4<!-- Google tag (gtag.js) -->
vendor: 64 bytes, lines 4-5
4
5<script async src="https://www.googletagmanager.com/gtag/js?id=
5G-ENZMBCKGDK
vendor: 12 bytes, line 5
5"></script>
6<script>
7  
vendor: 133 bytes, lines 7-10
7window.dataLayer = window.dataLayer || [];
8  function gtag(){dataLayer.push(arguments);}
9  gtag('js', new Date());
10  gtag('config', '
10G-ENZMBCKGDK
vendor: 4 bytes, line 10
10');
11</script>
11
12
13<meta charset="UTF-8">
14<meta name="viewport" content="width=device-width, initial-scale=1.0">
15<title>DeFade API Documentation — Multi-Chain Token Risk Analysis</title>
16<meta name="description" content="DeFade API — memecoin risk analysis on Solana, Ethereum, Base &amp; Robinhood. Rug detection, insider mapping, smart money. 25 endpoints, free tier.">
17<meta name="robots" content="index, follow">
18<link rel="canonical" href="https://defade.org/api-docs">
19<link rel="icon" href="https://defade.org/favicon.ico">
20<link rel="apple-touch-icon" sizes="192x192" href="https://defade.org/icon-192.png">
21
22<!-- Open Graph -->
23<meta property="og:type" content="website">
24<meta property="og:url" content="https://defade.org/api-docs">
25<meta property="og:title" content="DeFade API — Multi-Chain Token Risk Analysis">
26<meta property="og:description" content="Rug pull detection, insider network mapping, smart money tracking & 25 endpoints via a fast REST API. Every plan covers every chain. Plans from $29/mo.">
27<meta property="og:image" content="https://defade.org/og-image.jpg?v=5">
28<meta property="og:image:width" content="1536">
29<meta property="og:image:height" content="804">
30<meta property="og:image:type" content="image/jpeg">
31<meta property="og:site_name" content="DeFade">
32
33<!-- Twitter Card -->
34<meta name="twitter:card" content="summary_large_image">
35<meta name="twitter:site" content="@DeFade_">
36<meta name="twitter:title" content="DeFade API — Multi-Chain Token Risk Analysis">
37<meta name="twitter:description" content="Rug pull detection, insider network mapping, smart money tracking & 25 endpoints via a fast REST API. Every plan covers every chain. Plans from $29/mo.">
38<meta name="twitter:image" content="https://defade.org/og-image.jpg?v=5">
39
40<!-- Structured Data -->
41<script type="application/ld+json">
42{
43  "@context": "https://schema.org",
44  "@type": "WebAPI",
45  "name": "DeFade API",
46  "description": "Multi-chain memecoin risk analysis API for Solana, Ethereum, Base and Robinhood Chain — rug pull detection, insider network mapping, smart money tracking, and 25 endpoints.",
47  "url": "https://defade.org/api-docs",
48  "documentationUrl": "https://defade.org/api-docs",
49  "provider": {
50    "@type": "Organization",
51    "name": "DeFade Ltd",
52    "url": "https://defade.org",
53    "logo": "https://defade.org/icon-192.png",
54    "sameAs": ["https://x.com/DeFade_", "https://t.me/DeFadeChat"]
55  },
56  "offers": [
57    { "@type": "Offer", "name": "Starter", "price": "99", "priceCurrency": "USD" },
58    { "@type": "Offer", "name": "Pro", "price": "399", "priceCurrency": "USD" },
59    { "@type": "Offer", "name": "Enterprise", "price": "1999", "priceCurrency": "USD" }
60  ]
61}
62</script>
62
63<link rel="preconnect" href="https://fonts.googleapis.com">
64<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
65<link href="https://fonts.googleapis.com/css2?family=DM+Sans:wght@700&family=JetBrains+Mono:ital,wght@0,400;0,500;0,600;1,400&family=Outfit:wght@300;400;500;600;700&display=swap" rel="stylesheet">
66<style>
67*,*::before,*::after{box-sizing:border-box;margin:0;padding:0}
68:root{
69  --bg-primary:#030308;
70  --bg-secondary:#0d0d16;
71  --bg-tertiary:#12121c;
72  --bg-card:#0d0d16;
73  --border:rgba(255,255,255,0.06);
74  --border-bright:rgba(255,255,255,0.14);
75  --text-primary:#e8eaf0;
76  --text-secondary:#8b90a0;
77  --text-muted:#565b6e;
78  --accent:#00d4ff;
79  --accent-dim:#00c88a;
80  --accent-glow:rgba(0,229,160,.12);
81  --accent-glow-strong:rgba(0,229,160,.25);
82  --red:#ff4d6a;
83  --orange:#ff8c42;
84  --blue:#4d9fff;
85  --purple:#a97dff;
86  --yellow:#ffd04d;
87  --font-body:'Outfit',system-ui,sans-serif;
88  --font-mono:'JetBrains Mono',monospace;
89  --radius:10px;
90  --radius-sm:6px;
91  --sidebar-w:260px;
92}
93html{scroll-behavior:smooth;-webkit-text-size-adjust:100%}
94body{font-family:var(--font-body);background:var(--bg-primary);color:var(--text-primary);line-height:1.6;-webkit-font-smoothing:antialiased;min-height:100vh}
95body::before{content:'';position:fixed;inset:0;pointer-events:none;z-index:0;background:radial-gradient(ellipse 80% 50% at 20% 0%,rgba(0,229,160,.05),transparent),radial-gradient(ellipse 60% 40% at 80% 10%,rgba(77,159,255,.03),transparent)}
96a{color:var(--accent);text-decoration:none;transition:color .2s}
97a:hover{color:#33ffc0}
98::selection{background:var(--accent-glow-strong);color:var(--text-primary)}
99code{font-family:var(--font-mono);font-size:.9em}
100@keyframes gradShift{0%,100%{background-position:0% 50%}50%{background-position:100% 50%}}
101
102/* ---- TOP NAV ---- */
103.topnav{position:fixed;top:0;left:0;right:0;z-index:200;height:56px;display:flex;align-items:center;justify-content:space-between;padding:0 24px;background:rgb(3,3,8);border-bottom:1px solid var(--border)}
104.topnav-brand{display:flex;align-items:center;gap:10px;font-weight:700;font-size:20px;letter-spacing:-.03em}
105.topnav-brand img{width:30px;height:30px;border-radius:7px;object-fit:contain;filter:drop-shadow(0 0 10px rgba(0, 212, 255,.2))}
106.topnav-brand .brand-text{font-family:'Chakra Petch',var(--font-body);background:linear-gradient(135deg,#00d4ff 0%,#4d8fff 50%,#a855f7 100%);background-size:200% 200%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;animation:gradShift 8s ease infinite}
107.topnav-links{display:flex;align-items:center;gap:18px;font-size:13px;font-weight:500}
108.topnav-links a{color:var(--text-secondary)}
109.topnav-links a:hover{color:var(--text-primary)}
110.topnav-cta{padding:6px 16px;border-radius:6px;background:var(--accent);color:var(--bg-primary);font-weight:600;font-size:13px;transition:all .2s}
111.topnav-cta:hover{background:#33ffc0;color:var(--bg-primary)}
112.mobile-menu-btn{display:none;background:none;border:none;color:var(--text-secondary);cursor:pointer;padding:4px}
113
114/* ---- SIDEBAR ---- */
115.sidebar{position:fixed;top:56px;left:0;bottom:0;width:var(--sidebar-w);background:var(--bg-secondary);border-right:1px solid var(--border);overflow-y:auto;padding:20px 0;z-index:100;transition:transform .3s}
116.sidebar-group{margin-bottom:24px}
117.sidebar-label{font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.1em;color:var(--text-muted);padding:0 20px;margin-bottom:8px}
118.sidebar-link{display:flex;align-items:center;gap:8px;padding:7px 20px;font-size:13px;color:var(--text-secondary);transition:all .15s;cursor:pointer;border-left:2px solid transparent}
119.sidebar-link:hover{color:var(--text-primary);background:rgba(255,255,255,.02)}
120.sidebar-link.active{color:var(--accent);border-left-color:var(--accent);background:var(--accent-glow)}
121.sidebar-link svg{width:14px;height:14px;opacity:.6;flex-shrink:0}
122
123/* ---- MAIN CONTENT ---- */
124.main{margin-left:var(--sidebar-w);padding:80px 48px 80px;position:relative;z-index:1;max-width:900px}
125.main section{margin-bottom:64px;scroll-margin-top:72px}
126
127/* ---- TYPOGRAPHY ---- */
128h1{font-size:clamp(28px,4vw,42px);font-weight:700;letter-spacing:-.03em;line-height:1.15;margin-bottom:12px}
129h1 em{font-style:normal;background:linear-gradient(135deg,#00d4ff,#4d8fff,#a855f7);background-size:200% 200%;-webkit-background-clip:text;-webkit-text-fill-color:transparent;background-clip:text;animation:gradShift 8s ease infinite}
130h2{font-size:22px;font-weight:600;letter-spacing:-.02em;margin-bottom:8px;display:flex;align-items:center;gap:10px}
131h2 .icon{color:var(--accent);display:inline-flex;align-items:center}
132h2 .icon svg{width:20px;height:20px}
133h3{font-size:16px;font-weight:600;margin:24px 0 10px;color:var(--text-primary)}
134p.sub{font-size:14px;color:var(--text-secondary);margin-bottom:20px;line-height:1.7}
135p.body-text{font-size:14px;color:var(--text-secondary);line-height:1.8;margin-bottom:16px}
136
137/* ---- CARDS ---- */
138.card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius);padding:24px;margin-bottom:16px}
139.card:hover{border-color:var(--border-bright)}
140.info-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:12px;margin:16px 0}
141.info-item{background:var(--bg-tertiary);border:1px solid var(--border);border-radius:var(--radius-sm);padding:16px}
142.info-item .label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.08em;color:var(--text-muted);margin-bottom:4px}
143.info-item .value{font-size:20px;font-weight:700;color:var(--text-primary)}
144.info-item .value span{font-size:12px;font-weight:400;color:var(--text-muted)}
145
146/* ---- CODE BLOCKS ---- */
147.code-tabs{display:flex;gap:0;margin-bottom:0;border-bottom:1px solid var(--border);background:var(--bg-tertiary);border-radius:var(--radius) var(--radius) 0 0}
148.code-tab{padding:8px 16px;font-size:12px;font-weight:600;color:var(--text-muted);cursor:pointer;border-bottom:2px solid transparent;transition:all .15s;background:none;border-top:none;border-left:none;border-right:none;font-family:var(--font-body)}
149.code-tab:hover{color:var(--text-secondary)}
150.code-tab.active{color:var(--accent);border-bottom-color:var(--accent)}
151.code-block{background:var(--bg-primary);border:1px solid var(--border);border-top:none;border-radius:0 0 var(--radius) var(--radius);padding:18px 20px;font-family:var(--font-mono);font-size:13px;line-height:1.8;overflow-x:auto;position:relative;display:none}
152.code-block.active{display:block}
153.code-block-solo{background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius);padding:16px 20px;font-family:var(--font-mono);font-size:13px;line-height:1.8;overflow-x:auto;position:relative}
154.dim{color:var(--text-muted)}
155.str{color:var(--accent)}
156.key-c{color:var(--blue)}
157.comment{color:var(--text-muted);font-style:italic}
158.kw{color:var(--purple)}
159.fn{color:var(--orange)}
160.copy-btn{position:absolute;top:10px;right:10px;background:var(--bg-tertiary);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--text-secondary);font-size:0;padding:6px;cursor:pointer;transition:all .2s;z-index:2;display:flex;align-items:center;justify-content:center}
161.copy-btn:hover{border-color:var(--accent);color:var(--accent)}
162.copy-btn.copied{color:var(--accent);border-color:var(--accent)}
163
164/* ---- ENDPOINTS ---- */
165.endpoint-group{display:flex;flex-direction:column;gap:10px}
166.endpoint{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius);overflow:hidden;transition:border-color .2s}
167/* The nav is position:fixed and 56px tall, so an #ep-… jump used to land the
168   card's method/path row underneath it — the sidebar links reach these cards
169   now, and arriving at a header you cannot read is only half a fix. */
170.endpoint{scroll-margin-top:72px}
171.endpoint:hover{border-color:var(--border-bright)}
172.endpoint-header{display:flex;align-items:center;gap:12px;padding:14px 20px;cursor:pointer;user-select:none;transition:background .15s}
173.endpoint-header:hover{background:rgba(255,255,255,.015)}
174.method-badge{font-family:var(--font-mono);font-size:11px;font-weight:600;padding:4px 10px;border-radius:4px;letter-spacing:.04em;flex-shrink:0}
175.method-get{background:rgba(0,229,160,.1);color:var(--accent);border:1px solid rgba(0,229,160,.2)}
176.method-post{background:rgba(77,159,255,.1);color:var(--blue);border:1px solid rgba(77,159,255,.2)}
177.endpoint-path{font-family:var(--font-mono);font-size:13px;color:var(--text-primary);font-weight:500}
178.endpoint-path .param{color:var(--orange)}
179.endpoint-desc{font-size:13px;color:var(--text-secondary);margin-left:auto;white-space:nowrap}
180.endpoint-chevron{margin-left:12px;color:var(--text-muted);transition:transform .25s;font-size:12px;flex-shrink:0}
181.endpoint.open .endpoint-chevron{transform:rotate(180deg)}
182.endpoint-detail{display:none;padding:0 20px 20px;border-top:1px solid var(--border)}
183.endpoint.open .endpoint-detail{display:block}
184.detail-section{margin-top:16px}
185.detail-label{font-size:11px;font-weight:600;color:var(--text-muted);text-transform:uppercase;letter-spacing:.08em;margin-bottom:8px}
186.detail-desc{font-size:13px;color:var(--text-secondary);line-height:1.7;margin-bottom:12px}
187.tag{display:inline-block;padding:2px 8px;border-radius:4px;font-size:11px;font-weight:600}
188.tag-free{background:rgba(0,229,160,.1);color:var(--accent)}
189.tag-paid{background:rgba(169,125,255,.1);color:var(--purple)}
190/* Plan badges: the tag names the CHEAPEST plan that unlocks the endpoint,
191   so Starter also covers every Free one and Pro covers all 24. */
192.tag-starter{background:rgba(0,212,255,.1);color:#00d4ff}
193.tag-pro{background:rgba(169,125,255,.1);color:var(--purple)}
194.tag-chain{background:rgba(255,255,255,.06);color:var(--text-muted);font-weight:500}
195
196/* ---- TABLES ---- */
197.param-table{width:100%;border-collapse:collapse;font-size:13px;min-width:540px}
198.param-table th{text-align:left;font-weight:500;color:var(--text-muted);padding:6px 12px;font-size:11px;text-transform:uppercase;letter-spacing:.06em}
199.param-table td{padding:8px 12px;border-top:1px solid var(--border);color:var(--text-secondary)}
200.param-table .param-name{font-family:var(--font-mono);color:var(--text-primary);font-weight:500}
201.param-table .param-type{font-family:var(--font-mono);color:var(--purple);font-size:12px}
202.param-table .required{color:var(--red);font-size:11px;font-weight:600}
203
204.field-table{width:100%;border-collapse:collapse;font-size:12px;min-width:540px}
205.field-table th{text-align:left;font-weight:600;color:var(--text-muted);padding:6px 10px;font-size:10px;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary)}
206.field-table td{padding:7px 10px;border-top:1px solid var(--border);color:var(--text-secondary);vertical-align:top}
207.field-table .fname{font-family:var(--font-mono);color:var(--text-primary);font-weight:500;font-size:12px}
208.field-table .ftype{font-family:var(--font-mono);color:var(--purple);font-size:11px}
209
210.error-table{width:100%;border-collapse:collapse;font-size:13px}
211.error-table th{text-align:left;font-weight:500;color:var(--text-muted);padding:8px 12px;font-size:11px;text-transform:uppercase;letter-spacing:.06em;background:var(--bg-tertiary)}
212.error-table td{padding:10px 12px;border-top:1px solid var(--border);color:var(--text-secondary)}
213.error-table tr:hover td{background:rgba(255,255,255,.01)}
214.status-code{font-family:var(--font-mono);font-weight:600}
215.s4{color:var(--orange)}.s5{color:var(--red)}
216
217/* ---- RESPONSE EXAMPLE ---- */
218.response-example{background:var(--bg-primary);border:1px solid var(--border);border-radius:var(--radius-sm);padding:14px 18px;font-family:var(--font-mono);font-size:12px;line-height:1.7;overflow-x:auto;max-height:320px;overflow-y:auto;color:var(--text-secondary)}
219.response-example .key-r{color:var(--blue)}
220.response-example .val-s{color:var(--accent)}
221.response-example .val-n{color:var(--orange)}
222.response-example .val-b{color:var(--purple)}
223
224/* ---- PRICING ---- */
225.pricing-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(200px,1fr));gap:14px}
226.price-card{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius);padding:24px 20px;display:flex;flex-direction:column;gap:10px;transition:border-color .2s,transform .2s;position:relative}
227.price-card:hover{border-color:var(--border-bright);transform:translateY(-2px)}
228.price-card.featured{border-color:rgba(0,229,160,.3);background:linear-gradient(to bottom,rgba(0,229,160,.04),var(--bg-secondary))}
229.price-card.featured::before{content:'Popular';position:absolute;top:-10px;right:16px;background:linear-gradient(135deg,#00d4ff,#4d8fff);color:var(--bg-primary);font-size:10px;font-weight:700;text-transform:uppercase;letter-spacing:.08em;padding:3px 10px;border-radius:100px}
230.price-tier{font-size:13px;font-weight:600;color:var(--text-secondary)}
231.price-amount{font-size:32px;font-weight:700;letter-spacing:-.03em;line-height:1}
232.price-amount span{font-size:13px;font-weight:400;color:var(--text-muted)}
233.price-features{list-style:none;display:flex;flex-direction:column;gap:6px;margin-top:4px}
234.price-features li{font-size:12px;color:var(--text-secondary);display:flex;align-items:center;gap:8px}
235.price-features li::before{content:'';width:4px;height:4px;border-radius:50%;background:var(--accent);flex-shrink:0}
236.price-btn{display:block;margin-top:auto;padding:10px 0;width:100%;background:var(--accent);color:var(--bg-primary);border:none;border-radius:8px;font-family:var(--font-body);font-size:13px;font-weight:700;cursor:pointer;transition:all .2s;text-align:center;text-decoration:none}
237.price-btn:hover{opacity:.85;color:var(--bg-primary)}
238.price-btn:disabled{opacity:.5;cursor:wait}
239.price-btn-secondary{background:rgba(255,255,255,.08);color:var(--text-primary);border:1px solid var(--border-bright)}
240.price-btn-secondary:hover{background:rgba(255,255,255,.12);color:var(--text-primary)}
241.price-btn-crypto{margin-top:8px;background:transparent;color:var(--accent);border:1px solid var(--accent)}
242.price-btn-crypto:hover{background:rgba(0,229,160,.1);color:var(--accent)}
243
244/* ---- RATE LIMIT ---- */
245.rl-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(260px,1fr));gap:12px}
246.rl-item{background:var(--bg-secondary);border:1px solid var(--border);border-radius:var(--radius-sm);padding:14px 18px}
247.rl-header-name{font-family:var(--font-mono);font-size:13px;color:var(--blue);font-weight:500}
248.rl-desc{font-size:13px;color:var(--text-secondary);margin-top:4px}
249
250/* ---- CALLOUT ---- */
251.callout{border-radius:var(--radius-sm);padding:14px 18px;font-size:13px;line-height:1.7;margin:16px 0;display:flex;gap:10px;align-items:flex-start}
252.callout svg{flex-shrink:0;margin-top:2px}
253.callout-info{background:rgba(77,159,255,.06);border:1px solid rgba(77,159,255,.15);color:var(--text-secondary)}
254.callout-warn{background:rgba(255,140,66,.06);border:1px solid rgba(255,140,66,.15);color:var(--text-secondary)}
255.callout-tip{background:rgba(0,229,160,.06);border:1px solid rgba(0,229,160,.15);color:var(--text-secondary)}
256.callout strong{color:var(--text-primary)}
257
258/* ---- FOOTER ---- */
259.footer{margin-left:var(--sidebar-w);padding:32px 48px;border-top:1px solid var(--border);display:flex;align-items:center;justify-content:space-between;font-size:13px;color:var(--text-muted);flex-wrap:wrap;gap:12px}
260.footer a{color:var(--text-secondary)}
261
262/* ---- SCROLLBAR ---- */
263::-webkit-scrollbar{width:5px;height:5px}
264::-webkit-scrollbar-track{background:transparent}
265::-webkit-scrollbar-thumb{background:var(--border-bright);border-radius:3px}
266::-webkit-scrollbar-thumb:hover{background:var(--text-muted)}
267
268/* ---- RESPONSIVE ---- */
269@media(max-width:900px){
270  .sidebar{transform:translateX(-100%)}
271  .sidebar.open{transform:translateX(0)}
272  .main,.footer{margin-left:0;padding-left:20px;padding-right:20px}
273  .topnav-links .hide-mobile{display:none}
274  /* The bar has to hold the site burger, the brand, the account pill and the
275     CTA inside 375px. When it cannot, js/nav-drawer.js gives up and floats the
276     burger into a corner — which is how it ended up sideways on the right. */
277  .topnav{padding:0 24px;gap:10px}
278  .topnav-brand{font-size:17px;gap:7px}
279  .topnav-brand img{width:26px;height:26px}
280  .topnav-links{gap:10px}
281  .topnav-cta{padding:6px 11px;font-size:12px;white-space:nowrap}
282  .pricing-grid{grid-template-columns:1fr 1fr}
283  .endpoint-header{flex-wrap:wrap;gap:8px;padding:12px 16px}
284  .endpoint-desc{margin-left:0;order:3;width:100%;white-space:normal}
285  .footer{flex-direction:column;align-items:flex-start;padding-left:20px}
286  .sidebar-overlay{display:none;position:fixed;inset:0;top:56px;background:rgba(0,0,0,.5);z-index:99}
287  .sidebar-overlay.open{display:block}
288}
289@media(max-width:500px){
290  .pricing-grid{grid-template-columns:1fr}
291  .info-grid{grid-template-columns:1fr}
292  .topnav{padding:0 24px;gap:8px}
293  .topnav-brand{font-size:15px;gap:6px}
294  .topnav-brand img{width:24px;height:24px}
295  .topnav-cta{padding:5px 9px;font-size:11px}
296}
297</style>
298  <link rel="stylesheet" href="/css/auth.css">
299<script src="/js/site-access.js" defer></script>
299
300<!-- Page-to-page navigation: prefetch a static page's HTML when a link is hovered
301     (token and receipt pages are server-rendered, so they are left out), and keep
302     the current page on screen until the next one can paint instead of flashing blank. -->
303<style>@view-transition{navigation:auto}@media (prefers-reduced-motion:reduce){::view-transition-group(*),::view-transition-old(*),::view-transition-new(*){animation:none}}</style>
304<script type="speculationrules">{"prefetch":[{"where":{"and":[{"href_matches":"/*"},{"not":{"href_matches":"/*\\?*"}},{"not":{"href_matches":"/api/*"}},{"not":{"href_matches":"/token/*"}},{"not":{"href_matches":"/receipt/*"}},{"not":{"href_matches":"/pump-receipt/*"}},{"not":{"href_matches":"/callback/*"}},{"not":{"href_matches":"/delete-account"}},{"not":{"selector_matches":"[download], [target=_blank]"}}]},"eagerness":"moderate"}]}</script>
304
305</head>
306<body>
307<script src="/js/nav-drawer.js" defer></script>
vendor: 1 bytes, line 307
307
308<script src="/js/native-page.js"></script>
308
309<style>
310/* Native app: the shared adapter pads .nav/.page-header pages, but this page
311   uses a FIXED 56px .topnav with a fixed .sidebar hung at top:56px — grow the
312   topnav by the status-bar inset and shift the whole frame down with it. */
313body.is-native:not(.is-android) .topnav, body.fullbleed-top .topnav {
314  height: calc(56px + max(calc(env(safe-area-inset-top) - 12px), 47px));
315  padding-top: max(calc(env(safe-area-inset-top) - 12px), 47px);
316}
317body.is-native:not(.is-android) .sidebar, body.fullbleed-top .sidebar,
318body.is-native:not(.is-android) .sidebar-overlay, body.fullbleed-top .sidebar-overlay {
319  top: calc(56px + max(calc(env(safe-area-inset-top) - 12px), 47px));
320}
321body.is-native:not(.is-android) .main, body.fullbleed-top .main {
322  padding-top: calc(80px + max(calc(env(safe-area-inset-top) - 12px), 47px));
323}
324</style>
325
326<!-- TOP NAV -->
327<nav class="topnav">
328  <div class="topnav-links">
329    <a href="https://defade.org/developers" target="_blank" class="topnav-cta">Get API Key</a>
330    <div class="nav-links"></div>
331  </div>
332</nav>
333
334<!-- SIDEBAR -->
335<div class="sidebar-overlay" id="sidebar-overlay"></div>
336<aside class="sidebar" id="sidebar">
337  <div class="sidebar-group">
338    <div class="sidebar-label">Getting Started</div>
339    <a class="sidebar-link" href="#overview"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>Overview</a>
340    <a class="sidebar-link" href="#quickstart"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg>Quick Start</a>
341    <a class="sidebar-link" href="#auth"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg>Authentication</a>
342    <a class="sidebar-link" href="#generate-key"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 11-7.778 7.778 5.5 5.5 0 017.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg>Generate API Key</a>
343  </div>
344  <div class="sidebar-group">
345    <div class="sidebar-label">API Reference</div>
346    <a class="sidebar-link" href="#endpoints"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg>Endpoints</a>
347    <a class="sidebar-link" href="#ep-analyze"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/></svg>Full Analysis</a>
348    <a class="sidebar-link" href="#ep-rug-score"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>Rug Score</a>
349    <a class="sidebar-link" href="#ep-token-price"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="1" x2="12" y2="23"/><path d="M17 5H9.5a3.5 3.5 0 000 7h5a3.5 3.5 0 010 7H6"/></svg>Token Price</a>
350    <a class="sidebar-link" href="#ep-holders"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M17 21v-2a4 4 0 00-4-4H5a4 4 0 00-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 00-3-3.87"/><path d="M16 3.13a4 4 0 010 7.75"/></svg>Holders</a>
351    <a class="sidebar-link" id="more-endpoints-link" href="#endpoints" style="padding-left:28px;font-size:12px;color:var(--text-muted)">more endpoints</a>
352    <a class="sidebar-link" href="#chains"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/></svg>Chains</a>
353  </div>
354  <div class="sidebar-group">
355    <div class="sidebar-label">Guides</div>
356    <a class="sidebar-link" href="#pricing"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 3h12l4 6-10 13L2 9z"/><path d="M2 9h20"/></svg>Pricing &amp; Plans</a>
357    <a class="sidebar-link" href="#overage-credits"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v12M6 12h12"/></svg>Overage Credits</a>
358    <a class="sidebar-link" href="#rate-limits"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>Rate Limits</a>
359    <a class="sidebar-link" href="#errors"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/>
359<line x1="12" y1="17" x2="12.01" y2="17"/></svg>Error Handling</a>
360    <a class="sidebar-link" href="#sdks"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg>SDKs &amp; Integration</a>
361    <a class="sidebar-link" href="#mcp"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a3 3 0 00-3 3v1a3 3 0 006 0V5a3 3 0 00-3-3z"/><path d="M12 9v4"/><path d="M5 22v-5a7 7 0 0114 0v5"/></svg>MCP Connector</a>
362    <a class="sidebar-link" href="#changelog"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg>Changelog</a>
363  </div>
364</aside>
365
366<!-- MAIN CONTENT -->
367<div class="main">
368
369  <!-- OVERVIEW -->
370  <section id="overview">
371    <h1>Token <em>intelligence</em>, one API call away</h1>
372    <p class="body-text">The DeFade API gives developers programmatic access to the same on-chain risk analysis that powers <a href="https://defade.org" target="_blank">defade.org</a>. Analyze any token for rug pull risk, insider networks, bundle manipulation, smart money activity, and more — all via a fast REST API. Every endpoint defaults to Solana; adding <code>?chain=</code> runs the same analysis on Ethereum, Base or Robinhood Chain for keys on an All-Chains plan — see <a href="#chains">Chains</a>.</p>
373
374    <div class="info-grid">
375      <div class="info-item"><div class="label">Base URL</div><div class="value" style="font-family:var(--font-mono);font-size:14px;color:var(--accent)">api.defade.org</div></div>
376      <div class="info-item"><div class="label">Protocol</div><div class="value" style="font-size:14px">REST / HTTPS</div></div>
377      <div class="info-item"><div class="label">Format</div><div class="value" style="font-size:14px">JSON</div></div>
378      <div class="info-item"><div class="label">Auth</div><div class="value" style="font-size:14px">API Key</div></div>
379      <div class="info-item"><div class="label">Endpoints</div><div class="value">22</div></div>
380      <div class="info-item ios-web-pay"><div class="label">Plans from</div><div class="value" style="font-size:14px">$29/mo</div></div>
381      <div class="info-item"><div class="label">Status</div><div class="value" style="font-size:14px"><a href="/api-status" style="color:var(--accent);text-decoration:none;">Live latency &amp; errors</a></div></div>
382    </div>
383
384    <h3>What can you build?</h3>
385    <p class="body-text">Trading bots that check rug risk before buying. Portfolio dashboards with real-time risk scoring. Telegram/Discord bots for community token screening. Browser extensions that warn users on DEX pages. Analytics platforms tracking insider activity across Solana, Ethereum, Base and Robinhood Chain.</p>
386  </section>
387
388  <!-- QUICK START -->
389  <section id="quickstart">
390    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"/></svg></span> Quick Start</h2>
391    <p class="sub">Make your first API call in under 60 seconds.</p>
392
393    <h3>1. Get an API key</h3>
394    <p class="body-text">Paid plans are self-serve: pick Starter, Pro or Enterprise under <a href="#pricing">Pricing</a> (or at <a href="https://defade.org/developers">defade.org/developers</a>), pay by card or crypto, and your key is shown on the confirmation page and emailed to you straight away. Want to try first? <a href="https://defade.org/developers#keygen">Request a free 7-day trial key</a> and tell us what you're building; we review and email it, usually within 24 hours. Either way, send the key with every request in the <code>x-api-key</code> header. The same key also powers the <a href="#mcp">MCP connector</a> for Claude and ChatGPT.</p>
395
396    <h3>2. Analyze a token</h3>
397    <p class="body-text">Use your key to run a full analysis on any Solana token mint address:</p>
398
399    <div class="code-tabs" id="tabs-qs">
400      <button class="code-tab active" onclick="switchTab('tabs-qs','qs-curl',this)">cURL</button>
401      <button class="code-tab" onclick="switchTab('tabs-qs','qs-js',this)">JavaScript</button>
402      <button class="code-tab" onclick="switchTab('tabs-qs','qs-py',this)">Python</button>
403    </div>
404    <div class="code-block active" data-group="tabs-qs" id="qs-curl">
405      <button class="copy-btn" onclick="copyBlock(this,'qs-curl')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
406<pre><span class="dim">
406curl</span> <span class="str">https://api.defade.org/v1/analyze/YOUR_TOKEN_MINT</span> \
407  <span class="dim">-H</span> <span class="str">"x-api-key: df_your_api_key"</span></pre>
408    </div>
409    <div class="code-block" data-group="tabs-qs" id="qs-js">
410      <button class="copy-btn" onclick="copyBlock(this,'qs-js')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
411<pre><span class="kw">const</span> <span class="fn">res</span> = <span class="kw">await</span> <span class="fn">fetch</span>(<span class="str">'https://api.defade.org/v1/analyze/YOUR_TOKEN_MINT'</span>, {
412  <span class="key-c">headers</span>: { <span class="str">'x-api-key'</span>: <span class="str">'df_your_api_key'</span> }
413});
414<span class="kw">const</span> data = <span class="kw">await</span> res.<span class="fn">json</span>();
415console.<span class="fn">log</span>(data.risk.score, data.risk.rating);</pre>
416    </div>
417    <div class="code-block" data-group="tabs-qs" id="qs-py">
418      <button class="copy-btn" onclick="copyBlock(this,'qs-py')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
419<pre><span class="kw">import</span> requests
420
421res = requests.<span class="fn">get</span>(
422    <span class="str">'https://api.defade.org/v1/analyze/YOUR_TOKEN_MINT'</span>,
423    <span class="key-c">headers</span>={<span class="str">'x-api-key'</span>: <span class="str">'df_your_api_key'</span>}
424)
425data = res.<span class="fn">json</span>()
426<span class="fn">print</span>(data[<span class="str">'risk'</span>][<span class="str">'score'</span>], data[<span class="str">'risk'</span>][<span class="str">'rating'</span>])</pre>
427    </div>
428
429    <h3>3. Interpret the results</h3>
430    <p class="body-text"><strong>Two endpoints score a token, on scales that run in OPPOSITE directions.</strong> Read this before wiring either into a threshold: <code style="color:var(--orange)">rugScore</code> counts UP toward danger, while <code style="color:var(--orange)">risk.score</code> counts DOWN toward it. A token scoring 85 is near-certain trouble on one and near-clean on the other.</p>
431
432    <h4 style="margin:20px 0 8px">/v1/rug-score &mdash; <code style="color:var(--orange)">rugScore</code>
432, 0 safe &rarr; 100 critical</h4>
433    <p class="body-text">The rug probability model. Higher is worse. <code>verdict</code> is the label, <code>verdictColor</code> the colour to render it in.</p>
434    <div style="overflow-x:auto;border:1px solid var(--border);border-radius:var(--radius-sm)">
435      <table class="field-table">
436        <thead><tr><th>rugScore</th><th>verdict</th><th>verdictColor</th><th>Interpretation</th></tr></thead>
437        <tbody>
438          <tr><td class="fname">0&ndash;24</td><td style="color:var(--accent-dim);font-weight:600">PROBABLY SAFE</td><td class="fname" style="color:var(--text-muted)">green</td><td>Minimal risk indicators. Liquidity and holder distribution look healthy, no major flags.</td></tr>
439          <tr><td class="fname">25&ndash;44</td><td style="color:var(--yellow);font-weight:600">SOME RISK</td><td class="fname" style="color:var(--text-muted)">yellow</td><td>A few risk factors present. Review the detailed analysis before trading.</td></tr>
440          <tr><td class="fname">45&ndash;59</td><td style="color:var(--orange);font-weight:600">ELEVATED RISK</td><td class="fname" style="color:var(--text-muted)">orange</td><td>Several signals stacking up. This is the band at which a token is auto-recorded to the rug database.</td></tr>
441          <tr><td class="fname">60&ndash;74</td><td style="color:var(--red);font-weight:600">HIGH RISK</td><td class="fname" style="color:var(--text-muted)">red</td><td>Significant risk signals: bundled wallets, concentrated holdings, or suspicious dev activity.</td></tr>
442          <tr><td class="fname">75&ndash;100</td><td style="color:var(--red);font-weight:600">EXTREME RISK</td><td class="fname" style="color:var(--text-muted)">red</td><td>Strong rug pull indicators. The coordinated-supply kill switch floors the score here.</td></tr>
443        </tbody>
444      </table>
445      <p class="body-text" style="margin-top:12px">Tokens that have already collapsed override the bands entirely and return <code>RUGGED / DEAD</code> or <code>ABANDONED / DEAD</code>, signalling liquidity or activity has effectively gone to zero. A launchpad coin that never left its bonding curve returns <code>NEVER BONDED</code> instead: no pool ever existed, so nothing could be pulled. <code>rugScore</code> is still a number in every case; <code>scoreLabel</code> is <code>"NEVER BONDED"</code>
445 when DeFade's own surfaces print the state in place of the percentage, and <code>null</code> otherwise.</p>
446    </div>
447
448    <h4 style="margin:24px 0 8px">/v1/analyze &mdash; <code style="color:var(--orange)">risk.score</code>, 100 safe &rarr; 0 critical</h4>
449    <p class="body-text">The legacy safety score, carried on the <code>risk</code> object as <code>score</code>, <code>rating</code>, <code>color</code> and <code>flags</code>. <strong>Higher is safer</strong> &mdash; the inverse of rugScore, and a different set of labels. If you only need one number, use /v1/rug-score.</p>
450    <div style="overflow-x:auto;border:1px solid var(--border);border-radius:var(--radius-sm)">
451      <table class="field-table">
452        <thead><tr><th>risk.score</th><th>risk.rating</th><th>risk.color</th><th>Interpretation</th></tr></thead>
453        <tbody>
454          <tr><td class="fname">80&ndash;100</td><td style="color:var(--accent-dim);font-weight:600">PROBABLY SAFE</td><td class="fname" style="color:var(--text-muted)">green</td><td>No blocking signals found.</td></tr>
455          <tr><td class="fname">70&ndash;79</td><td style="color:var(--yellow);font-weight:600">PROCEED WITH CAUTION</td><td class="fname" style="color:var(--text-muted)">yellow</td><td>Minor flags worth reading before acting.</td></tr>
456          <tr><td class="fname">60&ndash;69</td><td style="color:var(--orange);font-weight:600">ELEVATED RISK</td><td class="fname" style="color:var(--text-muted)">orange</td><td>Real signals present, short of the high-risk bands.</td></tr>
457          <tr><td class="fname">40&ndash;59</td><td style="color:var(--orange);font-weight:600">HIGH RISK</td><td class="fname" style="color:var(--text-muted)">orange</td><td>Significant flags across liquidity, holders or the dev wallet.</td></tr>
458          <tr><td class="fname">20&ndash;39</td><td style="color:var(--red);font-weight:600">VERY HIGH RISK</td><td class="fname" style="color:var(--text-muted)">red</td><td>Severe, stacked signals.</td></tr>
459          <tr><td class="fname">0&ndash;19</td><td style="color:var(--red);font-weight:600">LIKELY RUG</td><td class="fname" style="color:var(--text-muted)">red</td><td>The strongest signals the legacy model has.</td></tr>
460        </tbody>
461      </table>
462      <p class="body-text" style="margin-top:12px">A collapsed token is capped at a score of 15 and rated <code>DEAD / RUGGED</code>, <code>FAILED / ABANDONED</code> or <code>NEVER BONDED</code> (still on its bonding curve) &mdash; note these strings differ from the /v1/rug-score overrides above; match on both if you consume the two endpoints.</p>
463    </div>
464  </section>
465
466  <!-- AUTHENTICATION -->
467  <section id="auth">
468    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="3" y="11" width="18" height="11" rx="2" ry="2"/><path d="M7 11V7a5 5 0 0110 0v4"/></svg></span> Authentication</h2>
469    <p class="sub">All API requests require authentication via an API key.</p>
470
471    <p class="body-text">Include your key using either the <code style="color:var(--blue)">x-api-key</code> request header (recommended) or the <code style="color:var(--blue)">api_key</code> query parameter. The header method is preferred as it keeps your key out of server logs and browser history.</p>
472
473    <div class="code-tabs" id="tabs-auth">
474      <button class="code-tab active" onclick="switchTab('tabs-auth','auth-header',this)">Header (recommended)</button>
475      <button class="code-tab" onclick="switchTab('tabs-auth','auth-query',this)">Query Parameter</button>
476    </div>
477    <div class="code-block active" data-group="tabs-auth" id="auth-header">
478<pre><span class="dim">curl</span> <span class="str">https://api.defade.org/v1/rug-score/TOKEN_MINT</span> \
479  <span class="dim">-H</span> <span class="str">"x-api-key: df_your_api_key_here"</span></pre>
480    </div>
481    <div class="code-block" data-group="tabs-auth" id="auth-query">
482<pre><span class="dim">curl</span> <span class="str">"https://api.defade.org/v1/rug-score/TOKEN_MINT?api_key=df_your_api_key_here"</span></pre>
483    </div>
484
485    <div class="callout callout-warn">
486      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--orange)" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
487      <div><strong>Keep your API key secret.</strong> Never expose it in client-side code, public repos, or browser requests. For frontend apps, proxy requests through your own backend.</div>
488    </div>
489  </section>
490
491  <!-- GENERATE KEY -->
492  <section id="generate-key">
493    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M21 2l-2 2m-7.61 7.61a5.5 5.5 0 11-7.778 7.778 5.5 5.5 0 017.777-7.777zm0 0L15.5 7.5m0 0l3 3L22 7l-3-3m-3.5 3.5L19 4"/></svg></span> Get an API Key</h2>
494    <p class="sub">Buy a plan and the key is yours immediately, or request a free 7-day trial.</p>
495
496    <p class="body-text"><strong>Paid plans are self-serve.</strong> Choose Starter, Pro or Enterprise under <a href="#pricing">Pricing</a> or on <a href="https://defade.org/developers">defade.org/developers</a> and pay by card (Stripe) or crypto. The key is shown on the confirmation page and emailed to you the moment payment clears; no review, no waiting. Every paid plan covers all four chains and every endpoint; the plans differ on monthly allowance and rate limit.</p>
497    <p class="body-text"><strong>Free trial keys are issued on request.</strong> Submit the form at <a href="https://defade.org/developers#keygen">defade.org/developers#keygen</a> with a short note on what you're building. We review each request and email a 7-day trial key, usually within 24 hours. Trial keys reach six endpoints (<code>analyze</code>, <code>rug-score</code>, <code>token-price</code>, <code>holders</code>, <code>kol</code>, <code>trending</code>) plus <code>usage</code>, on every chain we cover &mdash; Solana, Ethereum, Base and Robinhood &mdash; at 10 req/min, 100 req/day and 3,000 units/month.</p>
498    <p class="body-text">An API-plan key works everywhere: the REST API from your own code and the <a href="#mcp">MCP connector</a> in Claude or ChatGPT, same plan, same quota. DeFade Pro <em>web</em> subscribers get a different, connector-only key from their dashboard; it reaches the connector's tools, spends the plan's monthly scan allowance, and is not valid on the REST API. See <a href="#mcp">MCP connector → Getting a key</a>.</p>
499
500    <h3>Using your key</h3>
501    <p class="body-text">Send your key with every request in the <code>x-api-key</code> header (or as an <code>api_key</code> query parameter). Every paid plan can call all 25 endpoints on every chain; the plans differ on how many requests a month you get and how fast you may send them. See <a href="#authentication">Authentication</a> for details.</p>
502
503    <div class="callout callout-info">
504      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--blue)" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
505      <div><strong>Need higher limits?</strong> Every plan includes all 25 endpoints; Pro and Enterprise raise the monthly allowance and the rate limit. Email <a href="mailto:[email protected]" target="_blank">[email protected]</a>.</div>
506    </div>
507  </section>
508
509  <!-- ENDPOINTS -->
510  <section id="endpoints">
511    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><polyline points="16 18 22 12 16 6"/><polyline points="8 6 2 12 8 18"/></svg></span> API Endpoints</h2>
512    <p class="sub">25 endpoints covering every angle of on-chain risk. Click any endpoint to expand full details, parameters, and response schema. Every paid plan unlocks all 25 endpoints — plans differ on included volume, rate limit and chains. The second badge shows chain support: 21 run on every chain, <code>bundles</code> and <code>fee-fingerprint</code> are Solana-only, and <code>usage</code> reports on your key so it has no chain at all (see <a href="#chains">Chains</a>).</p>
513    <p class="body-text">Every endpoint wraps its result in the same envelope: <code>token</code> (the mint you asked about), <code>timestamp</code> (when the response was assembled) and <code>poweredBy</code>, with the endpoint&#39;s own fields in between. Five exceptions: <code>/v1/holder-overlap</code> and <code>/v1/wallet-overlap</code>
513 take several mints so they carry <code>mints</code> instead of <code>token</code>; <code>/v1/wallet-reputation</code> is about a wallet, so it carries <code>wallet</code> (and <code>chain</code>); <code>/v1/trending</code> is not about one token so it has no <code>token</code>; and <code>/v1/usage</code> reports on your key, so it has no envelope at all. On <code>/v1/analyze</code> the endpoint&#39;s own <code>token</code> object replaces the envelope&#39;s mint string.</p>
514    <div class="endpoint-group" id="endpoint-list"></div>
515  </section>
516
517  <!-- CHAINS -->
518  <section id="chains">
519    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10 13a5 5 0 007.54.54l3-3a5 5 0 00-7.07-7.07l-1.72 1.71"/><path d="M14 11a5 5 0 00-7.54-.54l-3 3a5 5 0 007.07 7.07l1.71-1.71"/></svg></span> Chains</h2>
520    <p class="sub">One endpoint set, four chains. Solana is the default; <code>?chain=</code> selects an EVM chain.</p>
521
522    <p class="body-text">Every endpoint takes an optional <code style="color:var(--blue)">chain</code> query parameter. Omit it and the request is treated as Solana, so existing integrations keep working with no change. Pass it to run the same analysis on an EVM chain — the response shape is identical, only the addresses differ.</p>
523
524    <div class="code-tabs" id="tabs-chains">
525      <button class="code-tab active" onclick="switchTab('tabs-chains','chain-sol',this)">Solana (default)</button>
526      <button class="code-tab" onclick="switchTab('tabs-chains','chain-evm',this)">EVM chain</button>
527    </div>
528    <div class="code-block active" data-group="tabs-chains" id="chain-sol">
529<pre><span class="dim">curl</span> <span class="str">https://api.defade.org/v1/rug-score/7xKXtg2CW87d97TXJSDpbD5jBkheTqA83TZRuJosgAsU</span> \
530  <span class="dim">-H</span> <span class="str">"x-api-key: df_your_api_key_here"</span></pre>
531    </div>
532    <div class="code-block" data-group="tabs-chains" id="chain-evm">
533<pre><span class="dim">curl</span> <span class="str">"https://api.defade.org/v1/rug-score/0xa0b86991c6218b36c1d19d4a2e9eb0ce3606eb48?chain=base"</span> \
534  <span class="dim">-H</span> <span class="str">"x-api-key: df_your_api_key_here"</span></pre>
535    </div>
536
537    <h3>Supported chains</h3>
538    <div style="overflow-x:auto">
539    <table class="param-table">
540      <thead><tr><th><code>chain</code> value</th><th>Network</th><th>Address format</th></tr></thead>
541      <tbody class="chain-id-rows">
542        <tr><td class="param-name">ethereum</td><td>Ethereum</td><td><code>0x</code> + 40 hex characters</td></tr>
543        <tr><td class="param-name">base</td><td>Base</td><td><code>0x</code> + 40 hex characters</td></tr>
544        <tr><td class="param-name">robinhood</td><td>Robinhood Chain</td><td><code>0x</code> + 40 hex characters</td></tr>
545      </tbody>
546    </table>
547    </div>
548    <p class="body-text" style="margin-top:10px">Plus <code>solana</code> (base58 mint address), which is the default when <code>chain</code> is omitted. Additional chains are added to this list as they launch — this table is generated from the live chain registry, so it always reflects what the API will actually answer for.</p>
549
550    <h3>Which plans reach which chains</h3>
551    <p class="body-text">Chain access is a property of your <em>plan variant</em>, not of the endpoint. Every plan ships in two variants with an <strong>identical endpoint list</strong>:</p>
552    <div style="overflow-x:auto">
553    <table class="param-table">
554      <thead><tr><th>Plan</th><th>Chains</th><th>Endpoints</th></tr></thead>
555      <tbody>
556        <tr><td class="param-name">Starter</td><td>Solana + <span class="chain-name-list">Ethereum, Base, Robinhood Chain</span></td><td>All 23</td></tr>
557        <tr><td class="param-name">Pro</td><td>Solana + <span class="chain-name-list">Ethereum, Base, Robinhood Chain</span></td><td>All 23</td></tr>
558        <tr><td class="param-name">Enterprise</td><td>Solana + <span class="chain-name-list">Ethereum, Base, Robinhood Chain</span></td><td>All 23</td></tr>
559      </tbody>
560    </table>
561    </div>
562    <p class="body-text" style="margin-top:10px">Requesting a <code>chain</code> your plan doesn't cover returns <code>403</code>. Sending a <code>0x</code> address without a <code>chain</code>, or a base58 mint with an EVM <code>chain</code>, returns <code>400</code> — the address format and the chain have to agree.</p>
563
564    <h3>Endpoint coverage on EVM</h3>
565    <p class="body-text">20 of the 25 endpoints run on every chain. Two are Solana-only:</p>
566    <div style="overflow-x:auto">
567    <table class="param-table">
568      <thead><tr><th>
568Endpoint</th><th>Why</th></tr></thead>
569      <tbody>
570        <tr><td class="param-name">/v1/bundles/:mint</td><td>EVM bundle analysis is a single deep implementation and ships as <code>/v1/bundles-pro</code>. On EVM, use <code>bundles-pro</code> (Pro and above).</td></tr>
571        <tr><td class="param-name">/v1/fee-fingerprint/:mint</td><td>It reads the compute-unit price out of Solana <code>ComputeBudget</code> instructions — the fee setting an operator's bot carries across every wallet it drives. EVM transactions have no equivalent field, so there is nothing to re-implement.</td></tr>
572      </tbody>
573    </table>
574    </div>
575    <p class="body-text" style="margin-top:10px"><code>/v1/usage</code> reports on your key rather than on a token, so it takes no <code>chain</code> parameter. <code>/v1/trending</code>, <code>/v1/holder-overlap</code>, <code>/v1/wallet-overlap</code> and <code>/v1/wallet-reputation</code> accept <code>chain</code> as a normal query parameter alongside their own.</p>
576
577    <div class="callout callout-warn">
578      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--orange)" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg>
579      <div><strong>EVM endpoints are rolling out.</strong> The <code>chain</code> parameter and the plan variants above are the shipping contract, documented ahead of the switch-on so you can build against them. Until EVM activates, requests with <code>?chain=</code> set to an EVM network return <code>400</code>. Solana is unaffected. Email <a href="mailto:[email protected]" target="_blank">[email protected]</a> to be told the moment it goes live.</div>
580    </div>
581  </section>
582
583  <!-- PRICING -->
584  <section id="pricing" class="ios-web-pay">
585    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M6 3h12l4 6-10 13L2 9z"/><path d="M2 9h20"/></svg></span> Pricing &amp; Plans</h2>
586    <p class="sub">Start free. Scale as you grow. Pro and Enterprise unlock every endpoint.</p>
587    <!-- Billing period. Always visible: yearly is 20% off on every plan and
588         both rails (card and crypto) honour it. -->
589    <div id="docsBilling" style="display:flex;gap:6px;margin:0 0 10px;">
590      <button type="button" data-period="monthly" onclick="setDocsBilling('monthly')" style="padding:7px 16px;border-radius:8px;border:1px solid var(--border-bright);background:var(--accent);color:var(--bg-primary);font-family:var(--font-body);font-size:12px;font-weight:700;cursor:pointer;">Monthly</button>
591      <button type="button" data-period="yearly" onclick="setDocsBilling('yearly')" style="padding:7px 16px;border-radius:8px;border:1px solid var(--border-bright);background:transparent;color:var(--text-primary);font-family:var(--font-body);font-size:12px;font-weight:700;cursor:pointer;">Yearly &minus;20%</button>
592    </div>
593    <!-- One plan family since 2026-08-22: every plan covers every chain
594         (Solana, Ethereum, Base, Robinhood) — no scope toggle. -->
595    <div class="pricing-grid">
596      <div class="price-card">
597        <div class="price-tier">Lite</div>
598        <div class="price-amount" id="docsLiteAmt">$29 <span>/mo</span></div>
599        <ul class="price-features">
600          <li>1,000 requests / month</li>
601          <li>15 requests / min</li>
602          <li>All 25 endpoints</li>
603          <li>All chains — Solana, Ethereum, Base &amp; Robinhood</li>
604          <li>REST API + MCP connector (15 tools)</li>
605          <li>Email support</li>
606        </ul>
607        <button type="button" id="docsLiteBtn" class="price-btn" onclick="docsSubscribe('lite',this)">Pay with card</button>
608          <a href="/crypto-checkout?product=api_lite_all_monthly" id="docsLiteCrypto" class="price-btn price-btn-crypto">Pay with crypto</a>
609      </div>
610      <div class="price-card">
611        <div class="price-tier">Starter</div>
612        <div class="price-amount" id="docsStarterAmt">$99 <span>/mo</span></div>
613        <ul class="price-features">
614          <li>5,000 requests / month</li>
615          <li>30 requests / min</li>
616          <li>All 25 endpoints</li>
617          <li>All chains — Solana, Ethereum, Base &amp; Robinhood</li>
618          <li>REST API + MCP connector (15 tools)</li>
619          <li>Email support</li>
620        </ul>
621        <button type="button" id="docsStarterBtn" class="price-btn" onclick="docsSubscribe('starter',this)">Pay with card</button>
622          <a href="/crypto-checkout?product=api_starter_all_monthly" id="docsStarterCrypto" class="price-btn price-btn-crypto">Pay with crypto</a>
623      </div>
624      <div class="price-card">
625        <div class="price-tier">Growth</div>
626        <div class="price-amount" id="docsGrowthAmt">$199 <span>/mo</span></div>
627        <ul class="price-features">
628          <li>10,000 requests / month</li>
629          <li>45 requests / min</li>
630          <li>All 25 endpoints</li>
631          <li>All chains &mdash; Solana, Ethereum, Base &amp; Robinhood</li>
632          <li>REST API + MCP connector (15 tools)</li>
633          <li>Email support</li>
634        </ul>
635        <button type="button" id="docsGrowthBtn" class="price-btn" onclick="docsSubscribe('growth',this)">Pay with card</button>
636          <a href="/crypto-checkout?product=api_growth_all_monthly" id="docsGrowthCrypto" class="price-btn price-btn-crypto">Pay with crypto</a>
637      </div>
638      <div class="price-card featured">
639        <div class="price-tier">Pro</div>
640        <div class="price-amount" id="docsProAmt">$399 <span>/mo</span></div>
641        <ul class="price-features">
642          <li>20,000 requests / month</li>
643          <li>60 requests / min</li>
644          <li>All 25 endpoints</li>
645          <li>All chains — Solana, Ethereum, Base &amp; Robinhood</li>
646          <li>REST API + MCP connector (15 tools)</li>
647          <li>
647Priority support</li>
648        </ul>
649        <button type="button" id="docsProBtn" class="price-btn" onclick="docsSubscribe('pro',this)">Pay with card</button>
650          <a href="/crypto-checkout?product=api_pro_all_monthly" id="docsProCrypto" class="price-btn price-btn-crypto">Pay with crypto</a>
651      </div>
652      <div class="price-card">
653        <div class="price-tier">Enterprise</div>
654        <div class="price-amount" id="docsEntAmt">$1,999 <span>/mo</span></div>
655        <ul class="price-features">
656          <li>100,000 requests / month</li>
657          <li>200 requests / min</li>
658          <li>All 25 endpoints</li>
659          <li>All chains — Solana, Ethereum, Base &amp; Robinhood</li>
660          <li>REST API + MCP connector (15 tools)</li>
661          <li>Dedicated support &amp; SLA</li>
662        </ul>
663        <button type="button" id="docsEntBtn" class="price-btn price-btn-secondary" onclick="docsSubscribe('enterprise',this)">Pay with card</button>
664          <a href="/crypto-checkout?product=api_enterprise_all_monthly" id="docsEntCrypto" class="price-btn price-btn-crypto">Pay with crypto</a>
665      </div>
666    </div>
667
668    <h3>What each plan includes</h3>
669    <p class="body-text">Every paid plan includes <strong>all 25 endpoints on every chain</strong> — plans differ by monthly request volume, rate limits and support. Expensive deep-analysis calls are metered in request units, so heavy endpoints draw more units per call. The free tier covers 6 endpoints. Calling past your plan returns <code>403</code> or <code>402</code> with upgrade instructions.</p>
670
671    <div style="overflow-x:auto">
672    <table class="param-table" style="margin-top:14px">
673      <thead><tr><th>Plan</th><th>Endpoints</th><th>What it adds</th></tr></thead>
674      <tbody>
675        <tr>
676          <td class="param-name">Free</td>
677          <td>6</td>
678          <td><code>analyze</code>, <code>rug-score</code>, <code>token-price</code>, <code>trending</code>, <code>holders</code>, <code>kol</code></td>
679        </tr>
680        <tr>
681          <td class="param-name">Starter</td>
682          <td>All 23</td>
683          <td>5,000 units/mo · 30 req/min — every endpoint incl. the deep-analysis modules (<code>funding-origin</code>, <code>funding-graph</code>, <code>sybil-cluster</code>, <code>fee-fingerprint</code>, <code>bundles-pro</code>, <code>historical-bundles</code>, <code>holder-overlap</code>, <code>wallet-overlap</code>, <code>wallet-reputation</code>)</td>
684        </tr>
685        <tr>
686          <td class="param-name">Pro</td>
687          <td>All 23</td>
688          <td>20,000 units/mo · 60 req/min · priority support</td>
689        </tr>
690        <tr>
691          <td class="param-name">Enterprise</td>
692          <td>All 23</td>
693          <td>100,000 units/mo · 200 req/min · dedicated support &amp; SLA</td>
694        </tr>
695      </tbody>
696    </table>
697    </div>
698
699    <p class="body-text" style="margin-top:14px">Every plan comes in two variants. The <strong>Solana</strong> variant answers for Solana tokens only. The <strong>All-Chains</strong> variant answers the same endpoints on Ethereum, Base and Robinhood Chain as well — the endpoint list is identical, only the chains differ. See <a href="#chains">Chains</a>.</p>
700  </section>
701
702  <!-- OVERAGE CREDITS -->
703  <section id="overage-credits">
704    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><path d="M12 6v12M6 12h12"/></svg></span> Overage Credits</h2>
705    <p class="sub">Keep making requests after your daily limit — pay-per-use, no plan upgrade required.</p>
706
707    <p class="body-text">When your daily request limit is reached, the API normally returns <code>429 Too Many Requests</code>. With overage credits enabled, requests beyond your daily limit are automatically fulfilled using credits instead of being blocked. Each overage request costs <strong>1 credit ($0.02)</strong>.</p>
708
709    <h3>How It Works</h3>
710    <p class="body-text">1. <strong>Purchase a credit pack</strong> via the <a href="https://defade.org/dashboard">dashboard</a> (card or USDC) or the API. 2. <strong>Enable overage</strong> on your API key (opt-in via dashboard toggle). 3. When you hit your daily limit, requests automatically consume credits. 4. When credits run out, the standard <code>429</code> response resumes.</p>
711
712    <div class="ios-web-pay">
713    <h3>Credit Packs</h3>
714    <div style="overflow-x:auto;border:1px solid var(--border);border-radius:var(--radius-sm)">
715      <table class="field-table">
716        <thead><tr><th>
716Pack</th><th>Price</th><th>Credits</th><th>Cost / Request</th><th>Bonus</th></tr></thead>
717        <tbody>
718          <tr><td class="fname">Small</td><td>$5</td><td>250</td><td>$0.020</td><td>—</td></tr>
719          <tr><td class="fname">Medium</td><td>$20</td><td>1,050</td><td>~$0.019</td><td style="color:var(--accent);font-weight:600">+5%</td></tr>
720          <tr><td class="fname">Large</td><td>$50</td><td>2,750</td><td>~$0.018</td><td style="color:var(--accent);font-weight:600">+10%</td></tr>
721        </tbody>
722      </table>
723    </div>
724    </div>
725
726    <h3>Buy Credits via API</h3>
727    <div class="endpoint" style="margin-bottom:16px">
728      <div class="endpoint-header" style="cursor:default">
729        <span class="method-badge method-post">POST</span>
730        <span class="endpoint-path">/api/stripe/buy-credits</span>
731        <span class="tag tag-paid">No Auth Required</span>
732      </div>
733    </div>
734    <p class="body-text">Returns a Stripe checkout URL for one-time credit purchase. After payment, credits are added to your key automatically.</p>
735    <div style="overflow-x:auto;border:1px solid var(--border);border-radius:var(--radius-sm)">
736      <table class="param-table">
737        <thead><tr><th>Field</th><th>Type</th><th>Required</th><th>Description</th></tr></thead>
738        <tbody>
739          <tr><td class="param-name">pack</td><td class="param-type">string</td><td><span class="required">Required</span></td><td>Credit pack size: <code>"small"</code>, <code>"medium"</code>, or <code>"large"</code></td></tr>
740          <tr><td class="param-name">apiKey</td><td class="param-type">string</td><td><span class="required">Required</span></td><td>The API key to add credits to (your <code>df_...</code> key)</td></tr>
741        </tbody>
742      </table>
743    </div>
744
745    <h3>Response Headers</h3>
746    <p class="body-text">When a request uses an overage credit, two extra headers are included in the response:</p>
747    <div class="rl-grid">
748      <div class="rl-item">
749        <div class="rl-header-name">X-Credit-Used</div>
750        <div class="rl-desc">Set to <code>1</code> when a credit was consumed for this request.</div>
751      </div>
752      <div class="rl-item">
753        <div class="rl-header-name">X-Credit-Balance</div>
754        <div class="rl-desc">Your remaining credit balance after this request.</div>
755      </div>
756    </div>
757
758    <h3>429 Response with Credits Info</h3>
759    <p class="body-text">When your daily limit is hit and credits are unavailable or disabled, the <code>429</code> response includes a <code>credits</code> object:</p>
760    <div class="code-block-solo">
761<pre>{
762  <span class="key-c">"error"</span>: <span class="str">"Daily limit exceeded"</span>,
763  <span class="key-c">"limit"</span>: <span class="str">"1000/day"</span>,
764  <span class="key-c">"resetsAt"</span>: <span class="str">"midnight UTC"</span>,
765  <span class="key-c">"credits"</span>: {
766    <span class="key-c">"enabled"</span>: <span class="fn">false</span>,
767    <span class="key-c">"balance"</span>: <span class="fn">0</span>,
768    <span class="key-c">"costPerRequest"</span>: <span class="str">"$0.02"</span>,
769    <span class="key-c">"hint"</span>: <span class="str">"Enable overage credits in your dashboard..."</span>
770  }
771}</pre>
772    </div>
773
774    <div class="callout callout-info">
775      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--blue)" stroke-width="2"><circle cx="12" cy="12" r="10"/><line x1="12" y1="16" x2="12" y2="12"/><line x1="12" y1="8" x2="12.01" y2="8"/></svg>
776      <div><strong>Credits never expire.</strong> Once purchased, credits remain on your key until used. Your credit balance and overage status are visible in the <a href="https://defade.org/dashboard">dashboard</a> and via the <code>/v1/usage</code> endpoint.</div>
777    </div>
778  </section>
779
780  <!-- RATE LIMITS -->
781  <section id="rate-limits">
782    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></span> Rate Limits</h2>
783    <p class="sub">Rate limits are enforced per API key at both per-minute and daily granularity.</p>
784    <p class="body-text">
784When you exceed your per-minute rate limit, the API returns <code>429 Too Many Requests</code> with a <code>retryAfter</code> field (in seconds). When you exceed your daily limit, the request is blocked unless you have <a href="#overage-credits">overage credits</a> enabled — in which case each extra request consumes 1 credit ($0.02). Rate limit status is included in every response via headers:</p>
785
786    <div class="rl-grid">
787      <div class="rl-item">
788        <div class="rl-header-name">X-RateLimit-Limit</div>
789        <div class="rl-desc">Maximum requests allowed per minute for your tier.</div>
790      </div>
791      <div class="rl-item">
792        <div class="rl-header-name">X-RateLimit-Remaining</div>
793        <div class="rl-desc">Requests remaining in the current 60-second window.</div>
794      </div>
795    </div>
796
797    <h3>Limits by Plan</h3>
798    <div style="overflow-x:auto;border:1px solid var(--border);border-radius:var(--radius-sm)">
799      <table class="field-table">
800        <thead><tr><th>Plan</th><th>Per Minute</th><th>Per Day</th><th>Daily Reset</th></tr></thead>
801        <tbody>
802          <tr><td class="fname">Free</td><td>10</td><td>100</td><td>Midnight UTC</td></tr>
803          <tr><td class="fname">Starter</td><td>30</td><td>1,000</td><td>Midnight UTC</td></tr>
804          <tr><td class="fname">Pro</td><td>60</td><td>5,000</td><td>Midnight UTC</td></tr>
805          <tr><td class="fname">Enterprise</td><td>200</td><td>50,000</td><td>Midnight UTC</td></tr>
806        </tbody>
807      </table>
808    </div>
809
810    <div class="callout callout-tip">
811      <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="var(--accent)" stroke-width="2"><path d="M22 11.08V12a10 10 0 11-5.93-9.14"/><polyline points="22 4 12 14.01 9 11.01"/></svg>
812      <div><strong>Best practice:</strong> Cache results on your end. Token risk profiles don't change every second — caching for 60–300 seconds dramatically reduces your API usage without sacrificing freshness.</div>
813    </div>
814  </section>
815
816  <!-- ERRORS -->
817  <section id="errors">
818    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M10.29 3.86L1.82 18a2 2 0 001.71 3h16.94a2 2 0 001.71-3L13.71 3.86a2 2 0 00-3.42 0z"/><line x1="12" y1="9" x2="12" y2="13"/><line x1="12" y1="17" x2="12.01" y2="17"/></svg></span> Error Handling</h2>
819    <p class="sub">All errors return a consistent JSON structure with an <code style="color:var(--blue)">error</code> field and optionally a <code style="color:var(--blue)">message</code> with more detail.</p>
820
821    <h3>Error Response Format</h3>
822    <div class="code-block-solo">
823<pre>{
824  <span class="key-c">"error"</span>: <span class="str">"Rate limit exceeded"</span>,
825  <span class="key-c">"limit"</span>: <span class="str">"10/min"</span>,
826  <span class="key-c">"retryAfter"</span>: <span class="fn">23</span>
827}</pre>
828    </div>
829
830    <h3>HTTP Status Codes</h3>
831    <div style="overflow-x:auto;border:1px solid var(--border);border-radius:var(--radius)">
832      <table class="error-table">
833        <thead><tr><th>Status</th><th>Meaning</th><th>Common Cause</th></tr></thead>
834        <tbody>
835          <tr><td class="status-code" style="color:var(--accent)">200</td><td>Success</td><td>Request completed. Response body contains the data.</td></tr>
836          <tr><td class="status-code s4">400</td><td>Bad Request</td><td>Invalid mint address format or malformed request body.</td></tr>
837          <tr><td class="status-code s4">401</td><td>Unauthorized</td><td>Missing or invalid API key. Check the <code>x-api-key</code> header.</td></tr>
838          <tr><td class="status-code s4">403</td><td>Forbidden</td><td>Endpoint not available on your plan. Upgrade to access.</td></tr>
839          <tr><td class="status-code s4">404</td><td>Not Found</td><td>Token mint address not found on Solana or not yet indexed.</td></tr>
840          <tr><td class="status-code s4">429</td><td>Too Many Requests</td><td>Rate limit exceeded. Check <code>retryAfter</code> and back off.</td></tr>
841          <tr><td class="status-code s5">500</td><td>Internal Error</td><td>Server error. Retry after a moment. If persistent, contact support.</td></tr>
842          <tr><td class="status-code s5">503</td><td>Service Unavailable</td><td>Upstream RPC provider temporarily down. Automatic recovery.</td></tr>
843        </tbody>
844      </table>
845    </div>
846  </section>
847
848  <!-- SDKs -->
849  <section id="sdks">
850    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><rect x="2" y="3" width="20" height="14" rx="2" ry="2"/><line x1="8" y1="21" x2="16" y2="21"/><line x1="12" y1="17" x2="12" y2="21"/></svg></span> SDKs &amp; Integration</h2>
851    <p class="sub">The DeFade API is a standard REST API — it works with any HTTP client in any language.</p>
852
853    <h3>Official JavaScript SDK</h3>
854    <p class="body-text">Zero-dependency client for Node 18+, CJS and ESM, with TypeScript types — open source at <a href="https://github.com/DeFadeLtd/defade-sdk" target="_blank" rel="noopener">github.com/DeFadeLtd/defade-sdk</a>.</p>
855    <div class="code-block-solo" id="sdk-npm">
856      <button class="copy-btn" onclick="copyBlock(this,'sdk-npm')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
857<pre><span class="dim">npm</span> install defade   <span class="comment"># or: npm install github:DeFadeLtd/defade-sdk</span></pre>
858    </div>
859    <div class="code-block-solo" id="sdk-official">
860      <button class="copy-btn" onclick="copyBlock(this,'sdk-official')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
861<pre><span class="kw">
861import</span> DeFade <span class="kw">from</span> <span class="str">'defade'</span>;
862
863<span class="kw">const</span> client = <span class="kw">new</span> <span class="fn">DeFade</span>({ <span class="key-c">apiKey</span>: process.env.<span class="fn">DEFADE_API_KEY</span> });
864
865<span class="kw">const</span> scan = <span class="kw">await</span> client.<span class="fn">analyze</span>(<span class="str">'TOKEN_MINT'</span>);            <span class="comment">// safety score: 100 = clean</span>
866<span class="kw">const</span> risk = <span class="kw">await</span> client.<span class="fn">rugScore</span>(<span class="str">'TOKEN_MINT'</span>);           <span class="comment">// rug probability: 100 = dangerous</span>
867<span class="kw">const</span> eth  = <span class="kw">await</span> client.<span class="fn">holders</span>(<span class="str">'0x…'</span>, { <span class="key-c">chain</span>: <span class="str">'ethereum'</span> });</pre>
868    </div>
869
870    <h3>Plain JavaScript / Node.js</h3>
871    <div class="code-block-solo" id="sdk-js">
872      <button class="copy-btn" onclick="copyBlock(this,'sdk-js')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
873<pre><span class="comment">// Simple wrapper function</span>
874<span class="kw">const</span> DEFADE_KEY = process.env.<span class="fn">DEFADE_API_KEY</span>;
875
876<span class="kw">async function</span> <span class="fn">defade</span>(endpoint, mint = <span class="str">''</span>) {
877  <span class="kw">const</span> url = <span class="str">`https://api.defade.org/v1/${</span>endpoint<span class="str">}${</span>
877mint ? <span class="str">`/${</span>mint<span class="str">}`</span> : <span class="str">''</span><span class="str">}`</span>;
878  <span class="kw">const</span> res = <span class="kw">await</span> <span class="fn">fetch</span>(url, {
879    <span class="key-c">headers</span>: { <span class="str">'x-api-key'</span>: DEFADE_KEY }
880  });
881  <span class="kw">if</span> (!res.ok) <span class="kw">throw new</span> Error(<span class="str">`DeFade API ${</span>res.status<span class="str">}: ${</span>(<span class="kw">await</span> res.<span class="fn">json</span>()).error<span class="str">}`</span>);
882  <span class="kw">return</span> res.<span class="fn">json</span>();
883}
884
885<span class="comment">// Usage</span>
886<span class="kw">const</span> analysis = <span class="kw">await</span> <span class="fn">defade</span>(<span class="str">'analyze'</span>, <span class="str">'TOKEN_MINT'</span>);
887<span class="kw">const</span> trending = <span class="kw">await</span> <span class="fn">defade</span>(<span class="str">'trending'</span>);</pre>
888    </div>
889
890    <h3>Python</h3>
891    <div class="code-block-solo" id="sdk-py">
892      <button class="copy-btn" onclick="copyBlock(this,'sdk-py')"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg></button>
893<pre><span class="kw">import</span> os, requests
894
895DEFADE_KEY = os.environ[<span class="str">'DEFADE_API_KEY'</span>]
896BASE = <span class="str">'https://api.defade.org/v1'</span>
897
898<span class="kw">def</span> <span class="fn">defade</span>(endpoint, mint=<span class="str">''</span>):
899    url = <span class="str">f'{BASE}/{endpoint}'</span> + (<span class="str">f'/{mint}'</span> <span class="kw">if</span> mint <span class="kw">else</span> <span class="str">''</span>)
900    r = requests.<span class="fn">get</span>(url, headers={<span class="str">'x-api-key'</span>: DEFADE_KEY})
901    r.<span class="fn">raise_for_status</span>()
902    <span class="kw">return</span> r.<span class="fn">json</span>()
903
904<span class="comment"># Usage</span>
905analysis = <span class="fn">defade</span>(<span class="str">'analyze'</span>, <span class="str">'TOKEN_MINT'</span>)
906trending = <span class="fn">defade</span>(<span class="str">'trending'</span>)</pre>
907    </div>
908
909    <h3>Other Integrations</h3>
910    <p class="body-text">DeFade also offers a <a href="https://t.me/DeFadeAnalyzerBot" target="_blank">Telegram bot</a> (@DeFadeAnalyzerBot) for instant token checks, a <a href="https://defade.org" target="_blank">Chrome extension</a> that auto-detects tokens on DEX pages, and a community channel at <a href="https://t.me/DeFadeChat" target="_blank">t.me/DeFadeChat</a>.</p>
911  </section>
912
913  <!-- MCP CONNECTOR -->
914  <section id="mcp">
915    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M12 2a3 3 0 00-3 3v1a3 3 0 006 0V5a3 3 0 00-3-3z"/><path d="M12 9v4"/><path d="M5 22v-5a7 7 0 0114 0v5"/></svg></span> MCP Connector</h2>
916    <p class="sub">The same API, spoken as <a href="https://modelcontextprotocol.io" target="_blank" rel="noopener">Model Context Protocol</a>, so Claude, ChatGPT and any other MCP client can run DeFade scans directly in a conversation. One endpoint, no SDK, no separate key.</p>
917
918    <h3>Connect</h3>
919    <p class="body-text">Add a custom connector pointing at the URL below, with your API key in the query string. Connector UIs only take a URL, which is why the key goes there; <code>x-api-key</code> and <code>Authorization: Bearer</code> also work for clients that let you set headers.</p>
920    <div class="code-block-solo">
921<pre>https://api.defade.org/mcp?api_key=<span class="str">YOUR_KEY</span></pre>
922    </div>
923    <p class="body-text"><strong>Claude</strong> — Settings → Connectors → Add custom connector → paste the URL. <strong>ChatGPT</strong> — Settings → Connectors → Add → paste the URL. Both then list DeFade's tools and call them when a question needs one.</p>
924    <h3 id="mcp-keys">Getting a key</h3>
925    <p class="body-text">Two keys open the connector, and they are different products:</p>
926    <p class="body-text"><strong>An API-plan key</strong> (<code>df_…</code>). Buy Starter, Pro or Enterprise under <a href="#pricing">Pricing</a> or on <a href="https://defade.org/developers">defade.org/developers</a> (card or crypto, key delivered immediately), or <a href="https://defade.org/developers#keygen">request a free 7-day trial</a>. It works on the REST API and in the connector alike, metered in units against the plan. A trial key reaches only <code>get_token_scan</code>, <code>get_rug_score</code>, <code>get_holders</code>, <code>get_token_price</code> and <code>get_usage</code>, on any chain.</p>
927    <p class="body-text"><strong>The Pro connector key</strong> (<code>df_mcp_…</code>), included with a <a href="https://defade.org/pricing">DeFade Pro</a> web subscription. Issue it from the <a href="https://defade.org/dashboard">dashboard</a> under "Claude &amp; ChatGPT connector" and paste the URL it gives you. It reaches all fifteen tools on every chain, and every tool call spends a scan from the plan's monthly allowance — the same one the website uses, one scan per distinct token per UTC day however many tools you run on it — so <code>get_usage</code> reports scans, not units. It only works through the connector: a direct REST call answers <code>403 mcp_only</code>, and it stops working when the subscription lapses. It is not an API key, and it does not turn a Pro subscription into an API plan.</p>
928
929    <h3>Tools</h3>
930    <p class="body-text">Fifteen tools, one per module, each mapping to the <code>/v1</code> endpoint of the same name:</p>
931    <div class="code-block-solo">
932<pre>get_token_scan          get_rug_score           get_holders
933get_whales              get_liquidity           get_launch_bundles
934get_launch_snipers      get_wallet_links        get_smart_money
935get_dev_tracker         get_funding_sources     get_lookalike_cluster
935s
936get_fee_fingerprint     get_token_price         get_usage</pre>
937    </div>
938    <p class="body-text">Every tool takes an <code>address</code> and an optional <code>chain</code>, exactly like the REST route behind it; <code>get_token_price</code> also takes an optional <code>timeframe</code> (the route&#39;s <code>?type=</code>), so <code>1D</code> reaches back up to a year of daily candles. Nothing here writes, trades or spends — all fifteen are read-only.</p>
939
940    <h3>Billing and limits</h3>
941    <p class="body-text">A tool call <em>is</em> an API call: it runs through the same key, the same plan endpoint list, the same chain scope, the same unit quota and the same rate limits as a REST request, and shows up in your usage the same way. Connector traffic is tagged <code>mcp</code> on the usage dashboard so you can tell it apart from your own integrations. There is no separate MCP plan or price. With the Pro connector key the meter is the web plan's scan allowance instead (see <a href="#mcp-keys">Getting a key</a>).</p>
942
943    <h3>Two scores, opposite directions</h3>
944    <p class="body-text">Worth knowing before you read an assistant's answer: <code>get_token_scan</code> returns <code>risk.score</code>, a <strong>safety</strong> score where 100 is clean, while <code>get_rug_score</code> returns <code>rugScore</code>, a rug pull <strong>probability</strong> where high is dangerous. The connector states this in its handshake instructions and repeats it on every result, so a model should not confuse them — but if you are reading raw output, check which tool produced it.</p>
945
946    <h3>Calling it directly</h3>
947    <p class="body-text">It is plain JSON-RPC 2.0 over HTTP POST (stateless Streamable HTTP — no session header, no SSE stream), so you can drive it with curl:</p>
948    <div class="code-block-solo">
949<pre>curl -X POST <span class="str">"https://api.defade.org/mcp?api_key=YOUR_KEY"</span> \
950  -H <span class="str">"Content-Type: application/json"</span> \
951  -d <span class="str">'{"jsonrpc":"2.0","id":1,"method":"tools/list"}'</span>
952
953curl -X POST <span class="str">"https://api.defade.org/mcp?api_key=YOUR_KEY"</span> \
954  -H <span class="str">"Content-Type: application/json"</span> \
955  -d <span class="str">'{"jsonrpc":"2.0","id":2,"method":"tools/call",
956       "params":{"name":"get_token_scan",
957                 "arguments":{"address":"YOUR_MINT","chain":"solana"}}}'</span></pre>
958    </div>
959    <p class="body-text">A failed call comes back as a tool result with <code>isError</code> set and the API's own message inside it — wrong plan, bad address, allowance spent — rather than a bare protocol error, so the assistant can tell you what actually went wrong.</p>
960  </section>
961
962  <!-- CHANGELOG -->
963  <section id="changelog">
964    <h2><span class="icon"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><circle cx="12" cy="12" r="10"/><polyline points="12 6 12 12 16 14"/></svg></span> Changelog</h2>
965    <p class="sub">Changes to the shape of a response, and anything else that can break an integration written against an earlier version. Endpoints added, and fields added to an existing response, are safe to ignore — they are listed so you know what is new.</p>
966
967    <h3>2026-10-01 &middot; Changed &middot; <code>/v1/rug-score</code> answers within a time budget</h3>
968    <p class="body-text">The call used to run the full analysis first, then its Pro modules, and wait for the slowest of them &mdash; a median of 11&ndash;13 s and a 95th percentile at the 25 s ceiling. It now starts the launch modules alongside the analysis and answers after a budget, <strong>5 s by default</strong>: the free checks and every module that has landed are scored, and the rest is named in a new <code>pending</code> array while it keeps computing server-side. <code>complete</code> is <code>true</code> when nothing is pending, and <code>coverage</code> reads <code>partial</code> until then. Pass <code>?wait=full</code> to wait for every module as before (up to 25 s), or <code>?wait=&lt;seconds&gt;</code>
968 to choose your own budget. <strong>If your integration needs the complete score in one call, add <code>?wait=full</code>.</strong> The MCP tool always waits for the complete answer.</p>
969
970    <h3>2026-09-30 &middot; Added &middot; <code>/v1/wallet-reputation/:wallet</code> and <code>/v1/wallet-overlap</code></h3>
971    <p class="body-text"><code>/v1/wallet-reputation/:wallet</code> is the Wallet Lookup page on the API: one wallet's record across every token DeFade scanned &mdash; tokens flagged in, confirmed rugs, the role on each, a tier verdict &mdash; with a <code>labelGlossary</code> that says what each role means. It is about a wallet rather than a token, so its envelope carries <code>wallet</code> and <code>chain</code> in place of <code>token</code>. <code>/v1/wallet-overlap?mints=A,B(,C)</code> returns the wallets holding two or more of the given tokens. Nothing about existing endpoints changed.</p>
972
973    <h3>2026-09-07 &middot; <span style="color:var(--red)">Breaking</span> &middot; <code>/v1/trending?chain=</code> returns a named array on EVM chains too</h3>
974    <p class="body-text">The 2026-08-28 fix below landed on the Solana path only. On <code>ethereum</code>, <code>base</code> and <code>robinhood</code> the feed was still spread into the envelope, so the same endpoint answered two different shapes depending on <code>?chain=</code> &mdash; a named <code>trending</code> array on Solana, numeric keys everywhere else. The EVM response now carries the same <code>trending</code> array. <strong>If your integration reads numeric keys off an EVM trending call, change it to <code>res.trending</code>;</strong> the Solana path is unaffected, and an error still puts <code>error</code> at the top level rather than inside <code>trending</code>.</p>
975
976    <h3>2026-09-07 &middot; Added &middot; trial keys reach every chain</h3>
977    <p class="body-text">The free 7-day trial key was Solana-only. It now covers every chain the API covers &mdash; Solana, Ethereum, Base and Robinhood &mdash; on the same six endpoints, at the same <code>10 req/min</code>, <code>100 req/day</code> and <code>3,000 units/month</code>. An EVM call from a trial key costs one unit, the same as a Solana one. Paid plans were already all-chains and are unchanged.</p>
978
979    <h3>2026-08-28 &middot; Added &middot; MCP connector at <code>/mcp</code></h3>
980    <p class="body-text">The <code>/v1</code> surface is now also reachable over the Model Context Protocol, so Claude, ChatGPT and other MCP clients can run scans in-conversation. Fifteen read-only tools, metered against your existing key exactly like REST calls. Nothing about the REST API changed. See <a href="#mcp">MCP Connector</a>.</p>
981
982    <h3>2026-08-28 &middot; <span style="color:var(--red)">Breaking</span> &middot; <code>/v1/trending</code> returns a named array</h3>
983    <p class="body-text">The feed is answered as a JSON array, and the endpoint used to spread it into the response envelope. That scattered the tokens across numeric keys — <code>"0"</code>, <code>"1"</code>, <code>"2"</code> … — next to <code>timestamp</code> and <code>poweredBy</code>, so reading the list meant subtracting the envelope and collecting whatever was left. The tokens now arrive in a <code>trending</code> array.</p>
984    <div class="code-block-solo">
985<pre><span class="comment">// before</span>
986{ <span class="key-c">"timestamp"</span>: <span class="str">"…"</span>, <span class="key-c">"0"</span>: { <span class="key-c">"symbol"</span>: <span class="str">"EX"</span> }, <span class="key-c">"1"</span>: { <span class="key-c">"symbol"</span>: <span class="str">"FOO"</span> }, <span class="key-c">"poweredBy"</span>: <span class="str">"DeFade.org"</span> }
987
988<span class="comment">// after</span>
989{ <span class="key-c">"timestamp"</span>: <span class="str">"…"</span>, <span class="key-c">"trending"</span>: [ { <span class="key-c">"symbol"</span>: <span class="str">"EX"</span> }, { <span class="key-c">"symbol"</span>: <span class="str">"FOO"</span> } ], <span class="key-c">"poweredBy"</span>: <span class="str">"DeFade.org"</span> }</pre>
990    </div>
991    <p class="body-text"><strong>
991If you read numeric keys, you must change your code.</strong> Anywhere you filtered the envelope out and took the rest — <code>Object.entries(res).filter(([k]) =&gt; !isNaN(k))</code> or similar — becomes <code>res.trending</code>. An error response is unaffected: a failure still puts <code>error</code> at the top level rather than inside <code>trending</code>.</p>
992
993    <h3>2026-08-28 &middot; Added &middot; <code>/v1/dev-tracker</code> says where the dev wallet came from</h3>
994    <p class="body-text">Two new fields. <code>creatorSource</code> names the signal that identified the wallet, and <code>creatorInferred</code> is true when that signal does not identify a person — a launchpad stamps one authority across every token it mints, so an authority-derived address is a guess, not a dev. Treat an inferred wallet's position as unconfirmed. Existing fields are unchanged.</p>
995
996    <h3>2026-08-28 &middot; Fixed &middot; <code>/v1/dev-tracker</code> <code>lastActivity</code> is populated</h3>
997    <p class="body-text">It had always been null. It is now the unix timestamp of the dev's most recent move of the token, across every bucket the endpoint tracks, and null only when the wallet has never moved it.</p>
998
999    <h3>2026-08-28 &middot; Docs &middot; response schemas rewritten against the endpoints</h3>
1000    <p class="body-text">No API behaviour changed here, but the reference on this page did. Every response sample used to open with a <code>"mint"</code> key that no endpoint returns — responses carry <code>token</code>, <code>timestamp</code> and <code>poweredBy</code> — and several field lists named fields that do not exist (<code>/v1/analyze</code> listed <code>rugScore</code> and <code>riskLevel</code>; <code>/v1/holders</code> listed <code>top10Pct</code>; <code>/v1/whales</code>, <code>/v1/bundles</code> and <code>/v1/snipers</code> listed counts that live inside <code>summary</code>). Every entry has been rewritten against the response its endpoint actually sends. If you built against the old schemas and something never worked, this is why.</p>
1001
1002    <h3>Older changes</h3>
1003    <p class="body-text">This log starts on 2026-08-28. Earlier changes were not recorded. For anything before that, the endpoint reference above describes current behaviour.</p>
1004  </section>
1005
1006</div>
1007
1008<!-- FOOTER -->
1009<footer class="footer">
1010  <div>&copy; 2026 DeFade Ltd &middot; <a href="https://defade.org" target="_blank">defade.org</a></div>
1011  <div>Contact: <a href="mailto:[email protected]" target="_blank">[email protected]</a> &middot; <a href="https://x.com/DeFade_" target="_blank">@DeFade_</a> &middot; <a href="https://t.me/DeFadeChat" target="_blank">Telegram</a></div>
1012</footer>
1013
1014<script>
1015// ======== ENDPOINT DATA ========
1016const endpoints = [
1017  {
1018    method:'GET', path:'/v1/analyze/:mint', desc:'Full risk analysis', id:'analyze',
1019    tier:'free',
1020    detail:'Runs the full core analysis suite in a single call and returns a comprehensive risk report. This is the primary endpoint for most use cases — it combines rug score, liquidity, holders, bundles, insider network, and more into one response.',
1021    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1022    fields:[
1023      {n:'success',t:'boolean',d:'Whether the scan completed.'},
1024      {n:'token',t:'object',d:'Full token metadata \u2014 <code>name</code>, <code>symbol</code>, <code>mint</code>, <code>supply</code>, <code>decimals</code>, <code>creator</code>, <code>creatorSource</code>, <code>mintAuthority</code>, <code>freezeAuthority</code>, <code>dexPaid</code>, <code>marketCap</code>, <code>liquidity</code>, <code>priceUsd</code>, <code>priceChange</code>, <code>volume</code>, <code>volumeBot</code> and a <code>timeline</code>. Note this REPLACES the envelope\u0027s token string.'},
1025      {n:'holders',t:'object',d:'Same body as /v1/holders: <code>totalHolders</code>, <code>topHolders</code>, <code>concentration</code>, <code>protocolHoldings</code>, <code>lockedSupply</code>, <code>deferredUnlock</code>, <code>bundles</code>.'},
1026      {n:'creator',t:'object',d:'<code>address</code>, <code>walletAgeDays</code>, <code>solBalance</code>, <code>totalTransactions</code>, <code>tokenCreations</code>, <code>recentTokens</code>, <code>riskLevel</code>.'},
1027      {n:'risk',t:'object',d:'The legacy safety score: <code>score</code>, <code>rating</code>, <code>color</code>, <code>flags</code>. <strong>Its scale is INVERTED relative to rugScore</strong> \u2014 100 is safe here, 0 is critical. Ratings run PROBABLY SAFE / PROCEED WITH CAUTION / ELEVATED RISK / HIGH RISK / VERY HIGH RISK / LIKELY RUG. For the rug probability model call /v1/rug-score.'},
1028      {n:'scanCount',t:'number',d:'How many times this token was scanned in the last 24 hours, on every DeFade surface (web, app, extension, Telegram, API) by every user, including this scan.'},
1029      {n:'scanWindow',t:'string',d:'The window <code>scanCount</code> covers: <code>24h</code>.'},
1030      {n:'analyzedAt',t:'string',d:'ISO timestamp of the scan itself, distinct from the envelope timestamp.'},
1031    ],
1032    response:`{
1033  "timestamp": "2026-08-28T09:30:11.402Z",
1034  "success": true,
1035  "token": { "name": "Example", "symbol": "EX", "mint": "7xK...", "creator": "9qR...", "creatorSource": "mint_tx" },
1036  "holders": { "totalHolders": 412, "concentration": { "top5": 18.2, "top10": 26.9, "top20": 34.1 } },
1037  "creator": { "address": "9qR...", "walletAgeDays": 96, "tokenCreations": 3 },
1038  "risk": { "score": 42, "rating": "SOME RISK", "color": "orange", "flags": [] },
1039  "scanCount": 17,
1040  "scanWindow": "24h",
1041  "analyzedAt": "2026-08-28T09:30:11.284Z",
1042  "poweredBy": "DeFade.org"
1043}`
1044  },
1045  {
1046    method:'GET', path:'/v1/rug-score/:mint', desc:'Rug probability score', id:'rug-score',
1047    tier:'free',
1048    detail:'Returns just the rug score and risk level — a lightweight call when you only need the risk classification without the full analysis breakdown. <strong>Answers within a time budget</strong> (default 5 s): the free checks plus every Pro module that has landed by then are scored, and anything still computing is named in <code>pending</code> and keeps running server-side, so a second call — or one with <code>?wait=full</code> — returns the complete score.',
1049    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'},{name:'wait',type:'string',required:false,desc:'How long to wait for the Pro modules before answering: a number of seconds (0–25), or <code>full</code> to wait for every module (up to 25 s, the previous behaviour). Default 5.'}],
1050    fields:[
1051      {n:'rugScore',t:'number',d:'Rug probability, 0 (safe) to 100 (critical).'},
1052      {n:'verdict',t:'string',d:'The label for that score, in full: <code>PROBABLY SAFE</code> (&lt;25), <code>SOME RISK</code> (25+), <code>ELEVATED RISK</code> (45+), <code>HIGH RISK</code> (60+), <code>EXTREME RISK</code> (75+) \u2014 or a state that overrides the bands: <code>RUGGED / DEAD</code>, <code>ABANDONED / DEAD</code>, <code>NEVER BONDED</code>. <code>verdictColor</code> is the matching colour.'},
1053      {n:'scoreLabel',t:'string|null',d:'<code>"NEVER BONDED"</code> when DeFade\'s own pages print that state instead of the percentage (a coin still on its launchpad curve has no pool to pull). <code>rugScore</code> is still returned as a number. <code>null</code> otherwise.'},
1054      {n:'signals',t:'array',d:'Every contributing signal: what fired, its weight and its explanation. Signals marked pro-only are omitted on non-Pro keys.'},
1055      {n:'coverage',t:'string',d:'<code>full</code> when the Pro signal set contributed, <code>partial</code> while something is still in <code>pending</code>, <code>free</code> when only the free checks did \u2014 a partial or free score has seen less evidence.'},
1056      {n:'pending',t:'array',d:'Modules that were still computing when the call answered (<code>liquidity</code>, <code>snipers</code>, <code>insider-network</code>, <code>dev-tracker</code>). Empty when the score is complete. They keep running: call again, or pass <code>?wait=full</code>.'},
1057      {n:'complete',t:'boolean',d:'<code>true</code> when <code>pending</code> is empty.'},
1058      {n:'bundleSubScore',t:'number',d:'The bundle component of the score; <code>bundleEngine</code> names which bundle detector produced it.'},
1059      {n:'fusion',t:'object',d:'Cross-signal wallet correlation. On non-Pro keys <code>fusion.wallets</code> is empty and <code>fusion.walletsLocked</code> is true.'},
1060      {n:'proChecksLocked',t:'number',d:'How many Pro-only checks were withheld from this response.'},
1061    ],
1062    response:`{
1063  "token": "7xK...",
1064  "timestamp": "2026-08-28T09:30:11.402Z",
1065  "rugScore": 72,
1066  "verdict": "HIGH RISK",
1067  "verdictColor": "red",
1068  "signals": [ { "id": "dev_transferred", "weight": 18, "label": "Dev moved 20% of supply to a fresh wallet" } ],
1069  "bundleSubScore": 14,
1070  "bundleEngine": "v2",
1071  "coverage": "partial",
1072  "pending": [ "snipers" ],
1073  "complete": false,
1074  "proChecksLocked": 15,
1075  "fusion": { "available": true, "wallets": [], "walletsLocked": true },
1076  "poweredBy": "DeFade.org"
1077}`
1078  },
1079  {
1080    method:'GET', path:'/v1/token-price/:mint', desc:'Token price & market data', id:'token-price',
1081    tier:'free',
1082    detail:'Returns OHLCV candles, the latest price, the window&#39;s high and low and the percent change across it, all in USD. <code>?type=</code> picks the candle size, and with it how far back the window reaches: <code>15m</code> (default) covers about 2.5 days, <code>1H</code> about 10 days, <code>4H</code> about 40 days, <code>1D</code> up to a year — a token younger than the window returns candles from its first trade. Data sourced from DexScreener and on-chain DEX pools.',
1083    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'},{name:'type',type:'string',required:false,desc:'Candle size: <code>1m</code>, <code>5m</code>, <code>15m</code> (default), <code>30m</code>, <code>1H</code>, <code>4H</code> or <code>1D</code>. Any other value is rejected with 400.'}],
1084    fields:[
1085      {n:'candles',t:'array',d:'OHLCV candles, oldest first: <code>ts</code> (ms), <code>open</code>, <code>high</code>, <code>low</code>, <code>close</code>, <code>volume</code> and the matching <code>*Usd</code> values.'},
1086      {n:'current',t:'object',d:'Latest close, as <code>current.priceUsd</code>.'},
1087      {n:'priceChange',t:'number',d:'Percent change from the first candle to the last across the requested window. Null when it cannot be computed.'},
1088      {n:'high',t:'object',d:'Window high as <code>priceUsd</code> plus its <code>ts</code>. <code>low</code> is the same shape.'},
1089      {n:'totalCandles',t:'number',d:'Number of candles returned. A token with no chart data answers <code>candles: []</code> and <code>totalCandles: 0</code>.'},
1090    ],
1091    response:`{
1092  "token": "7xK...",
1093  "timestamp": "2026-08-28T09:30:11.402Z",
1094  "candles": [
1095    { "ts": 1756369200000, "open": 0.000071, "high": 0.000103, "low": 0.000068, "close": 0.000082, "volume": 25170 }
1096  ],
1097  "current": { "priceUsd": 0.000082 },
1098  "priceChange": 9.64,
1099  "high": { "priceUsd": 0.000103, "ts": 1756370100000 },
1100  "low": { "priceUsd": 0.000068, "ts": 1756369200000 },
1101  "totalCandles": 96,
1102  "poweredBy": "DeFade.org"
1103}`
1104  },
1105  {
1106    method:'GET', path:'/v1/holders/:mint', desc:'Holder distribution', id:'holders',
1107    tier:'free',
1108    detail:'Analyzes token holder distribution — top holder concentration, whale counts, and breakdown by wallet size. High concentration in top wallets is a common rug pull indicator.',
1109    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1110    fields:[
1111      {n:'totalHolders',t:'number',d:'Holder count. This is a fast estimate from the top accounts \u2014 not an exhaustive census.'},
1112      {n:'topHolders',t:'array',d:'Top 20 accounts: <code>rank</code>, <code>address</code> (the token account), <code>walletAddress</code> (its owner), <code>amount</code>, <code>percentage</code>, <code>solBalance</code>, plus <code>isProtocol</code> / <code>protocolLabel</code> / <code>protocolType</code> when the holder is a pool, locker, treasury or custodian rather than a person.'},
1113      {n:'concentration',t:'object',d:'<code>top5</code>, <code>top10</code>, <code>top20</code> as percentages of supply, counting REAL wallets only \u2014 pools, lockers and other protocol accounts are excluded.'},
1114      {n:'protocolHoldings',t:'object',d:'What was excluded: <code>count</code> and <code>totalPct</code>.'},
1115      {n:'lockedSupply',t:'object',d:'<code>pct</code> plus a <code>lockers</code> array naming each escrow.'},
1116      {n:'deferredUnlock',t:'object',d:'Supply locked now that unlocks back to the deployer later \u2014 <code>pct</code>, <code>unlockDate</code>, <code>cancelablePct</code>. Null when there is none. A scheduled overhang, not a burn.'},
1117      {n:'bundles',t:'object',d:'Bundle detection over the real wallets: <code>detected</code>, <code>bundlePct</code>, <code>groups</code>.'},
1118    ],
1119    response:`{
1120  "token": "7xK...",
1121  "timestamp": "2026-08-28T09:30:11.402Z",
1122  "totalHolders": 412,
1123  "topHolders": [
1124    { "rank": 1, "address": "CPd...", "walletAddress": "CPd...", "amount": 153040000, "percentage": "15.95", "isProtocol": true, "protocolLabel": "Pump.fun AMM", "protocolType": "amm" }
1125  ],
1126  "concentration": { "top5": 18.2, "top10": 26.9, "top20": 34.1 },
1127  "protocolHoldings": { "count": 2, "totalPct": 30.01 },
1128  "lockedSupply": { "pct": 0, "lockers": [] },
1129  "deferredUnlock": null,
1130  "bundles": { "detected": false, "bundlePct": "0.00", "groups": [] },
1131  "poweredBy": "DeFade.org"
1132}`
1133  },
1134  {
1135    method:'GET', path:'/v1/liquidity/:mint', desc:'Liquidity pool depth', id:'liquidity',
1136    tier:'starter',
1137    detail:'Returns liquidity pool details across Raydium, Orca, and other Solana DEXs. Shows whether liquidity is locked or burnt — unlocked liquidity is a major rug pull risk factor.',
1138    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1139    fields:[
1140      {n:'lpStatus',t:'string',d:'The headline verdict on the pool \u2014 e.g. BURNED, LOCKED, UNLOCKED, NO LP FOUND. <code>lpStatusColor</code> is the matching colour.'},
1141      {n:'lpBurnPct',t:'number',d:'Percent of LP tokens burned; <code>lpLockPct</code> is the percent locked. <code>lpBurned</code> and <code>lpLocked</code> are the booleans behind them.'},
1142      {n:'totalLiquidityUsd',t:'number',d:'Combined USD depth across pools. <code>pools</code> lists them individually and <code>poolCount</code> counts them.'},
1143      {n:'poolLocks',t:'array',d:'Per-pool lock detail. <code>lpLockable</code> says whether this pool type can be locked at all, and <code>lpNote</code> explains the verdict in words.'},
1144      {n:'dex',t:'string',d:'Which DEX holds the deepest pool. <code>lpMint</code> is the LP token mint, <code>pumpFunGraduated</code> whether it left the bonding curve.'},
1145      {n:'risk',t:'string',d:'Liquidity risk label, with <code>riskColor</code>. <code>rugCheckScore</code> is the external RugCheck figure where available, and <code>lpEvidence</code> carries the on-chain evidence behind the verdict.'},
1146    ],
1147    response:`{
1148  "token": "7xK...",
1149  "timestamp": "2026-08-28T09:30:11.402Z",
1150  "lpStatus": "BURNED",
1151  "lpStatusColor": "green",
1152  "lpBurned": true,
1153  "lpLocked": false,
1154  "lpBurnPct": 100,
1155  "lpLockPct": 0,
1156  "poolCount": 1,
1157  "totalLiquidityUsd": 48210,
1158  "pools": [ { "dex": "PumpSwap", "liquidityUsd": 48210, "pairAddress": "CPd..." } ],
1159  "dex": "PumpSwap",
1160  "pumpFunGraduated": true,
1161  "risk": "LOW",
1162  "riskColor": "green",
1163  "poweredBy": "DeFade.org"
1164}`
1165  },
1166  {
1167    method:'GET', path:'/v1/socials/:mint', desc:'Social links & metadata', id:'socials',
1168    tier:'starter',
1169    detail:'Returns the token\'s social media links, website, and verification status. Sourced from on-chain metadata and DexScreener.',
1170    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1171    fields:[
1172      {n:'twitter',t:'string',d:'Links found for the token, each null when absent: <code>twitter</code>, <code>telegram</code>, <code>website</code>, <code>discord</code>.'},
1173      {n:'description',t:'string',d:'Token description from its metadata, and <code>metadataUri</code> the URI it came from.'},
1174      {n:'pumpFunReplies',t:'number',d:'Reply count on the pump.fun page, where the token has one.'},
1175      {n:'linkCount',t:'number',d:'How many of the social links resolved.'},
1176      {n:'socialScore',t:'number',d:'Presence score built from those links, with <code>socialScoreColor</code>. It measures whether a project HAS socials, not whether they are real.'},
1177    ],
1178    response:`{
1179  "token": "7xK...",
1180  "timestamp": "2026-08-28T09:30:11.402Z",
1181  "twitter": "https://x.com/example",
1182  "telegram": null,
1183  "website": "https://example.xyz",
1184  "discord": null,
1185  "description": "the example token",
1186  "pumpFunReplies": 88,
1187  "metadataUri": "https://ipfs.io/ipfs/Qm...",
1188  "linkCount": 2,
1189  "socialScore": 60,
1190  "socialScoreColor": "yellow",
1191  "poweredBy": "DeFade.org"
1192}`
1193  },
1194  {
1195    method:'GET', path:'/v1/whales/:mint', desc:'Whale wallet tracking', id:'whales',
1196    tier:'starter',
1197    detail:'Identifies wallets holding significant supply (>1%) and tracks their positions. Useful for monitoring large holder activity that could impact price.',
1198    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1199    fields:[
1200      {n:'whales',t:'array',d:'Wallets holding a significant share, each with its address, balance, percentage of supply and any attribution label (notable wallet, dev-linked stash, CEX).'},
1201      {n:'protocolAccounts',t:'array',d:'Pools, lockers, treasuries and custodial accounts held OUT of the whale list, named, so a pool vault is never reported as a whale.'},
1202      {n:'summary',t:'object',d:'The counts and totals \u2014 how many whales and what share of supply they hold between them.'},
1203      {n:'terminalUsage',t:'object',d:'Which trading terminals the whale cohort trades through.'},
1204    ],
1205    response:`{
1206  "token": "7xK...",
1207  "timestamp": "2026-08-28T09:30:11.402Z",
1208  "whales": [
1209    { "address": "5yN...", "balance": 5200000, "pctSupply": 5.2, "label": null }
1210  ],
1211  "protocolAccounts": [
1212    { "address": "CPd...", "label": "Pump.fun AMM", "pctSupply": 15.95 }
1213  ],
1214  "summary": { "whaleCount": 8, "whaleHoldingPct": 28.4 },
1215  "terminalUsage": { "Photon": 3, "BullX": 2 },
1216  "poweredBy": "DeFade.org"
1217}`
1218  },
1219  {
1220    method:'GET', path:'/v1/bundles/:mint', desc:'Bundle & sniper detection', id:'bundles',
1221    tier:'starter',
1222    detail:'Detects coordinated buy transactions (bundles) where multiple wallets bought in the same block — a common manipulation technique used by developers to control supply while appearing decentralized.',
1223    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1224    fields:[
1225      {n:'bundles',t:'array',d:'Detected bundles. Each carries the wallets that bought together, what they spent and what share of supply they took.'},
1226      {n:'summary',t:'object',d:'The totals across those bundles \u2014 how many bundles, how many wallets, and the combined percentage of supply they hold.'},
1227    ],
1228    response:`{
1229  "token": "7xK...",
1230  "timestamp": "2026-08-28T09:30:11.402Z",
1231  "bundles": [
1232    { "wallets": ["3kM...", "8pQ..."], "totalSol": 12.5, "pctSupply": 4.1 }
1233  ],
1234  "summary": { "bundleCount": 3, "bundledWallets": 12, "bundledPct": 8.4 },
1235  "poweredBy": "DeFade.org"
1236}`
1237  },
1238  {
1239    method:'GET', path:'/v1/insider-network/:mint', desc:'Insider wallet mapping', id:'insider-network',
1240    tier:'starter',
1241    detail:'Maps wallet clusters that share funding sources or exhibit coordinated behavior — indicating insider control. Uses on-chain fund flow analysis to detect wallets linked to the deployer or early investors.',
1242    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1243    fields:[
1244      {n:'insiderCount',t:'number',d:'Wallets in the connected cohort, holding <code>insiderHoldingPct</code> of supply between them.'},
1245      {n:'connections',t:'array',d:'The links themselves \u2014 wallet-to-wallet transfers that tie the cohort together. <code>connectionsTotal</code> is the count before truncation.'},
1246      {n:'nodes',t:'array',d:'Graph nodes, and <code>clusters</code> the groups they fall into.'},
1247      {n:'totalTransfers',t:'number',d:'Transfers behind the graph, moving <code>transferredPct</code> of supply. <code>totalConnections</code> counts the distinct links.'},
1248      {n:'walletConnections',t:'object',d:'Per-wallet connection counts.'},
1249      {n:'locked',t:'boolean',d:'Non-Pro keys receive <code>{ locked: true, reason: &#34;pro_only&#34;, upgradeUrl, message }</code> INSTEAD of the fields above \u2014 check for it before reading the rest.'},
1250    ],
1251    response:`{
1252  "token": "7xK...",
1253  "timestamp": "2026-08-28T09:30:11.402Z",
1254  "insiderCount": 6,
1255  "insiderHoldingPct": 11.3,
1256  "totalConnections": 9,
1257  "totalTransfers": 14,
1258  "transferredPct": 6.8,
1259  "connections": [ { "from": "3kM...", "to": "8pQ...", "amount": 4100000 } ],
1260  "connectionsTotal": 9,
1261  "nodes": [ { "address": "3kM...", "pctSupply": 2.4 } ],
1262  "clusters": [ { "size": 4, "pctSupply": 8.1 } ],
1263  "poweredBy": "DeFade.org"
1264}`
1265  },
1266  {
1267    method:'GET', path:'/v1/smart-money/:mint', desc:'Smart money signals', id:'smart-money',
1268    tier:'starter',
1269    detail:'Tracks wallets with a proven profitable track record to see whether they\'re buying or selling a given token. A strong indicator of informed market sentiment.',
1270    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1271    fields:[
1272      {n:'wallets',t:'array',d:'The holders that were profiled, each classified as smart money, verified, experienced, active trader or retail, with its win rate.'},
1273      {n:'activeBuys',t:'array',d:'Other tokens the smart wallets are currently buying.'},
1274      {n:'summary',t:'object',d:'<code>analyzed</code>, <code>smartMoneyCount</code>, <code>verifiedCount</code>, <code>experiencedCount</code>, <code>activeTraderCount</code>, <code>retailCount</code>, <code>smartMoneyPct</code>, <code>retailPct</code>, <code>avgWinRate</code>, and a <code>signal</code> with its <code>signalColor</code>.'},
1275    ],
1276    response:`{
1277  "token": "7xK...",
1278  "timestamp": "2026-08-28T09:30:11.402Z",
1279  "wallets": [
1280    { "address": "5yN...", "tier": "smart_money", "winRate": 68 }
1281  ],
1282  "activeBuys": [ { "mint": "9cR...", "buyers": 3 } ],
1283  "summary": {
1284    "analyzed": 20, "smartMoneyCount": 3, "verifiedCount": 1, "experiencedCount": 4,
1285    "activeTraderCount": 6, "retailCount": 6, "smartMoneyPct": 15, "retailPct": 30,
1286    "avgWinRate": 41, "signal": "MIXED", "signalColor": "yellow"
1287  },
1288  "poweredBy": "DeFade.org"
1289}`
1290  },
1291  {
1292    method:'GET', path:'/v1/snipers/:mint', desc:'Sniper detection', id:'snipers',
1293    tier:'starter',
1294    detail:'Detects wallets that bought in the very first blocks after liquidity was added — often bots or insiders with advance knowledge of the token launch.',
1295    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1296    fields:[
1297      {n:'snipers',t:'array',d:'Wallets that bought inside the launch window, capped at 30 rows.'},
1298      {n:'totalEarlyBuyers',t:'number',d:'How many were found in total. <code>windowSeconds</code> is the launch window used and <code>firstTxTime</code> the launch itself.'},
1299      {n:'terminals',t:'object',d:'Which trading terminals the launch cohort came through; <code>activeTerminals</code> is who is trading it now.'},
1300      {n:'reachedGenesis',t:'boolean',d:'Whether the walk reached the true first transaction. When false, <code>partial</code> is true and the long tail of small snipers may be missing \u2014 do not treat the count as authoritative.'},
1301      {n:'migrationCrankersExcluded',t:'array',d:'Migration-crank MEV bots filtered out of the sniper set: infrastru
1301cture, not launch coordination. Named rather than silently dropped.'},
1302      {n:'stats',t:'object',d:'Cohort totals for the window.'},
1303    ],
1304    response:`{
1305  "token": "7xK...",
1306  "timestamp": "2026-08-28T09:30:11.402Z",
1307  "snipers": [ { "address": "8pQ...", "buyBlock": 1, "holdingPct": 1.8 } ],
1308  "terminals": { "Photon": 4, "BullX": 2 },
1309  "activeTerminals": { "Photon": 2 },
1310  "totalEarlyBuyers": 23,
1311  "firstTxTime": 1756368000,
1312  "windowSeconds": 120,
1313  "reachedGenesis": true,
1314  "partial": false,
1315  "migrationCrankersExcluded": [],
1316  "stats": { "sniperPct": 6.4 },
1317  "poweredBy": "DeFade.org"
1318}`
1319  },
1320  {
1321    method:'GET', path:'/v1/dev-tracker/:mint', desc:'Developer wallet history', id:'dev-tracker',
1322    tier:'starter',
1323    detail:'Follows the creator\'s own position in THIS token: what they were minted or bought, what they sold into the pool, and what left the wallet another way \u2014 transferred out, locked in an escrow, seeded as liquidity, or parked at a known treasury or custodian \u2014 with the transactions behind each bucket. Those routes are separated on purpose: seeding a pool and locking supply both empty a dev wallet without being an exit, and a park at a custodial entity cannot be sold at all. It does NOT cover the creator\'s other launches \u2014 for previous tokens and rug history, see Deployer Reputation.',
1324    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1325    fields:[
1326      {n:'status',t:'string',d:'One-line verdict. <code>STILL HOLDING</code>, <code>PARTIAL EXIT</code>, <code>FULLY EXITED</code>, <code>TRANSFERRED OUT</code>, <code>SOLD &amp; TRANSFERRED</code>, <code>HOLDING + TRANSFERRED</code>, <code>DISTRIBUTED</code>, <code>LOCKED</code>, <code>HOLDING + LOCKED</code>, <code>LOCKED + TRANSFERRED</code>, <code>TRANSFERRED + LOCKED</code>, <code>SEEDED LIQUIDITY</code>, <code>TRANSFERRED TO TREASURY</code>, <code>HOLDING + TREASURY</code>, <code>PARKED AT CUSTODIAN</code>, <code>HOLDING + CUSTODIAL PARK</code>, <code>BURNED</code>, <code>SEEDED LIQUIDITY + BURNED</code>, <code>SOLD &amp; BURNED</code>, <code>HOLDING + BURNED</code>, <code>INDEXING</code> (accounting incomplete, usually seconds after launch), <code>NOT TRACKED</code> (no balance and no transactions found), <code>NO TOKENS</code>, or <code>UNKNOWN CREATOR</code>.'},
1327      {n:'statusColor',t:'string',d:'How to render the status: <code>green</code>, <code>yellow</code>, <code>gray</code> or <code>red</code>. Note a dev selling out is <code>gray</code>, not red \u2014 it is the standard memecoin launch pattern, not a rug signal.'},
1328      {n:'creatorSource',t:'string',d:'How the dev wallet was identified: <code>creators_verified</code> / <code>creators</code> (signed creator metadata), <code>owner</code>, <code>mint_tx</code> (the mint-creation transaction), <code>launch_platform_payment</code> (a launch platform deployed the token and this wallet\u2019s on-chain payment launched it \u2014 see <code>launchPlatformCreator</code>) \u2014 or <code>authorities</code> / <code>mint_authority</code> / <code>freeze_authority</code>, which name whoever can edit the token rather than a person. <code>caller_supplied</code> means you named the wallet yourself. Null when no creator resolved.'},
1329      {n:'creatorInferred',t:'boolean',d:'True when creatorSource does not identify a person \u2014 a launchpad stamps one authority across every token it mints, so treat the wallet as unconfirmed. False for a signed creator, for a caller-supplied wallet, and when no source is recorded.'},
1330      {n:'walletBalance',t:'object|null',d:'The dev wallet\u2019s balance in the chain\u2019s own coin: <code>amount</code> (number) and <code>symbol</code> (<code>SOL</code>). <code>null</code> when the balance could not be read \u2014 never a zero.'},
1331      {n:'currentHolding',t:'number',d:'Tokens the dev holds now, in whole tokens. <code>currentHoldingPct</code> is the same figure as a percentage of supply; <code>currentHoldingDisplay</code> is the display-safe string, which reads <code>&#34;&lt; 0.01&#34;</code> for a dust balance rather than rounding it to zero.'},
1332      {n:'totalMinted',t:'number',d:'Tokens minted STRAIGHT to the dev \u2014 the genesis allocation. Deliberately not counted as a buy: it cost nothing. Percentage in <code>totalMintedPct</code>.'},
1333      {n:'totalBought',t:'number',d:'Tokens the dev acquired by buying. Percentage in <code>totalBoughtPct</code>.'},
1334      {n:'totalSold',t:'number',d:'Tokens sold through a DEX. Percentage in <code>totalSoldPct</code>.'},
1335      {n:'totalTransferred',t:'number',d:'Tokens sent wallet-to-wallet with no SOL coming back \u2014 the wallet-hopping bucket. Excludes locks, liquidity seeding, known treasuries and custodial parks, which get their own totals below.'},
1336      {n:'totalBurned',t:'number',d:'Tokens the dev destroyed with an SPL Token / Token-2022 <code>Burn</code> instruction, read from the instruction itself (the enhanced parser reports these as transfers with no counterparty). Out of circulation: never a transfer, never scored. Percentage in <code>totalBurnedPct</code>; <code>
1336burnCount</code> and <code>recentBurns</code> alongside.'},
1337      {n:'totalLocked',t:'number',d:'Tokens sent to a lock/vesting program (Streamflow, Jupiter Lock). Percentage in <code>totalLockedPct</code>; <code>lockDetails</code> carries up to 10 entries of <code>program</code>, <code>amount</code>, <code>unlockDate</code> and <code>unlocksToCreator</code> \u2014 a lock that pays back to the dev is a deferred overhang, not a burn.'},
1338      {n:'totalLiquidity',t:'number',d:'Tokens seeded into a pool (LP or pool creation). Percentage in <code>totalLiquidityPct</code>.'},
1339      {n:'liquidityLock',t:'object|null',d:'Raydium Burn &amp; Earn locks on this token\u2019s liquidity; <code>null</code> when there are none. <code>positions[]</code>: <code>kind</code> (<code>clmm</code> position or <code>cpmm</code> LP), <code>source</code> (<code>dev_seed</code>, <code>launchlab_migration</code> or <code>other</code>, with <code>lockedBy</code>), <code>lockSignature</code>, <code>lockedAt</code>, <code>feeKeyMint</code>, <code>feeKeyHolder</code> (who collects that liquidity\u2019s trading fees now), <code>feeKeyHolderIsDev</code>, <code>feeKeyHolderIsPlatform</code>, <code>feeKeyHolderReceivedFromDev</code>; CPMM locks add <code>pool</code>, <code>lpMint</code>, <code>quoteMint</code>, <code>lpLocked</code>, <code>poolLockedPct</code> and, for a dev seed, <code>lockedSharePct</code> of the LP the dev received. <code>positionsLocked</code> / <code>positionsSeeded</code> count the dev\u2019s own seeds. <code>launchPlatform</code> names the Raydium LaunchLab platform of a graduated token (<code>name</code>, <code>web</code>, <code>feeWallet</code>, <code>nftWallet</code>; the <code>*SharePct</code> LP split is the platform\u2019s <em>current</em> config and may differ from the one this token graduated under). <code>feeClaims</code>: <code>count</code>, <code>sol</code>, <code>tokens</code>, <code>other</code> (by quote mint), <code>byClaimant[]</code>, <code>recent[]</code>, with <code>countIsFloor</code> when only the latest <code>parsed</code> claims were read. Informational, not scored.'},
1340      {n:'launchPlatformCreator',t:'object|null',d:'Set when a launch platform\u2019s own wallet deployed the token (e.g. StonkFun, which mints, seeds and locks every token itself): <code>platform</code>, <code>platformWallet</code>, <code>resolved</code>. When resolved, the wallet reported here paid the platform for this launch: <code>paymentSignature</code>, <code>paidSol</code>, <code>paidAt</code>, <code>creationSignature</code>, and <code>evidence</code> tying the payment to this token (<code>dev_buy</code> \u2014 the platform delivered the dev buy to the payer; <code>fee_key</code> \u2014 the payer was given the creator fee key of its Burn &amp; Earn lock). When not resolved, the platform wallet is reported as the dev and <code>reason</code> says why the payer could not be proven. Read from chain only.'},
1341      {n:'launchPlatformWallets',t:'object',d:'Addresses on this response that a Raydium LaunchLab launch platform declares as its own wallets in its on-chain PlatformConfig, keyed by address: <code>name</code> (e.g. StonkFun), <code>roles</code> (<code>fee_wallet</code>, <code>nft_wallet</code> \u2014 the wallet that receives graduation LP fee keys) and up to five <code>platformConfigs</code>. Covers the dev wallet, fee-key holders, fee claimants and transfer / receive / buy counterparties. Empty object when none match. Informational, not scored.'},
1342      {n:'totalTreasury',t:'number',d:'Tokens sent to a known treasury wallet. <code>totalCustodial</code> is the same idea for a known custodial entity (the key sits with a custodian, so the parcel cannot be sold). Percentages in <code>totalTreasuryPct</code> and <code>totalCustodialPct</code>.'},
1343      {n:'transferRecipients',t:'number',d:'Distinct wallets that received a transfer. <code>topRecipientOfTransferredPct</code> is the largest single recipient\'s share OF THE TRANSFERRED amount, and <code>distributionShaped</code> is true when the transfers read as spreading the minted allocation rather than hopping a position.'},
1344      {n:'transferRecipientAnalysis',t:'array',d:'What the large recipients DID with the tokens. Each entry: <code>address</code>, <code>amountPct</code>, <code>stillHeldPct</code>, <code>verdict</code> (<code>parked</code>, <code>sold</code>, <code>forwarded</code>, <code>cex</code>, <code>cex_deposit</code>, <code>custodial_entity</code>), a human-readable <code>line</code>, plus <code>entityLabel</code>, <code>cexName</code>, <code>sweptTo</code>, <code>farmParcels</code> and <code>farmParking</code>. Informational \u2014 it never changes the status. <code>transferRecipientLabels</code> lists any attribution names (e.g. a known KOL).'},
1345      {n:'roundTripCount',t:'number',d:'Outbound transfers matched to an inbou
1345nd leg from the same counterparty at nearly the same amount \u2014 supply that went out and came straight back. Netted OUT of the buy and transfer buckets so it cannot inflate both sides. <code>totalRoundTrip</code> and <code>recentRoundTrips</code> carry the amounts and signatures.'},
1346      {n:'sellCount',t:'number',d:'Transaction counts per bucket, alongside <code>buyCount</code>, <code>mintCount</code>, <code>transferCount</code>, <code>lockCount</code>, <code>liquidityCount</code>, <code>treasuryCount</code>, <code>custodialCount</code> and <code>burnCount</code>.'},
1347      {n:'recentSells',t:'array',d:'The transactions behind each bucket, newest first, capped at 10 (5 for buys and mints): <code>amount</code>, the counterparty (<code>to</code> or <code>from</code>), <code>signature</code> and unix <code>timestamp</code>. Siblings: <code>recentBuys</code>, <code>recentMints</code>, <code>recentTransfers</code>, <code>recentLocks</code>, <code>recentLiquidity</code>, <code>recentTreasuryTransfers</code>, <code>recentCustodialTransfers</code>, <code>recentBurns</code> (no counterparty: a burn goes to nobody).'},
1348      {n:'holdingPercentage',t:'number',d:'Aliases kept for older integrations, duplicating the <code>*Pct</code> fields: <code>holdingPercentage</code>, <code>soldPercentage</code>, <code>transferredPercentage</code>, <code>treasuryPercentage</code>, <code>custodialPercentage</code>. Prefer the <code>*Pct</code> names.'},
1349      {n:'lastActivity',t:'number',d:'Unix seconds of the dev\u0027s most recent move of this token, across every bucket \u2014 sells, buys, mints, transfers, locks, liquidity, treasury and custodial parks, round trips included. Null when the wallet has never moved the token.'},
1350    ],
1351    response:`{
1352  "token": "7xK...",
1353  "timestamp": "2026-08-28T09:12:44.918Z",
1354  "status": "PARTIAL EXIT",
1355  "statusColor": "yellow",
1356  "creatorSource": "mint_tx",
1357  "creatorInferred": false,
1358  "currentHolding": 18400000,
1359  "currentHoldingPct": 1.84,
1360  "currentHoldingDisplay": "1.84",
1361  "totalMinted": 100000000,
1362  "totalMintedPct": 10,
1363  "totalBought": 0,
1364  "totalSold": 62000000,
1365  "totalSoldPct": 6.2,
1366  "totalTransferred": 19600000,
1367  "totalTransferredPct": 1.96,
1368  "totalLocked": 0,
1369  "totalLiquidity": 0,
1370  "totalTreasury": 0,
1371  "totalCustodial": 0,
1372  "totalBurned": 0,
1373  "sellCount": 7,
1374  "buyCount": 0,
1375  "mintCount": 1,
1376  "transferCount": 2,
1377  "burnCount": 0,
1378  "transferRecipients": 2,
1379  "topRecipientOfTransferredPct": 71.4,
1380  "distributionShaped": false,
1381  "transferRecipientLabels": [],
1382  "transferRecipientAnalysis": [
1383    {
1384      "address": "5yN...", "amountPct": 1.4, "stillHeldPct": 100,
1385      "verdict": "parked", "line": "recipient parked, never moved",
1386      "entityLabel": null, "cexName": null, "sweptTo": null,
1387      "farmParcels": 0, "farmParking": false
1388    }
1389  ],
1390  "roundTripCount": 0,
1391  "recentSells": [
1392    { "amount": 12000000, "to": "CPd...", "signature": "4vB...", "timestamp": 1756370000 }
1393  ],
1394  "recentTransfers": [
1395    { "amount": 14000000, "to": "5yN...", "toLabel": null, "signature": "2xQ...", "timestamp": 1756371200 }
1396  ],
1397  "lastActivity": 1756371200,
1398  "poweredBy": "DeFade.org"
1399}`
1400  },
1401  {
1402    method:'GET', path:'/v1/copy-traders/:mint', desc:'Copy-trading detection', id:'copy-traders',
1403    tier:'starter',
1404    detail:'Compares the token portfolios of the top holders and surfaces wallet pairs that hold many of the same other tokens, a signal of coordinated or copy-trading behaviour. Returns the pairs and an overlap percentage per pair.',
1405    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1406    fields:[
1407      {n:'copyGroups',t:'array',d:'Groups of wallets that repeatedly trade the same tokens in the same order \u2014 the follower pattern.'},
1408      {n:'summary',t:'object',d:'<code>totalCopiers</code> and the group totals. A token with fewer than 5 holders to profile answers with empty groups.'},
1409    ],
1410    response:`{
1411  "token": "7xK...",
1412  "timestamp": "2026-08-28T09:30:11.402Z",
1413  "copyGroups": [
1414    { "leader": "5yN...", "followers": ["3kM...", "8pQ..."], "tokensShared": 4 }
1415  ],
1416  "summary": { "totalCopiers": 7 },
1417  "poweredBy": "DeFade.org"
1418}`
1419  },
1420  {
1421    method:'GET', path:'/v1/funding-origin/:mint', desc:'Funding origin by 
1421KYC tier', id:'funding-origin',
1422    tier:'pro',
1423    detail:'Traces the top holders back to where their wallets were funded (centralized exchanges, swap services, bridges, mixers) and aggregates the supply by source and KYC tier. High unknown or mixer share is a coordination signal.',
1424    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1425    fields:[
1426      {n:'origins',t:'array',d:'Where holder supply was funded from, as <code>{ name, share }</code>, biggest first \u2014 the exchanges and services behind the wallets.'},
1427      {n:'tiers',t:'array',d:'The same supply grouped by tier of certainty, as <code>{ tier, share }</code>.'},
1428      {n:'coveragePct',t:'number',d:'Share of supply actually attributed to a funding origin. <code>dexPct</code> (bought on an AMM, origin erased) and <code>bridgedPct</code> are real states but NOT attribution, so they are excluded from coverage rather than inflating it.'},
1429      {n:'walletCount',t:'number',d:'Wallets resolved, with <code>resolvedCount</code> and <code>unknownCount</code>. <code>totalKnownSupply</code> and <code>unknownSupply</code> are the token amounts behind them.'},
1430      {n:'risk',t:'object',d:'Risk verdict with its label and severity.'},
1431      {n:'computedAt',t:'string',d:'When this was computed; <code>fromCache</code> says whether it was served from a stored result.'},
1432    ],
1433    response:`{
1434  "token": "7xK...",
1435  "timestamp": "2026-08-28T09:30:11.402Z",
1436  "origins": [ { "name": "Binance", "share": 22.4 }, { "name": "Coinbase", "share": 9.1 } ],
1437  "tiers": [ { "tier": "cex", "share": 31.5 }, { "tier": "dex_acquired", "share": 40.2 } ],
1438  "coveragePct": 31.5,
1439  "dexPct": 40.2,
1440  "bridgedPct": 0,
1441  "totalKnownSupply": 315000000,
1442  "unknownSupply": 284000000,
1443  "walletCount": 20,
1444  "resolvedCount": 12,
1445  "unknownCount": 8,
1446  "risk": { "label": "MIXED", "severity": 2 },
1447  "computedAt": "2026-08-28T09:20:00.000Z",
1448  "fromCache": false,
1449  "poweredBy": "DeFade.org"
1450}`
1451  },
1452  {
1453    method:'GET', path:'/v1/funding-graph/:mint', desc:'Cross-funding graph', id:'funding-graph',
1454    tier:'pro',
1455    detail:'Maps which top holders were funded by the same upstream wallet, drawing the SOL-funding relationships behind the buys. Distinct from the insider network (token transfers between holders), this is who paid for whom.',
1456    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1457    fields:[
1458      {n:'nodes',t:'array',d:'Wallets in the funding graph, each with its label and share of supply.'},
1459      {n:'edges',t:'array',d:'Funding relationships between them \u2014 who paid whom, and how much.'},
1460      {n:'hubs',t:'array',d:'Wallets that funded several holders: the shape that distinguishes one operator behind many wallets from unrelated buyers.'},
1461      {n:'stats',t:'object',d:'Graph totals \u2014 node and edge counts, and how much supply the graph covers.'},
1462      {n:'computedAt',t:'string',d:'When this was computed; <code>fromCache</code> says whether it was served from a stored result.'},
1463    ],
1464    response:`{
1465  "token": "7xK...",
1466  "timestamp": "2026-08-28T09:30:11.402Z",
1467  "nodes": [ { "address": "3kM...", "pctSupply": 2.4, "label": null } ],
1468  "edges": [ { "from": "9qR...", "to": "3kM...", "lamports": 200000000 } ],
1469  "hubs": [ { "address": "9qR...", "funded": 6 } ],
1470  "stats": { "nodeCount": 21, "edgeCount": 18, "coveredPct": 14.2 },
1471  "computedAt": "2026-08-28T09:20:00.000Z",
1472  "fromCache": false,
1473  "poweredBy": "DeFade.org"
1474}`
1475  },
1476  {
1477    method:'GET', path:'/v1/sybil-cluster/:mint', desc:'Sybil band clustering', id:'sybil-cluster',
1478    tier:'pro',
1479    detail:'Collapses the cross-funding relationships into bands of wallets that behave as a single actor, excluding shared CEX, mixer, and bridge sources, and reports the combined supply each band controls. Surfaces concentration that per-wallet checks miss.',
1480    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1481    fields:[
1482      {n:'bands',t:'array',d:'Wallet clusters banded by how strongly they look like one operator behind many addresses.'},
1483      {n:'stats',t:'object',d:'Totals across the bands \u2014 wallets clustered and the supply they hold.'},
1484      {n:'risk',t:'object',d:'Verdict for the token, with its label and severity.'},
1485      {n:'computedAt',t:'string',d:'When this was computed; <code>fromCache</code> says whether it was served from a stored result.'},
1486    ],
1487    response:`{
1488  "token": "7xK...",
1489  "timestamp": "2026-08-28T09:30:11.402Z",
1490  "bands": [ { "band": "likely", "wallets": 6, "pctSupply": 7.4 } ],
1491  "stats": { "clustered": 9, "pctSupply": 9.8 },
1492  "risk": { "label": "ELEVATED", "severity": 3 },
1493  "computedAt": "2026-08-28T09:20:00.000Z",
1494  "fromCache": false,
1495  "poweredBy": "DeFade.org"
1496}`
1497  },
1498  {
1499    method:'GET', path:'/v1/fee-fingerprint/:mint', desc:'Shared bot fee settings', id:'fee-fingerprint',
1500    tier:'pro', chain:'solana',
1501    detail:'Groups wallets whose transactions pin an identical compute-unit price (or Jito tip) \u2014 the settings an operator types into a trading bot, which ride along in every wallet that bot drives. This is a shared-CONFIGURATION link and nothing more: it carries no timing claim, is never counted as bundled supply, and two wallets can match days apart. Values most of the launch used are excluded as client defaults rather than reported; round values and groups confined to one short window are scored down, because the first is a number strangers pick independently and the second can be two bots in dynamic-fee mode hitting the same congestion. Computed by the bundle scan, so a token that has never had one answers <code>pending</code> rather than an empty result. Solana only.',
1502    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1503    fields:[
1504      {n:'groups',t:'array',d:'One entry per fee setting shared by two or more wallets, strongest first. Each carries its <code>wallets</code>, the <code>supplyPct</code> they bought, a <code>confidence</code> of 0\u2013100 and the <code>reasons</code> behind it.'},
1505      {n:'excluded',t:'array',d:'Fee values suppressed as client defaults \u2014 too common across the launch to link anyone \u2014 with the wallet count each covered.'},
1506      {n:'stats',t:'object',d:'Population accounting: wallets seen, how many carried a readable fee setting, how many were linked, and how many set no priority fee at all.'},
1507      {n:'pending',t:'boolean',d:'Present and <code>true</code> when no bundle scan has run for this token yet, with a <code>reason</code>. Means nothing has looked \u2014 not that nothing was found.'},
1508      {n:'computedAt',t:'string',d:'When this result was read.'},
1509    ],
1510    response:`{
1511  "token": "7xK...",
1512  "timestamp": "2026-08-28T09:30:11.402Z",
1513  "groups": [
1514    {
1515      "family": "cu_price",
1516      "value": "1487662",
1517      "walletCount": 3,
1518      "supplyPct": 1.6,
1519      "sides": ["buy", "sell"],
1520      "confidence": 80,
1521      "reasons": ["same compute-unit limit", "matches on buys and sells"]
1522    }
1523  ],
1524  "excluded": [ { "value": "100000", "walletCount": 16, "reason": "generic_default" } ],
1525  "stats": { "groupCount": 13, "linkedWalletCount": 9, "linkedSupplyPct": 3.4, "walletsNoFeeData": 40 },
1526  "computedAt": "2026-08-28T09:20:00.000Z",
1527  "poweredBy": "DeFade.org"
1528}`
1529  },
1530  {
1531    method:'GET', path:'/v1/bundles-pro/:mint', desc:'Bundle Detection', id:'bundles-pro',
1532    tier:'pro',
1533    detail:'Deep launch-window bundle analysis: Jito atomic bundles, multi-hop funding chains, fresh-wallet cluster
1533s, and identical-amount groups, with a disposition breakdown of whether each bundle sold, transferred, or still holds.',
1534    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1535    fields:[
1536      {n:'bundles',t:'array',d:'Bundles with the deep-scan detail: the wallets, what they spent, what they still hold, and how they were funded.'},
1537      {n:'hiddenBundleCount',t:'number',d:'Bundles the shallow v1 detector does not see \u2014 the reason this endpoint exists.'},
1538      {n:'summary',t:'object',d:'Totals across the detected bundles.'},
1539    ],
1540    response:`{
1541  "token": "7xK...",
1542  "timestamp": "2026-08-28T09:30:11.402Z",
1543  "bundles": [
1544    { "wallets": ["3kM...", "8pQ..."], "totalSol": 12.5, "pctSupply": 4.1, "stillHeldPct": 62 }
1545  ],
1546  "hiddenBundleCount": 2,
1547  "summary": { "bundleCount": 5, "bundledPct": 11.9 },
1548  "poweredBy": "DeFade.org"
1549}`
1550  },
1551  {
1552    method:'GET', path:'/v1/historical-bundles/:mint', desc:'Historical bundles', id:'historical-bundles',
1553    tier:'pro',
1554    detail:'Detects coordinated buys during post-launch volume spikes, not just the launch window. Finds days where volume spiked well above the rolling average and looks for bundled buying inside those windows.',
1555    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1556    fields:[
1557      {n:'spikes',t:'array',d:'Windows after launch where coordinated buying reappeared \u2014 the accumulation a launch-window-only scan misses.'},
1558      {n:'bundles',t:'array',d:'The bundles found inside those windows.'},
1559      {n:'summary',t:'object',d:'Totals across the spikes and bundles.'},
1560    ],
1561    response:`{
1562  "token": "7xK...",
1563  "timestamp": "2026-08-28T09:30:11.402Z",
1564  "spikes": [ { "startedAt": 1756380000, "windowSeconds": 300, "wallets": 7, "pctSupply": 3.2 } ],
1565  "bundles": [ { "wallets": ["3kM...", "8pQ..."], "totalSol": 8.1, "pctSupply": 2.0 } ],
1566  "summary": { "spikeCount": 2, "bundledPct": 5.2 },
1567  "poweredBy": "DeFade.org"
1568}`
1569  },
1570  {
1571    method:'GET', path:'/v1/kol/:mint', desc:'Notable holders', id:'kol',
1572    tier:'free',
1573    detail:'Checks the token\u2019s current holders against a database of notable Solana wallets (KOLs, X traders and labelled wallets), returning which of them hold the token and how much. A holder snapshot, informational only, it does not affect the risk score.',
1574    params:[{name:':mint',type:'string',required:true,desc:'Solana token mint address (base58)'}],
1575    fields:[
1576      {n:'kols',t:'array',d:'Notable wallets (KOLs, X traders and labelled wallets) holding or trading this token, each named from the tracked roster with its position.'},
1577      {n:'summary',t:'object',d:'How many were found and what share of supply they hold between them.'},
1578    ],
1579    response:`{
1580  "token": "7xK...",
1581  "timestamp": "2026-08-28T09:30:11.402Z",
1582  "kols": [ { "name": "Ansem", "address": "GV6...", "pctSupply": 1.2, "xUrl": "https://x.com/blknoiz06" } ],
1583  "summary": { "kolCount": 1, "kolHoldingPct": 1.2 },
1584  "poweredBy": "DeFade.org"
1585}`
1586  },
1587  {
1588    method:'GET', path:'/v1/holder-overlap', desc:'Holder overlap across tokens', id:'holder-overlap',
1589    tier:'pro',
1590    detail:'For 1 to 3 token mints, finds the top holders of each and maps which other tokens those holders share. Returns nodes and edges for a force-directed graph. Pass the mints as a comma-separated query parameter.',
1591    params:[{name:'mints',type:'string (query)',required:true,desc:'1 to 3 comma-separated mint addresses, e.g. ?mints=MINT_A,MINT_B'}],
1592    fields:[
1593      {n:'mints',t:'array',d:'The mints you asked about, echoed back. This endpoint takes 1\u20133 mints via <code>?mints=A,B,C</code>, so the envelope carries <code>mints</code> where every other endpoint carries <code>token</code>.'},
1594      {n:'nodes',t:'array',d:'Tokens the shared holders also hold.'},
1595      {n:'edges',t:'array',d:'How many holders each pair of tokens has in common.'},
1596      {n:'stats',t:'object',d:'<code>inputTokens</code>, <code>totalHolders</code>, <code>sharedTokensFound</code>, <code>sharedTokensShown</code>, <code>elapsedMs</code>.'},
1597      {n:'cached',t:'boolean',d:'Whether the result came from a stored computation.'},
1598    ],
1599    response:`{
1600  "mints": ["7xK...", "9cR..."],
1601  "timestamp": "2026-08-28T09:30:11.402Z",
1602  "nodes": [ { "mint": "DezX...", "symbol": "BONK", "sharedHolders": 6 } ],
1603  "edges": [ { "a": "7xK...", "b": "9cR...", "sharedHolders": 4 } ],
1604  "stats": { "inputTokens": 2, "totalHolders": 40, "sharedTokensFound": 31, "sharedTokensShown": 12, "elapsedMs": 2140 },
1605  "cached": false,
1606  "poweredBy": "DeFade.org"
1607}`
1608  },
1609  {
1610    method:'GET', path:'/v1/wallet-overlap', desc:'Wallets holding several tokens', id:'wallet-overlap',
1611    tier:'pro',
1612    detail:'For 2 to 3 token mints, finds the top holders of each and returns the wallets that hold two or more of them. A wallet counts on a token when it is a top holder there (rank given) or its portfolio carries the token at any size (rank null). Same graph payload as <code>holder-overlap</code>, with wallet nodes in place of shared-token nodes. Pass the mints as a comma-separated query parameter.',
1613    params:[{name:'mints',type:'string (query)',required:true,desc:'2 to 3 comma-separated mint addresses, e.g. ?mints=MINT_A,MINT_B'}],
1614    fields:[
1615      {n:'mints',t:'array',d:'The mints you asked about, echoed back. Like <code>holder-overlap</code>, the envelope carries <code>mints</code> where every other endpoint carries <code>token</code>.'},
1616      {n:'nodes',t:'array',d:'The input tokens (<code>type: input</code>) and the overlapping wallets (<code>type: wallet</code>), each wallet with <code>totalShared</code> (how many inputs it holds), a label where one is known, and <code>holdings</code> keyed by input mint with <code>rank</code> and <code>topHolder</code>.'},
1617      {n:'edges',t:'array',d:'One edge per wallet and input it holds; <code>weight</code> 3 where the wallet is a top holder, 1 where it merely holds the token.'},
1618      {n:'stats',t:'object',d:'<code>inputTokens</code>, <code>totalHolders</code>, <code>overlapWalletsFound</code>, <code>overlapWalletsShown</code>, <code>holdingAll</code>, <code>byCount</code>, <code>elapsedMs</code>.'},
1619      {n:'cached',t:'boolean',d:'Whether the result came from a stored computation.'},
1620    ],
1621    response:`{
1622  "mints": ["7xK...", "9cR..."],
1623  "timestamp": "2026-09-30T01:30:11.402Z",
1624  "nodes": [
1625    { "id": "7xK...", "type": "input", "symbol": "EX", "holderCount": 50, "position": 0 },
1626    { "id": "HxhW...", "type": "wallet", "symbol": "HxhW…4uEK", "name": "Ansem", "totalShared": 2,
1627      "holdings": { "7xK...": { "rank": 3, "topHolder": true }, "9cR...": { "rank": null, "topHolder": false } } }
1628  ],
1629  "edges": [ { "source": "HxhW...", "target": "7xK...", "weight": 3 }, { "source": "HxhW...", "target": "9cR...", "weight": 1 } ],
1630  "stats": { "inputTokens": 2, "totalHolders": 91, "overlapWalletsFound": 7, "overlapWalletsShown": 7, "holdingAll": 7, "byCount": { "2": 7 }, "elapsedMs": 2140 },
1631  "cached": false,
1632  "poweredBy": "DeFade.org"
1633}`
1634  },
1635  {
1636    method:'GET', path:'/v1/wallet-reputation/:wallet', desc:'Wallet reputation: cross-token rug history', id:'wallet-reputation',
1637    tier:'pro',
1638    detail:'Everything DeFade has recorded about ONE wallet across every token it scanned: the tokens it was flagged in, which of them later rugged, the role it played in each (bundle, insider, funding, sniper, fresh) and a tier verdict that mirrors the scoring engine’s own repeat-offender rule, so the endpoint never claims more than a scan does. Sightings are written as a side effect of scans, so a wallet no scan has flagged answers <code>UNKNOWN</code>: absence of evidence, not a clean bill of health. Read from the reputation ledger alone: no chain calls, one unit. The address is a wallet, not a mint; on an EVM chain pass <code>?chain=</code>, since a 0x wallet exists on every chain and each keeps its own record.',
1639    params:[{name:':wallet',type:'string',required:true,desc:'Wallet address: base58 on Solana, 0x on an EVM chain (with <code>?chain=</code>).'},{name:'chain',type:'string',required:false,desc:'<code>solana</code> (default) or an EVM chain id. The ledger is per chain.'}],
1640    fields:[
1641      {n:'wallet',t:'string',d:'The wallet you asked about, echoed back. The envelope carries <code>wallet</code> and <code>chain</code> where token endpoints carry <code>token</code>.'},
1642      {n:'tier',t:'string',d:'<code>REPEAT_OFFENDER</code>: an operator role (bundle, insider or funding) in at least one confirmed rug, or 3+ confirmed rugs in any role, under the ambient-breadth ceilings (a wallet flagged across 30+ tokens, or 10+ in a week, is infrastru
1642cture or a spraying bot, and its rug count is the platform death rate). <code>RUG_ASSOCIATED</code>: confirmed rugs, but not qualifying. <code>OBSERVED</code>: flagged by scans, no confirmed rug yet. <code>UNKNOWN</code>: never flagged by any scan.'},
1643      {n:'tokensSeen',t:'number',d:'Distinct tokens a scan flagged this wallet in, on this chain. <code>recentTokensSeen</code> is the same over the last 7 days.'},
1644      {n:'rugsSeen',t:'number',d:'Of those, the tokens whose price and liquidity later collapsed on-chain (the RUGGED / DEAD verdict). A high risk score alone never counts.'},
1645      {n:'operatorRugsSeen',t:'number',d:'Confirmed rugs where the wallet’s role there was bundle, insider or funding: a participant in the launch rather than a bystander who bought in.'},
1646      {n:'labels',t:'array',d:'Every role ever attached to the wallet, the union over all sightings.'},
1647      {n:'labelGlossary',t:'object',d:'One sentence per label present, from what the detector behind it measured: <code>bundle</code> bought in a same-slot launch cohort; <code>insider</code> a transfer or shared-funder link to another top holder from 48h before launch (not an allocation); <code>funding</code> shares a funding source with other flagged holders (it did not fund the token); <code>sniper</code> bought in the first 120 seconds; <code>fresh</code> under 7 days old.'},
1648      {n:'sightings',t:'array',d:'Per-token record, newest first with rugged tokens ranked first, capped at 50: <code>mint</code>, <code>symbol</code>, <code>name</code>, <code>labels</code> (the roles on that token), <code>maxRugScore</code>, <code>rugOutcome</code>, <code>ruggedAt</code>, <code>firstSeen</code>, <code>lastSeen</code>. The counts above cover the full history regardless of the cap.'},
1649      {n:'protocol',t:'object|null',d:'Set when the address is known protocol infrastructure (an AMM authority, router or vault) that appears in countless unrelated transactions; its rug count then tracks platform volume, not intent, and scoring excludes it.'},
1650      {n:'fromCache',t:'boolean',d:'Whether the record came from the short server cache (a few minutes: sightings accrue as scans land).'},
1651    ],
1652    response:`{
1653  "wallet": "HxhW...",
1654  "chain": "solana",
1655  "timestamp": "2026-09-30T09:30:11.402Z",
1656  "available": true,
1657  "tier": "REPEAT_OFFENDER",
1658  "tokensSeen": 6,
1659  "recentTokensSeen": 1,
1660  "rugsSeen": 4,
1661  "operatorRugsSeen": 2,
1662  "labels": [ "bundle", "insider", "sniper" ],
1663  "labelGlossary": { "bundle": "Bought in a launch bundle: one of a cohort of wallets that bought in the same or adjacent slots at launch ...", "insider": "Holder Network link: ...", "sniper": "Bought within the first 120 seconds of launch ..." },
1664  "firstSeen": "2026-07-02T14:03:51.000Z",
1665  "lastSeen": "2026-09-29T21:17:08.000Z",
1666  "sightings": [
1667    { "mint": "7xK...", "symbol": "EX", "name": "Example", "labels": [ "bundle", "sniper" ], "maxRugScore": 78,
1668      "rugOutcome": true, "ruggedAt": "2026-08-14T02:11:40.000Z", "firstSeen": "2026-08-13T22:40:05.000Z", "lastSeen": "2026-08-13T23:10:12.000Z" }
1669  ],
1670  "protocol": null,
1671  "computedAt": "2026-09-30T09:30:11.398Z",
1672  "fromCache": false,
1673  "poweredBy": "DeFade.org"
1674}`
1675  },
1676  {
1677    method:'GET', path:'/v1/trending', desc:'Trending tokens', id:'trending',
1678    tier:'free',
1679    detail:'The current Solana token feed, built from DexScreener boosts and search and filtered for real depth \u2014 stablecoins, wrapped and staked SOL are excluded. Cached for a few minutes, so it is near-real-time rather than live.',
1680    params:[{name:'category',type:'string',required:false,desc:'Which feed: trending (default), new, gainers, losers, traded, viewed'}],
1681    fields:[
1682      {n:'trending',t:'array',d:'The feed, best first. Each token carries its <code>symbol</code>, <code>mint</code>, <code>priceUsd</code> and <code>volume24h</code>. Empty when the upstream feed is unavailable rather than absent.'},
1683      {n:'timestamp',t:'string',d:'When the response was assembled.'},
1684    ],
1685    response:`{
1686  "timestamp": "2026-08-28T09:30:11.402Z",
1687  "trending": [
1688    { "symbol": "EX", "mint": "7xK...", "priceUsd": 0.000082, "volume24h": 412000 },
1689    { "symbol": "FOO", "mint": "9cR...", "priceUsd": 0.00131, "volume24h": 208000 }
1690  ],
1691  "poweredBy": "DeFade.org"
1692}`
1693  },
1694  {
1695    method:'GET', path:'/v1/usage', desc:'Your API usage stats & credit balance', id:'usage',
1696    tier:'starter',
1697    detail:'Returns your current API key\'s usage statistics — today\'s request count, total lifetime requests, plan limits, and overage credit balance.',
1698    params:[],
1699    fields:[
1700      {n:'tier',t:'string',d:'The tier this key is on.'},
1701      {n:'limits',t:'object',d:'<code>perMinute</code>, <code>perDay</code>, <code>perMonth</code>. <code>perMonth</code> is null on grandfathered keys, which have no monthly ceiling.'},
1702      {n:'usage',t:'object',d:'<code>today</code>, <code>total</code>, <code>thisPeriod</code>, <code>remainingThisPeriod</code>, <code>periodResetsAt</code>. The period figures are null wherever <code>limits.perMonth</code> is.'},
1703      {n:'units',t:'object',d:'How metering works: one request is one unit, except the heaviest EVM modules. <code>heavyOnEvm</code> lists them and <code>heavyCost</code> gives their unit cost.'},
1704      {n:'credits',t:'object',d:'Overage: <code>balance</code>, <code>overageEnabled</code>, <code>costPerRequest</code>.'},
1705    ],
1706    response:`{
1707  "tier": "starter",
1708  "limits": { "perMinute": 30, "perDay": 1000, "perMonth": 5000 },
1709  "usage": {
1710    "today": 214, "total": 18402, "thisPeriod": 3120,
1711    "remainingThisPeriod": 1880, "periodResetsAt": "2026-09-12T00:00:00.000Z"
1712  },
1713  "units": { "note": "Requests are metered in units. One request costs 1 unit, except the heaviest EVM modules which cost 5.", "heavyOnEvm": ["funding-origin"], "heavyCost": 5 },
1714  "credits": { "balance": 0, "overageEnabled": false, "costPerRequest": 0.02 }
1715}`
1716  },
1717];
1718
1719// ======== HELPERS (must be defined before render) ========
1720function syntaxHighlight(json) {
1721  return json
1722    .replace(/"([^"]+)":/g, '<span class="key-r">"$1"</span>:')
1723    .replace(/: "([^"]*)"/g, ': <span class="val-s">"$1"</span>')
1724    .replace(/: (\d+\.?\d*)/g, ': <span class="val-n">$1</span>')
1725    .replace(/: (true|false)/g, ': <span class="val-b">$1</span>');
1726}
1727
1728// ======== RENDER ENDPOINTS ========
1729const list = document.getElementById('endpoint-list');
1730
1731// Build all HTML in one pass, then set innerHTML once — avoids the
1732// innerHTML += bug that strips onclick handlers from previously rendered nodes
1733const allHtml = endpoints.map((ep, i) => {
1734  const pathHtml = ep.path.replace(/:(\w+)/g, '<span class="param">:$1</span>');
1735  // Since 2026-08-09 every paid plan reaches every endpoint — plans differ on
1736  // volume, rate limit and chains, not on which routes they can call — so the
1737  // per-endpoint plan badge names no distinction and reads the same on all 25.
1738  // ep.tier is kept on the data so the matrix can be reinstated if that changes.
1739  const tierTag = '<span class="tag tag-starter">Every plan</span>';
1740  // Chain availability. Everything runs on Solana; SOLANA_ONLY is the one
1741  // endpoint with no EVM route of its own — EVM bundle analysis is a single
1742  // deep module that ships as bundles-pro (see the Chains section).
1743  const SOLANA_ONLY = ['bundles'];
1744  const CHAIN_AGNOSTIC = ['usage']; // reports on the key, not on a token
1745  const chainTag = CHAIN_AGNOSTIC.includes(ep.id)
1746    ? ''
1747    : SOLANA_ONLY.includes(ep.id)
1748      ? '<span class="tag tag-chain">Solana only</span>'
1749      : '<span class="tag tag-chain">All chains</span>';
1750
1751  const paramsHtml = ep.params.length ? `
1752    <div class="detail-section">
1753      <div class="detail-label">Parameters</div>
1754      <div style="overflow-x:auto">
1755      <table class="param-table">
1756        <thead><tr><th>Name</th><th>Type</th><th>Required</th><th>Description</th></tr></thead>
1757        <tbody>${ep.params.map(p => `
1758          <tr>
1759            <td class="param-name">${p.name}</td>
1760            <td class="param-type">${p.type}</td>
1761            <td>${p.required ? '<span class="required">Required</span>' : 'Optional'}</td>
1762            <td>${p.desc}</td>
1763          </tr>`).join('')}
1764        </tbody>
1765      </table>
1766      </div>
1767    </div>` : '';
1768
1769  const fieldsHtml = ep.fields ? `
1770    <div class="detail-section">
1771      <div class="detail-label">Response Fields</div>
1772      <div style="overflow-x:auto">
1773      <table class="field-table">
1774        <thead><tr><th>Field</th><th>Type</th><th>Description</th></tr></thead>
1775        <tbody>${ep.fields.map(f => `
1776          <tr>
1777            <td class="fname">${f.n}</td>
1778            <td class="ftype">${f.t}</td>
1779            <td>${f.d}</td>
1780          </tr>`).join('')}
1781        </tbody>
1782      </table>
1783      </div>
1784    </div>` : '';
1785
1786  const responseHtml = ep.response ? `
1787    <div class="detail-section">
1788      <div class="detail-label">Example Response</div>
1789      <div class="response-example">${syntaxHighlight(ep.response)}</div>
1790    </div>` : '';
1791
1792  return `
1793    <div class="endpoint" id="ep-${ep.id || i}">
1794      <div class="endpoint-header" data-toggle="ep-${ep.id || i}">
1795        <span class="method-badge method-get">${ep.method}</span>
1796        <span class="endpoint-path">${pathHtml}</span>
1797        ${tierTag}
1798        ${chainTag}
1799        <span class="endpoint-desc">${ep.desc}</span>
1800        <span class="endpoint-chevron">▼</span>
1801      </div>
1802      <div class="endpoint-detail">
1803        <div class="detail-desc">${ep.detail || ''}</div>
1804        ${paramsHtml}
1805        ${fieldsHtml}
1806        ${responseHtml}
1807      </div>
1808    </div>`;
1809}).join('');
1810
1811list.innerHTML = allHtml;
1812
1813// ======== SIDEBAR ENDPOINT LINKS ========
1814// The sidebar named four endpoints as #analyze, #rug-score, #token-price and
1815// #holders, but the cards render as #ep-analyze and so on, so all four were
1816// dead: clicking them did nothing. Alongside them "+ 9 more endpoints" pointed
1817// at #more-endpoints, which has never existed, and said 9 when the list had
1818// grown to 22. Both counts below are derived rather than typed, so neither can
1819// go stale again.
1820const namedEndpointLinks = [...document.querySelectorAll('.sidebar-link[href^="#ep-"]')];
1821const moreLink = document.getElementById('more-endpoints-link');
1822if (moreLink) {
1823  const namedIds = new Set(namedEndpointLinks.map(a => a.getAttribute('href').slice(4)));
1824  const remaining = endpoints.filter(ep => !namedIds.has(ep.id));
1825  moreLink.textContent = `+ ${remaining.length} more endpoints`;
1826  // Land on the first endpoint the sidebar does NOT name — that is what the
1827  // label promises. Falls back to the section when every one is listed.
1828  if (remaining.length > 0) moreLink.setAttribute('href', `#ep-${remaining[0].id}`);
1829}
1830
1831// A sidebar link to an endpoint should OPEN it, not drop the reader on a
1832// collapsed header — landing on a closed accordion is barely better than the
1833// dead link this replaces. Also runs on load, so a shared #ep-… URL opens the
1834// card it points at.
1835function openEndpointFromHash(hash) {
1836  if (!hash || hash.indexOf('#ep-') !== 0) return;
1837  const el = document.getElementById(hash.slice(1));
1838  if (el) el.classList.add('open');
1839}
1840window.addEventListener('hashchange', () => openEndpointFromHash(location.hash));
1841openEndpointFromHash(location.hash);
1842
1843// ======== INTERACTIONS ========
1844// Use event delegation — one listener on the parent, works for all endpoints
1845list.addEventListener('click', (e) => {
1846  const header = e.target.closest('[data-toggle]');
1847  if (!header) return;
1848  const id = header.getAttribute('data-toggle');
1849  const el = document.getElementById(id);
1850  if (el) el.classList.toggle('open');
1851});
1852
1853// Keep toggleEndpoint for any legacy direct calls
1854function toggleEndpoint(id) {
1855  const el = document.getElementById(id);
1856  if (el) el.classList.toggle('open');
1857}
1858
1859function switchTab(groupId, activeId, el) {
1860  const tabs = document.querySelectorAll(`#${groupId} .code-tab`);
1861  const blocks = document.querySelectorAll(`.code-block[data-group="${groupId}"]`);
1862  tabs.forEach(t => t.classList.remove('active'));
1863  blocks.forEach(b => b.classList.remove('active'));
1864  document.getElementById(activeId).classList.add('active');
1865  el.classList.add('active');
1866}
1867
1868function copyBlock(btn, blockId) {
1869  const block = document.getElementById(blockId);
1870  const pre = block.querySelector('pre');
1871  const text = pre ? pre.textContent : block.textContent;
1872  navigator.clipboard.writeText(text.trim()).then(() => {
1873    btn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="20 6 9 17 4 12"/></svg>';
1874    btn.classList.add('copied');
1875    setTimeout(() => { btn.innerHTML = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><rect x="9" y="9" width="13" height="13" rx="2" ry="2"/><path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"/></svg>'; btn.classList.remove('copied'); }, 2000);
1876  });
1877}
1878
1879// Sidebar active state
1880const sidebarLinks = document.querySelectorAll('.sidebar-link');
1881const sections = document.querySelectorAll('section[id]');
1882function updateActive() {
1883  let current = '';
1884  sections.forEach(s => {
1885    if (window.scrollY >= s.offsetTop - 100) current = s.id;
1886  });
1887  sidebarLinks.forEach(l => {
1888    l.classList.toggle('active', l.getAttribute('href') === '#' + current);
1889  });
1890}
1891window.addEventListener('scroll', updateActive);
1892updateActive();
1893
1894// Mobile: close sidebar when clicking a link
1895sidebarLinks.forEach(link => {
1896  link.addEventListener('click', () => {
1897    openEndpointFromHash(link.getAttribute('href'));
1898    const sidebar = document.getElementById('sidebar');
1899    const overlay = document.getElementById('sidebar-overlay');
1900    if (window.innerWidth <= 900) {
1901      sidebar.classList.remove('open');
1902      if (overlay) overlay.classList.remove('open');
1903    }
1904  });
1905});
1906</script>
1906
1907  
1907<script src="/js/auth.js" defer></script>
vendor: 1 bytes, line 1907
1907
1908<script>
1909// EVM beta pricing reveal — same gate as the site. Public gets
1910// enabled:false and this page renders exactly as before.
1911(function(){
1912  var API_ORIGIN = (window.location.hostname === 'localhost') ? '' : 'https://api.defade.org';
1913  // Price + crypto-product matrix, scope x period. These strings must track
1914  // STRIPE_PRICES in server.js and CRYPTO_PRODUCTS in routes/crypto-pay.js —
1915  // the same three numbers live in developers.html too, which is why the two
1916  // pages are worth diffing whenever pricing moves.
1917  var DOCS_PRICES = {
1918    // Solana-only plans retired 2026-08-22 — all-chains is the only family.
1919    all: {
1920      suffix: '_all',
1921      monthly: { lite: '$29',  starter: '$99',  growth: '$199',   pro: '$399',   ent: '$1,999', per: '/mo' },
1922      yearly:  { lite: '$278', starter: '$950', growth: '$1,910', pro: '$3,830', ent: '$19,190', per: '/yr' },
1923      crypto: {
1924        monthly: { lite: 'api_lite_all_monthly', starter: 'api_starter_all_monthly', growth: 'api_growth_all_monthly', pro: 'api_pro_all_monthly', ent: 'api_enterprise_all_monthly' },
1925        yearly:  { lite: 'api_lite_all_yearly',  starter: 'api_starter_all_yearly',  growth: 'api_growth_all_yearly',  pro: 'api_pro_all_yearly',  ent: 'api_enterprise_all_yearly' }
1926      }
1927    }
1928  };
1929  var docsScope = 'all'; // all-chains only since 2026-08-22
1930  var docsPeriod = 'monthly';
1931
1932  // DOCS_PRICES above is the offline fallback only. The live numbers come from
1933  // GET /api/pricing, derived from the same API_TIERS / STRIPE_PRICES the
1934  // checkout charges against — this page holding its own copy is why it was
1935  // still quoting $29/$99/$499 the day after the 2026-08-09 reprice.
1936  (function loadLiveDocsPricing(){
1937    var usd = function(n){ return '$' + Number(n).toLocaleString('en-US'); };
1938    var KEY = { lite: 'lite', starter: 'starter', growth: 'growth', pro: 'pro', enterprise: 'ent' };
1939    fetch(API_ORIGIN + '/api/pricing')
1940      .then(function(r){ return r.ok ? r.json() : null; })
1941      .then(function(data){
1942        if (!data || !Array.isArray(data.plans) || !data.plans.length) return;
1943        var next = {
1944          solana: { suffix: '',     monthly: { per: '/mo' }, yearly: { per: '/yr' }, crypto: { monthly: {}, yearly: {} } },
1945          all:    { suffix: '_all', monthly: { per: '/mo' }, yearly: { per: '/yr' }, crypto: { monthly: {}, yearly: {} } },
1946        };
1947        data.plans.forEach(function(p){
1948          var scope = p.chainScope === 'all' ? 'all' : 'solana';
1949          var k = KEY[p.tier.replace(/_all$/, '')];
1950          if (!k) return;
1951          next[scope].monthly[k] = usd(p.monthly);
1952          next[scope].yearly[k]  = usd(p.yearly);
1953          next[scope].crypto.monthly[k] = p.crypto.monthly;
1954          next[scope].crypto.yearly[k]  = p.crypto.yearly;
1955        });
1956        // Only adopt a complete payload; a partial one would blank a card.
1957        // Only the 'all' scope is sold since 2026-08-22.
1958        var complete = ['lite','starter','growth','pro','ent'].every(function(k){ return next.all.monthly[k] && next.all.crypto.monthly[k]; });
1959        if (!complete) return;
1960        DOCS_PRICES = next;
1961        renderDocsPrices();
1962      })
1963      .catch(function(){ /* offline — the fallback is already rendered */ });
1964  })();
1965
1966  function renderDocsPrices(){
1967    var p = DOCS_PRICES[docsScope];
1968    var amounts = p[docsPeriod];
1969    var cryptoIds = p.crypto[docsPeriod];
1970    [['docsLiteAmt','docsLiteCrypto','lite'],
1971     ['docsStarterAmt','docsStarterCrypto','starter'],
1972     ['docsGrowthAmt','docsGrowthCrypto','growth'],
1973     ['docsProAmt','docsProCrypto','pro'],
1974     ['docsEntAmt','docsEntCrypto','ent']].forEach(function(r){
1975      var amt = document.getElementById(r[0]);
1976      var crypto = document.getElementById(r[1]);
1977      if (amt) amt.innerHTML = amounts[r[2]] + ' <span>' + amounts.per + '</span>';
1978      if (crypto) crypto.href = '/crypto-checkout?product=' + cryptoIds[r[2]];
1979    });
1980  }
1981  function paintToggle(sel, attr, value){
1982    document.querySelectorAll(sel).forEach(function(b){
1983      var active = b.dataset[attr] === value;
1984      b.style.background = active ? 'var(--accent)' : 'transparent';
1985      b.style.color = active ? 'var(--bg-primary)' : 'var(--text-primary)';
1986    });
1987  }
1988  window.setDocsScope = function(scope){
1989    docsScope = (scope === 'all') ? 'all' : 'solana';
1990    paintToggle('#docsChainScope button', 'scope', docsScope);
1991    renderDocsPrices();
1992  };
1993  window.setDocsBilling = function(period){
1994    docsPeriod = (period === 'yearly') ? 'yearly' : 'monthly';
1995    paintToggle('#docsBilling button', 'period', docsPeriod);
1996    renderDocsPrices();
1997  };
1998  // Card checkout, same endpoint and payload the developers page posts. The
1999  // server resolves the price from the tier name, so the _all suffix is the
2000  // only thing that has to be right here.
2001  window.docsSubscribe = async function(tier, btn){
2002    var label = btn ? btn.textContent : '';
2003    if (btn) { btn.textContent = 'Redirecting…'; btn.disabled = true; }
2004    // Mode 'change_plan' = this account already pays for an API plan by
2005    // card; the same key moves to this plan after a confirm.
2006    var post = function(confirmPlanChange){
2007      return fetch(API_ORIGIN + '/api/stripe/checkout', {
2008        method: 'POST',
2009        credentials: 'include',
2010        headers: { 'Content-Type': 'application/json' },
2011        body: JSON.stringify({
2012          tier: (tier === 'ent' ? 'enterprise' : tier) + DOCS_PRICES[docsScope].suffix,
2013          period: docsPeriod,
2014          label: 'api-docs-subscribe',
2015          confirmPlanChange: confirmPlanChange
2016        })
2017      }).then(function(r){ return r.json(); });
2018    };
2019    try {
2020      var data = await post(false);
2021      if (data.mode === 'change_plan') {
2022        if (!window.confirm(data.confirmMessage)) {
2023          if (btn) { btn.textContent = label; btn.disabled = false; }
2024          return;
2025        }
2026        if (btn) btn.textContent = 'Changing plan…';
2027        data = await post(true);
2028        if (data.ok) { alert(data.message); window.location.href = '/dashboard'; return; }
2029        // 3-D Secure: Stripe's page takes the approval; the change applies when it clears.
2030        if (data.mode === 'authenticate' && data.url) { alert(data.message); window.location.href = data.url; return; }
2031      }
2032      if (data.url) { window.location.href = data.url; return; }
2033      alert(data.error || 'Failed to start checkout');
2034    } catch (e) {
2035      alert('Network error. Please try again.');
2036    }
2037    if (btn) { btn.textContent = label; btn.disabled = false; }
2038  };
2039  renderDocsPrices();
2040  // Chain lists are never hardcoded in the copy: /api/evm/access is the single
2041  // source of truth and already honours HIDDEN_CHAINS, so a chain that is held
2042  // back (BNB, at time of writing) can't leak into the docs, and one that
2043  // launches appears here with no edit. The markup ships a sensible default so
2044  // the page still reads correctly if the probe fails.
2045  var CHAIN_TICKER = { ethereum:'ETH', base:'BASE', robinhood:'RH', bsc:'BNB' };
2046  var CHAIN_NAME   = { ethereum:'Ethereum', base:'Base', robinhood:'Robinhood Chain', bsc:'BNB Chain' };
2047  try {
2048    fetch(API_ORIGIN + '/api/evm/access', { credentials: 'include' })
2049      .then(function(r){ return r.ok ? r.json() : null; })
2050      .then(function(d){
2051        if (!d || !d.enabled) return;
2052        var t = document.getElementById('docsChainScope');
2053        if (t) t.style.display = 'flex';
2054        var live = (d.chains || []).filter(function(c){ return CHAIN_TICKER[c]; });
2055        if (!live.length) return;
2056        document.querySelectorAll('.chain-ticker-list').forEach(function(el){
2057          el.textContent = ['SOL'].concat(live.map(function(c){ return CHAIN_TICKER[c]; })).join('·');
2058        });
2059        document.querySelectorAll('.chain-name-list').forEach(function(el){
2060          el.textContent = live.map(function(c){ return CHAIN_NAME[c]; }).join(', ');
2061        });
2062        document.querySelectorAll('.chain-id-rows').forEach(function(el){
2063          el.innerHTML = live.map(function(c){
2064            return '<tr><td class="param-name">' + c + '</td><td>' + CHAIN_NAME[c] +
2065                   '</td><td><code>0x</code> + 40 hex characters</td></tr>';
2066          }).join('');
2067        });
2068      }).catch(function(){});
2069  } catch(e){}
2070})();
2071</script>
2071
2072</body>
2073</html>

Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.