Last week I shipped AtlasData, a pay-per-call crypto data API where the buyer is usually not a human — it is an agent that holds a wallet. Getting paid per request without accounts, API keys, or invoices meant implementing both of the protocols that actually work today: x402 (USDC on Base) and L402 (Lightning sats). Here is what I learned running both on the same FastAPI app.
The shape of both protocols
Both live on HTTP 402 Payment Required:
curl -i https://atlasdata.shares.zrok.io/api/price/BTC # HTTP/2 402 # {"payment": {"maxAmountRequired":"1000", "asset":"USDC", "network":"eip155:8453", ...}} curl -i https://atlasdata.shares.zrok.io/l402/btc/fees # HTTP/2 402 # www-authenticate: L402 macaroon="...", invoice="lnbc100n1..." The difference is the proof. x402 returns an EIP-3009 transferWithAuthorization the client signs; a facilitator settles it onchain, then your server serves the response. L402 pairs a macaroon with a BOLT11 invoice — after paying, the client retries with Authorization: L402 <token>:<preimage> and you verify sha256(preimage) == payment_hash with zero stored state.
Why run both
- x402 buyers are mostly EVM-native agents (CDP wallets, Coinbase's Bazaar discovery). Settlement is a stablecoin transfer — clean accounting, but every call is a chain transaction.
- L402 buyers are Lightning-native (the sats crowd, Nostr agents). No facilitator, instant finality, and the credential can be reused until caveats expire — closer to a bearer capability than a payment.
Per-request stablecoin settlement vs. prepaid capability — different trust models, same 402 status.
The boring parts that mattered
- Discovery docs are the product. Agents do not browse — they read
/.well-known/x402,/openapi.jsonwithx-payment-infohints, and/llms.txt. Half my paid traffic comes from crawlers, not humans. - Return a real challenge, not a marketing page. Any error string that is not a parseable 402 payload breaks machine clients. I verify with
curl -ifrom a clean shell — browsers see the tunnel's interstitial, agents see the 402. - One fee model, two prices. Each route has one USD price expressed twice:
$0.001for x402 or ~10 sats for L402. Keep them equivalent; arbitrage hunters notice. - Reject bad params before the paywall. A 404 must come before a 402 — agents will retry a paid request forever if you let them pay into a 404.
The catalog today: spot prices, 24h tickers, mempool fees, Base gas/blocks, ERC-20 metadata, wallet balances, Dexscreener pairs, Fear & Greed, plus a few paid research reports ($0.50 / 200 sats). Everything is discoverable from /llms.txt and /openapi.json.
If you are building paid APIs for agents, run both rails — the audiences barely overlap, and the marginal cost of the second middleware is tiny.
