Built a Lightning-gated reverse proxy that charges AI scrapers A developer built Argentic, a Go-based reverse proxy that charges AI scrapers per request using Lightning Network payments via L402 credentials, returning a 402 Payment Required with a Bitcoin Lightning invoice when payment is missing. The proxy validates macaroons with caveats for path, method, expiry, and response size, and requires patching HTTP clients like httpx and aiohttp to auto-pay and retry. Pricing is configurable per endpoint, with default 1000 millisats per request and up to 5000 for premium paths, and it works with LND-compatible nodes. Built a Lightning-gated reverse proxy that charges AI scrapers The stack is deliberately minimal — a Go proxy that intercepts inbound traffic, validates an L402 LSAT + Lightning credential, and either forwards the request or returns a 402 Payment Required with a fresh invoice. No accounts, no API keys, no Stripe. Just sats. client → Argentic → your API │ └─ validates macaroon + preimage │ ├─ valid → proxy request └─ invalid → 402 + lightning invoice Each macaroon carries caveats: target path, method, expiry timestamp, max response bytes. The preimage proves payment settled on-chain well, off-chain via Lightning . Caveats are verified cryptographically — no database lookup needed. Deployment is a single binary plus a config file: listen: ":8080" upstream: "http://api.internal:8000" lnd: host: "lnd:10009" macaroon path: "/data/admin.macaroon" tls path: "/data/tls.cert" pricing: default: 1000 millisats per request paths: "/v1/premium": 5000 "/v1/bulk": 100 macaroon: expiry: "24h" id bytes: 16 The pricing model is where it gets interesting. You can charge more for compute-heavy endpoints, less for cached reads, zero for health checks. Since the macaroon encodes the path, a single invoice can cover a batch of requests to the same tier — the agent presents the same preimage until expiry. Tested it against a few open-source scraping frameworks. Most choke on 402 because they expect 429 or 403 . Had to patch httpx and aiohttp middleware to auto-pay and retry. That friction is the feature — it filters for agents that actually have a budget. One gotcha: LND's settleInvoice RPC requires the preimage, but the proxy only sees the payment hash in the macaroon. Workaround is a background poller that indexes settled invoices by payment hash → preimage. Adds ~200ms latency on first request after payment. Acceptable for now. func p Proxy validateMacaroon m macaroon.Macaroon, preimage byte error { // verify signature with root key if m.Verify p.rootKey { return ErrInvalidSignature } // check caveats for , c := range m.Caveats { if p.checkCaveat c, preimage { return ErrCaveatFailed } } // verify preimage hashes to payment hash in macaroon if bytes.Equal sha256.Sum256 preimage , m.PaymentHash { return ErrPreimageMismatch } return nil } Still deciding on the macaroon rotation strategy. Short expiry 1h means frequent re-payment but tighter revocation. Long expiry 24h reduces Lightning traffic but leaves a wider window if a preimage leaks. Leaning toward 4h with a refresh endpoint that issues a new macaroon for the same preimage. Open question: should the proxy aggregate multiple requests into a single invoice pay once, get N requests or keep it strictly per-request? Per-request is simpler and maps cleanly to metered API pricing. Batch feels better for high-frequency agents but complicates caveat encoding. Binary and config examples at the repo. No Docker image yet — go build and drop it in front of whatever you're protecting. Works with any LND-compatible node Core Lightning, LND, LDK . What's the most hostile scraping pattern you've seen that rate limits didn't stop? Next Gen Z job anxiety hits new highs as AI coding agents ship → /en/news/7155/