L402 API Design Patterns: Selling Services for Sats
What L402 Is#
L402 is an authentication scheme built on HTTP 402 ("Payment Required") and Lightning Network invoices. The flow is:
- Client requests a protected resource
- Server returns 402 + a Macaroon (capability token) + BOLT11 invoice
- Client pays the invoice
- Client presents the paid Macaroon as a Bearer token
- Server validates Macaroon + payment preimage → grants access
No accounts. No API keys to manage. No subscription billing. Just HTTP with money.
The Macaroon Design#
Macaroons are structured tokens with caveats you can add unidirectionally (you can restrict but not expand permissions). This maps perfectly to API access control.
A good L402 Macaroon structure:
Root Macaroon:
- user_id: (payment hash)
- service: text-inference
- expires: 2026-10-28T00:00:00Z
Caveats you might add:
- calls_remaining: 10
- model: gpt-4o-mini
- max_tokens: 2000
When the client pays and receives the preimage, they bind it to their Macaroon. Your server verifies the binding.
Pricing Tiers#
A useful L402 API usually has tiers:
| Tier | Price | Access |
|---|---|---|
| Demo | 0 sats | Single call, limited output |
| Basic | 1000 sats | 10 calls, standard models |
| Pro | 5000 sats | 100 calls, all models |
The demo tier reduces friction to zero. A lot of users who try the demo buy the paid tier.
Rate Limiting Without Accounts#
Without accounts, rate limiting by IP is your primary defense. But IP-based limits are easy to abuse.
Better approach: each paid Macaroon encodes a call budget. The server decrements a counter per call. No state needed beyond a nonce check to prevent replay.
For high-volume attacks: require a small "proof-of-work" challenge on the demo endpoint (hashcash or similar). This costs milliseconds for legitimate users and kills bot traffic.
Handling Expired Invoices#
BOLT11 invoices expire (typically 3600 seconds). If a client waits too long to pay, the invoice is invalid.
Solutions:
- Generate fresh invoices on every 402 response
- Store pending invoices with a TTL
- Client detects expired invoice → fetch new one → retry
Most Lightning wallets handle this transparently. Build your server to generate fresh invoices gracefully rather than returning stale ones.
Real-World Deployment#
The hardest part of L402 in production is the Lightning backend. Your options:
- LND (most mature, REST/gRPC API)
- Core Lightning (lighter, plugin ecosystem)
- LDK (library, build your own node)
- NWC (Nostr Wallet Connect — delegate to a managed wallet)
NWC via Alby is the simplest starting point. The wallet manages channels; you just call makeInvoice() and lookupInvoice().
Why This Pattern Works#
Traditional API monetization has high friction: sign up, add credit card, wait for approval, get a key, integrate the SDK. Churn is high.
L402 reduces that to: try it → pay 1000 sats → use it immediately. The barrier is low enough that curious developers actually convert.
The catch: Lightning wallet penetration is still low. L402 APIs serve the Bitcoin-native developer community best. If your target market is mainstream enterprise, you'll want fiat fallback.
Comments
No comments yet. Start the conversation.