-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathindex.html
More file actions
170 lines (155 loc) · 8.38 KB
/
index.html
File metadata and controls
170 lines (155 loc) · 8.38 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>402.pub — Paid APIs on Nostr</title>
<meta name="description" content="The open marketplace for paid APIs. Discover services on Nostr, pay with L402, x402, or Cashu. Gate your API or give your agent a wallet.">
<meta property="og:title" content="402.pub — Paid APIs on Nostr">
<meta property="og:description" content="The open marketplace for paid APIs. Discover services on Nostr, pay with L402, x402, or Cashu.">
<meta property="og:url" content="https://402.pub/">
<meta property="og:type" content="website">
<meta property="og:site_name" content="402.pub">
<meta property="og:image" content="https://402.pub/social-preview.png">
<meta property="og:image:width" content="1280">
<meta property="og:image:height" content="640">
<meta name="twitter:card" content="summary_large_image">
<meta name="twitter:image" content="https://402.pub/social-preview.png">
<meta name="twitter:title" content="402.pub — Paid APIs on Nostr">
<meta name="twitter:description" content="The open marketplace for paid APIs. No registry, no API keys, no gatekeepers.">
<meta http-equiv="Content-Security-Policy" content="default-src 'none'; script-src 'self' https://plausible.io; style-src 'self' https://fonts.googleapis.com 'unsafe-inline'; font-src https://fonts.gstatic.com; img-src 'self' https:; connect-src ws: wss: http: https:; base-uri 'none'; form-action 'none';">
<link rel="stylesheet" href="style.css">
<link rel="icon" href="favicon.ico" sizes="any">
<link rel="icon" href="icon.svg" type="image/svg+xml">
<link rel="apple-touch-icon" href="apple-touch-icon.png">
</head>
<body>
<canvas id="particle-canvas" aria-hidden="true"></canvas>
<!-- ===== Hero ===== -->
<header>
<div class="header-content">
<h1>402.pub</h1>
<p class="subtitle">The open marketplace for paid APIs. Discover services on Nostr. Pay with L402, x402, or Cashu.</p>
<div class="hero-stats" aria-label="Live ecosystem stats">
<div class="hero-stat">
<span class="stat-value" id="hero-service-count">0</span>
<span class="stat-label">services</span>
</div>
<div class="hero-stat hero-stat-clickable" id="hero-stat-l402">
<span class="stat-value" id="hero-l402-count">0</span>
<span class="stat-label">L402</span>
</div>
<div class="hero-stat hero-stat-clickable" id="hero-stat-x402">
<span class="stat-value" id="hero-x402-count">0</span>
<span class="stat-label">x402</span>
</div>
<div class="hero-stat hero-stat-clickable" id="hero-stat-ietf">
<span class="stat-value" id="hero-ietf-count">0</span>
<span class="stat-label">IETF 402</span>
</div>
<div class="hero-stat hero-stat-clickable" id="hero-stat-cashu">
<span class="stat-value" id="hero-cashu-count">0</span>
<span class="stat-label">Cashu</span>
</div>
<div class="hero-stat">
<span class="stat-value" id="hero-relay-count">0</span>
<span class="stat-label">relays</span>
</div>
</div>
<div class="hero-updated" id="hero-last-updated" aria-live="polite"></div>
<div class="hero-ctas">
<a href="#panel-operator" class="btn btn-primary" id="cta-operator" data-tab="tab-operator">I run an API</a>
<a href="#panel-agent" class="btn btn-secondary" id="cta-agent" data-tab="tab-agent">I build agents</a>
</div>
<div id="relay-status" class="relay-status" role="status" aria-label="Relay connection status"></div>
</div>
</header>
<main>
<!-- ===== Audience Tabs ===== -->
<section class="audience-section">
<div class="audience-tabs" role="tablist" aria-label="Get started">
<button class="audience-tab audience-tab-operator active" role="tab" aria-selected="true" aria-controls="panel-operator" id="tab-operator">I run an API</button>
<button class="audience-tab audience-tab-agent" role="tab" aria-selected="false" aria-controls="panel-agent" id="tab-agent">I build agents</button>
</div>
<div class="audience-panel audience-panel-operator active" role="tabpanel" id="panel-operator" aria-labelledby="tab-operator">
<h2>Gate any API behind a paywall in 5 lines</h2>
<pre><code>npm i @forgesworn/toll-booth</code></pre>
<div class="audience-links">
<a href="https://github.com/forgesworn/toll-booth">toll-booth</a>
<a href="https://github.com/forgesworn/402-announce">402-announce</a>
<a href="https://github.com/forgesworn/toll-booth-announce">toll-booth-announce</a>
</div>
</div>
<div class="audience-panel audience-panel-agent" role="tabpanel" id="panel-agent" aria-labelledby="tab-agent" hidden>
<h2>Give your agent a wallet. It handles the rest.</h2>
<pre><code>npx 402-mcp</code></pre>
<div class="audience-links">
<a href="https://github.com/forgesworn/402-mcp">402-mcp</a>
<a href="https://www.npmjs.com/package/402-mcp">npm</a>
</div>
</div>
</section>
<!-- ===== Directory Toolbar ===== -->
<div id="filters" class="services-toolbar" aria-label="Filter services">
<div class="toolbar-status" role="status" aria-live="polite">
<span class="live-dot" aria-hidden="true"></span>
<span id="service-count">0 services</span>
<span class="toolbar-sep" aria-hidden="true"></span>
<span id="relay-count" class="relay-count-inline">0 relays</span>
</div>
<div class="toolbar-filters">
<label for="search" class="sr-only">Search services</label>
<input type="search" id="search" placeholder="Search services..." autocomplete="off" aria-label="Search services">
<div class="filter-row">
<div id="rail-filters" class="filter-pills" role="group" aria-label="Filter by payment rail"></div>
<div id="tier-filters" class="filter-pills" role="group" aria-label="Filter by trust tier"></div>
<div id="transport-filters" class="filter-pills" role="group" aria-label="Filter by transport type"></div>
</div>
<div id="payment-filters" class="filter-pills" role="group" aria-label="Filter by payment method"></div>
<div id="topic-filters" class="filter-pills" role="group" aria-label="Filter by topic"></div>
</div>
</div>
<!-- ===== Services Grid ===== -->
<div id="loading" class="loading" role="status" aria-live="polite">Connecting to relays...</div>
<section id="services-grid" class="services-grid" aria-label="Discovered services" aria-live="polite"></section>
<section id="empty-state" class="empty-state" hidden aria-live="polite">
<p>No services match your filters.</p>
</section>
<!-- ===== Announce CTA ===== -->
<section id="announce" class="announce-cta">
<h2>Announce Your Own API</h2>
<p>Get your API listed here. Announce it on Nostr in 10 lines of code.</p>
<pre><code>import { announceService } from '402-announce'
await announceService({
secretKey: process.env.NOSTR_SK,
relays: ['wss://relay.damus.io'],
identifier: 'my-api',
name: 'My Paid API',
url: 'https://api.example.com',
about: 'Pay-per-request API',
pricing: [{ capability: 'query', price: 10, currency: 'sats' }],
paymentMethods: [['l402', 'lightning']],
})</code></pre>
<div class="cta-links">
<a href="https://www.npmjs.com/package/402-announce">402-announce on npm</a>
<a href="https://www.npmjs.com/package/toll-booth-announce">toll-booth-announce bridge</a>
<a href="https://github.com/forgesworn/402-announce">GitHub</a>
</div>
</section>
</main>
<!-- ===== Footer ===== -->
<footer>
<p>
<a href="https://github.com/forgesworn/toll-booth">toll-booth</a> ·
<a href="https://github.com/forgesworn/402-announce">402-announce</a> ·
<a href="https://github.com/forgesworn/toll-booth-announce">toll-booth-announce</a> ·
<a href="https://github.com/forgesworn/402-mcp">402-mcp</a>
</p>
<p>Services discovered via <a href="https://github.com/forgesworn/402-announce">kind 31402</a> on Nostr</p>
</footer>
<script src="bech32.js"></script>
<script src="nip19.js"></script>
<script src="app.js"></script>
<script defer data-domain="402.pub" src="https://plausible.io/js/script.js"></script>
</body>
</html>