Try it now: https://402-proxy.albylabs.com
A minimal HTTP proxy that gates upstream API access behind Lightning payments. It supports two protocols:
- L402 — uses macaroons and
WWW-Authenticate/Authorizationheaders - x402 — uses
PAYMENT-REQUIRED/Payment-Signatureheaders, settled via the Alby x402 facilitator
Unauthenticated requests receive a 402 Payment Required challenge containing a Lightning invoice. Once the invoice is paid, the client authenticates and the proxy forwards the request to the upstream URL.
This is for testing only — the receiving wallet NWC URL is included in the request, as well as the real upstream URL, so if you inspect the URL you could extract the original endpoint and execute it for free.
yarn install
yarn run dev # development (tsx, no build step)
# or
yarn run build && yarn start # productionThe server listens on port 3000 by default. Set PORT to override.
Both endpoints accept the same query parameters:
| Param | Description |
|---|---|
url |
The encoded upstream URL to proxy to |
nwc_url |
An encoded Nostr Wallet Connect connection string used to create the invoice |
amount |
Amount in sats |
curl -v "http://localhost:3000/l402?url=https://example.com&nwc_url=nostr%2Bwalletconnect%3A%2F%2F...&amount=1"Response: 402 Payment Required
WWW-Authenticate: L402 macaroon="<macaroon>", invoice="<bolt11>"
The macaroon encodes the upstream URL, payment hash, and a 1-hour expiry, signed with an HMAC. Save it — you'll need it in step 3.
Pay the bolt11 invoice using any Lightning wallet. After payment you receive a preimage (32-byte hex string).
curl -v -H "Authorization: L402 <macaroon>:<preimage>" \
"http://localhost:3000/l402?url=https://example.com&nwc_url=nostr%2Bwalletconnect%3A%2F%2F...&amount=1"The proxy verifies the macaroon signature and that SHA256(preimage) == paymentHash, then forwards the request upstream. Query params are ignored on authenticated requests.
curl -v "http://localhost:3000/x402?url=https://example.com&nwc_url=nostr%2Bwalletconnect%3A%2F%2F...&amount=1"Response: 402 Payment Required with a JSON body and header:
PAYMENT-REQUIRED: <encoded payment requirements>
The JSON body contains the x402 payment requirements including a Lightning invoice in accepts[0].extra.invoice.
Pay the Lightning invoice. The Alby facilitator tracks the payment.
Retry the request with a Payment-Signature header containing the encoded payment proof (as per the x402 spec). The proxy verifies the payment via the Alby facilitator, proxies the request upstream, and returns a PAYMENT-RESPONSE header with the settlement result.
- The signing secret is generated randomly at startup, so macaroons (L402) and payment bindings (x402) are invalidated when the server restarts.
- L402 macaroons expire after 1 hour.
- The
Authorizationheader is stripped before forwarding to the upstream.