Skip to content

Commit ebe9fc8

Browse files
realbubclaude
andcommitted
docs: update README for v1.0.0 wallet-scoped L402 API
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 238face commit ebe9fc8

1 file changed

Lines changed: 14 additions & 9 deletions

File tree

README.md

Lines changed: 14 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { l402, LnBot } from "@lnbot/l402";
1717
const app = express();
1818
const ln = new LnBot({ apiKey: "key_..." });
1919

20-
app.use("/api/premium", l402.paywall(ln, { price: 10 }));
20+
app.use("/api/premium", l402.paywall(ln, { walletId: "wal_...", price: 10 }));
2121

2222
app.get("/api/premium/data", (req, res) => {
2323
res.json({ data: "premium content" });
@@ -73,6 +73,7 @@ const ln = new LnBot({ apiKey: "key_..." });
7373

7474
// Paywall a route group — 10 sats per request
7575
app.use("/api/premium", l402.paywall(ln, {
76+
walletId: "wal_...",
7677
price: 10,
7778
description: "API access",
7879
}));
@@ -96,19 +97,20 @@ app.listen(3000);
9697
### How the middleware works
9798

9899
1. Checks for an `Authorization: L402 ...` header
99-
2. If present, calls `ln.l402.verify()` — the SDK checks signature, preimage, and caveats server-side
100+
2. If present, calls `wallet.l402.verify()` — the SDK checks signature, preimage, and caveats server-side
100101
3. If valid, populates `req.l402` and calls `next()`
101-
4. If missing or invalid, calls `ln.l402.createChallenge()` and returns a `402` response with the invoice and macaroon
102+
4. If missing or invalid, calls `wallet.l402.createChallenge()` and returns a `402` response with the invoice and macaroon
102103

103104
### Dynamic pricing
104105

105106
```typescript
106107
// Fixed price per route
107-
app.use("/api/cheap", l402.paywall(ln, { price: 1 }));
108-
app.use("/api/expensive", l402.paywall(ln, { price: 100 }));
108+
app.use("/api/cheap", l402.paywall(ln, { walletId: "wal_...", price: 1 }));
109+
app.use("/api/expensive", l402.paywall(ln, { walletId: "wal_...", price: 100 }));
109110

110111
// Custom pricing function — receives the request, returns price in sats
111112
app.use("/api/dynamic", l402.paywall(ln, {
113+
walletId: "wal_...",
112114
price: (req) => {
113115
if (req.path.includes("/bulk")) return 50;
114116
return 5;
@@ -120,6 +122,7 @@ app.use("/api/dynamic", l402.paywall(ln, {
120122

121123
| Option | Type | Description |
122124
| --- | --- | --- |
125+
| `walletId` | `string` | Wallet ID for L402 operations |
123126
| `price` | `number \| (req) => number` | Price in satoshis — fixed or per-request |
124127
| `description` | `string` | Invoice memo shown in wallets |
125128
| `expirySeconds` | `number` | Challenge expiry in seconds |
@@ -137,6 +140,7 @@ import { l402, LnBot } from "@lnbot/l402";
137140
const ln = new LnBot({ apiKey: "key_..." });
138141

139142
const client = l402.client(ln, {
143+
walletId: "wal_...", // wallet for L402 payments
140144
maxPrice: 100, // refuse to pay more than 100 sats per request
141145
budgetSats: 50000, // spending limit for the period
142146
budgetPeriod: "day", // reset period: "hour" | "day" | "week" | "month"
@@ -167,13 +171,14 @@ await client.delete("https://api.example.com/premium/item/1");
167171
2. If cached, sends the request with the `Authorization` header
168172
3. If no cache (or server rejects), makes a plain request
169173
4. On `402`, parses the challenge and checks budget limits
170-
5. Calls `ln.l402.pay()` — the SDK pays the invoice and returns a ready-to-use token
174+
5. Calls `wallet.l402.pay()` — the SDK pays the invoice and returns a ready-to-use token
171175
6. Caches the token and retries the request with authorization
172176

173177
### Client options
174178

175179
| Option | Type | Default | Description |
176180
| --- | --- | --- | --- |
181+
| `walletId` | `string` || Wallet ID for L402 operations |
177182
| `maxPrice` | `number` | `1000` | Max sats to pay for a single request |
178183
| `budgetSats` | `number` | unlimited | Total budget in sats for the period |
179184
| `budgetPeriod` | `string` || Reset period: `"hour"`, `"day"`, `"week"`, `"month"` |
@@ -195,7 +200,7 @@ const redisStore: TokenStore = {
195200
async delete(url) { /* delete from Redis */ },
196201
};
197202

198-
const client = l402.client(ln, { store: redisStore });
203+
const client = l402.client(ln, { walletId: "wal_...", store: redisStore });
199204
```
200205

201206
---
@@ -251,13 +256,13 @@ try {
251256

252257
| Export | Description |
253258
| --- | --- |
254-
| `l402.paywall(ln, options)` | Express middleware factory — protects routes behind an L402 paywall |
259+
| `l402.paywall(ln, options)` | Express middleware factory — protects routes behind an L402 paywall. Options must include `walletId`. |
255260

256261
### Client
257262

258263
| Export | Description |
259264
| --- | --- |
260-
| `l402.client(ln, options?)` | Creates an L402-aware HTTP client with automatic payment |
265+
| `l402.client(ln, options)` | Creates an L402-aware HTTP client with automatic payment. Options must include `walletId`. |
261266
| `client.fetch(url, init?)` | L402-aware fetch — pays 402 challenges automatically |
262267
| `client.get(url, init?)` | GET + JSON parse with automatic L402 payment |
263268
| `client.post(url, init?)` | POST + JSON parse with automatic L402 payment |

0 commit comments

Comments
 (0)