← Blog
August 18, 2026 · 14 min

L402 Audited: The Original HTTP 402 Is Becoming a Payment Method

Five years before x402 existed, Lightning Labs shipped a working HTTP 402. We audited it on 2026-08-18: the spec, the standardization trail, and every line of the proxy that implements it. The protocol works. The paperwork never happened. And the reference implementation now speaks someone else's payment scheme alongside its own.

Most of the agentic payments conversation of the last eighteen months assumes HTTP 402 was dormant until stablecoins woke it up. It was not. L402, formerly LSAT, has been in production since 2019 behind Lightning Loop, and the repository that holds its specification was created on 2020-02-07. It solved the same problem x402 solves: how a server charges an anonymous client per request without accounts, API keys, or an out-of-band signup.

The design is different enough to be worth understanding on its own terms, and its 2026 trajectory is the most interesting thing about it. So we cloned the spec repo, the reference proxy, and the Lightning bLIP repository, pulled the IANA registries and the IETF datatracker, and read what is actually there.

What L402 specifies

The protocol specification is 402 lines of RFC-styled Markdown. The core is two headers.

// Challenge: server to client, on HTTP 402
WWW-Authenticate: L402 macaroon="<base64>", invoice="<bolt11>"

// Credential: client to server, on the retry
Authorization: L402 <base64(macaroon)>:<hex(preimage)>

Both parameters in the challenge are REQUIRED. The macaroon MUST commit to the payment hash of the BOLT 11 invoice inside its identifier. That commitment is the whole trick: the server verifies payment by checking H == sha256(r) against the hash it embedded, where r is the preimage the client obtained by paying. No database lookup, no call back to the Lightning node, no facilitator. The spec calls this the RECOMMENDED path and it is the reason L402 scales sideways: any replica holding the macaroon root key can verify any credential.

The macaroon identifier is 66 bytes, big-endian: a 2-byte version (currently 0), the 32-byte payment hash, and a 32-byte random token ID that survives macaroon rotation and identifies the buyer across credentials. Caveats are key-value strings appended to the HMAC chain, and each new caveat can only narrow authority: services=name:tier, <service>_capabilities=cap1,cap2, and per-capability constraints.

Status codes are tighter than most implementations of 402 bother to be. 402 is used exclusively for the initial challenge. Once a client presents any credential, valid or not, the server MUST answer 401 on failure, never 402 again. That single rule lets a client distinguish "you have not paid" from "your credential is broken" without parsing a body.

Two details show the protocol's age, in a good way. gRPC gets its own flow, because gRPC requires HTTP 200 on every response: the challenge travels in a grpc-status-details-bin trailer with Grpc-Status: 402. And Section 10 mandates emitting both scheme names for backwards compatibility, LSAT first. The reference proxy does exactly that, with a comment explaining that old Loop clients scan only the first WWW-Authenticate header.

The design difference in one line — x402 sends money with the request; L402 buys a bearer credential and then reuses it. In x402 the payment payload is per request. In L402 the preimage is a receipt you present again and again until the server revokes it.

The standardization trail is empty

L402 is routinely described as bLIP-26, "Status: Active". We checked. Pull request #26 on lightning/blips, titled "blip-0026: L402 - Lightning HTTP 402 Protocol", was opened on 2023-06-07 by Olaoluwa Osuntokun. As of 2026-08-18 it is still open: one commit, 650 additions, 13 issue comments, 91 review comments, last touched 2026-03-11, merge state clean. The repository's root listing contains blip-0001 through blip-0055 with gaps; blip-0026.md is not among them.

The IANA side is the same story. The HTTP Authentication Schemes registry we pulled on 2026-08-18 lists fourteen schemes: Basic, Bearer, Concealed, Digest, DPoP, GNAP, HOBA, Mutual, Negotiate, OAuth, PrivateToken, SCRAM-SHA-1, SCRAM-SHA-256 and vapid. L402 is not one of them. Neither is Payment, the scheme we discuss below. The L402 spec's own sentence, "The L402 scheme is registered under the HTTP Authentication Framework specified in RFC 7235", is best read as "defined within that framework"; there is no registry entry behind it.

This is not fatal. Bearer tokens ran the web for years before RFC 6750, and a proxy that ships is worth more than a registry row. But it matters for anyone deciding what to implement, because it means there is no cross-vendor conformance surface: no registered scheme name, no adopted working-group document, no test vector authority outside the implementation itself.

What the repository looks like today

The spec repo has 90 stars, 19 forks and 11 open issues, no license file, and its last push was 2026-06-09. It was restructured in March 2026: commits on 2026-03-11 and 2026-03-20 split the old monolith into protocol-specification.md, a 533-line macaroon-spec.md, and something we had not seen in any other protocol repo.

agent-spec.md is 88 lines and the README describes it as "the complete protocol in ~560 tokens for AI agent integration". It is a specification compiled for a context window: headers, flow, identifier table, caveat grammar, and a nine-step implementation checklist, with every explanatory sentence removed. Whatever you think of the protocol, that file is a good idea. A spec an agent can hold entirely in context while writing a client is a distribution channel, and most protocol repos in this space still make an agent read forty pages of prose to find one header name.

The client ecosystem is where the age shows. The README lists two client libraries, lsat-js and boltwall, both from Tierion. Their last pushes were 2023-08-09 and 2023-04-26 respectively. Neither is archived; neither has moved in three years.

Aperture is not standing still

Aperture, the reverse proxy that terminates L402, is a different picture: MIT licensed, 268 stars, 77 forks, 58 open issues, 607 commits total of which 180 landed in 2026 alone, head commit 2026-08-13. Three of its directories did not exist a year ago.

// Addition 1

An MCP server for the paywall itself

Landed 2026-03-25. aperturecli mcp serve exposes the admin API as ten typed tools over stdio JSON-RPC: create_service, update_service, list_transactions, list_tokens, revoke_token, get_stats and friends. Input schemas are inferred from Go struct tags. The documented client is Claude Code.

The operator of a paid API is now an agent too: the paywall is configured by the same kind of client that pays it.

// Addition 2

meterd: prepaid bundles instead of per-request pricing

Landed 2026-07-06. The stated motivation is inference: "one request costs the seller a few dozen upstream tokens, the next costs four thousand, and the seller only learns which after the response has been served."

So payment happens once for a bundle, and accounting happens per request afterwards. A price server implements four RPCs: GetPrice quotes, ChallengeMinted books a bundle when the 402 is minted, AuthorizeRequest admits and reserves an estimate, ReportUsage debits what actually flowed.

The metering design is worth reading in full because it is the most honest treatment of LLM billing we have found in a payments codebase. Bundles are booked at challenge-mint time, not at payment time, and an unpaid booking expires after ten minutes. Reservations use the request's own max_tokens when present and a configurable estimatedtokens default of 4,096 otherwise, so ten concurrent requests cannot each be admitted against the same last thousand tokens. Aperture captures a bounded 16 KiB tail of the response body, hands it to the price server, and debits the true usage weighted by direction, rounding up so the satoshis drawn always cover the satoshis served. On streamed responses it walks the data: lines for the last usage-bearing chunk, falls back to brace-matching a truncated object, and strips the client's Accept-Encoding so the tail is readable at all. When no usage can be parsed, the request settles at the estimate rather than at zero.

That is the same problem we worked through in x402's upto scheme, solved with a different primitive: a prepaid balance drawn down off-chain rather than an authorization capped on-chain and captured for the actual amount.

The third directory is the story

The package added on 2026-03-19 is called mpp, and its constants name their sources directly:

// AuthScheme is the HTTP authentication scheme name for the Payment
// protocol as defined in draft-httpauth-payment-00.
AuthScheme = "Payment"

MethodLightning = "lightning"
IntentCharge    = "charge"   // draft-lightning-charge-00
IntentSession   = "session"  // draft-lightning-session-00

That is the Machine Payments Protocol, the Stripe and Tempo effort we audited from the spec up on 2026-08-10. Lightning Labs has implemented it inside Aperture, as a peer of its own protocol. With enablempp: true, a single 402 response now carries three offers: an LSAT challenge, an L402 challenge, and a Payment challenge. The config field is literally called authscheme and accepts "l402", "mpp", or "l402+mpp".

The engineering underneath that sentence is careful. The Payment charge offer mints its own invoice, distinct from the L402 offer's, so each 402 books two bundles at the same price and the unpaid sibling expires quietly. The metering key differs per door: L402 keys off the random token ID in the macaroon identifier, while the charge intent keys off the payment hash, since the preimage the buyer presents hashes to exactly the bundle key, so proof of payment and lookup key are the same 32 bytes. Aperture also documents where it deliberately breaks the Payment spec: a charge is single-use by default, but on a metered service a consumed charge would strand the bundle the buyer paid for, so charge credentials stay re-presentable and the exhausted balance is what retires them. The consumption record is still written on first use.

Sessions are the third door, behind enablesessions. A deposit opens the session, priced by default at twenty service units, bearer requests draw against it with a five-minute idle timeout, and the remainder is refunded at close. Aperture holds the balance; the price server is consulted twice per request, QuoteSession before and SettleSession after. Errors on all three doors come back as RFC 9457 problem documents under https://paymentauth.org/problems/, with a Lightning-specific subtree for invalid preimages, expired invoices, closed sessions and bad return invoices.

Who owns the Lightning method

Here is where the audit turns up something the announcements do not say. We checked the IETF datatracker on 2026-08-18. draft-httpauth-payment-00 exists: "The Payment HTTP Authentication Scheme", 33 pages, submitted 2026-06-19, expiring 2026-12-21, filed as an individual submission with no working group, preceded by draft-ryan-httpauth-payment-01 from 2026-03-18.

The documents Aperture cites for the Lightning behaviour, draft-lightning-charge-00 and draft-lightning-session-00, are not on the datatracker at all. They live in tempoxyz/mpp-specs, the Tempo repository, under specs/methods/lightning/. Lightning is one of ten payment method families there, next to card, evm, hedera, nearintents, solana, stellar, stripe, tempo and usdc. Neither the intent drafts nor the discovery extension are on the datatracker either; the Lightning charge draft's own normative reference points at datatracker.ietf.org/doc/draft-payment-intent-charge/, which returns 404.

And the authors of the Lightning method are not Lightning Labs. The front matter of draft-lightning-charge-00.md names Kevin Zhang, Jeremy Klein and Zhen Lu, all of Lightspark. The file has been in the repository since its initial commit on 2026-01-05.

Read the sequence plainly. Lightning Labs invented the working 402 and never merged its own bLIP. A different company wrote Lightning up as a payment method inside a scheme owned by a different repository. And Lightning Labs shipped that scheme in its proxy eight days after publishing a post about why L402 is purpose-built for agents. The protocol that was the whole product is becoming one method identifier among ten.

L402 against x402, mechanically

Both protocols answer with 402 and a challenge, and both let a client pay and retry. Everything after that differs.

L402's proof is a preimage: possession proves an invoice was paid, and the check is one SHA-256. x402's proof is a signed transfer authorization the facilitator verifies and settles on chain, which we walked through in the facilitator audit. L402 denominates in millisatoshis and inherits Lightning's custody model: to sell, you run a node with inbound liquidity; to buy, you keep channels funded. x402 denominates in stablecoins and inherits the chain's: to sell, you need an address; to buy, you need a balance and gas or an EIP-3009 style gasless transfer.

L402's credential is reusable and attenuable. A holder can append caveats to narrow a macaroon before handing it to a sub-agent, and the server verifies the narrowing without being told. x402 has no equivalent delegation primitive in the base protocol; scoping is done by the payer's wallet policy, which is exactly the trade-off we mapped in bearer versus walk-up. On the other hand, x402 v2, published 2026-06-24, brought discovery, wallet-based identity and CAIP-aligned multi-chain support into the standard, with a foundation and a spec repository behind it. L402 has one proxy, one spec repo, and two client libraries last touched in 2023.

The unglamorous difference is accounting. Stablecoin settlement produces an on-chain record any auditor can reconstruct. Lightning settlement produces a preimage and a private channel update. For a consumer paying for an article, that is a privacy feature. For a company that must reconcile agent spend against invoices, it is work someone has to do off-chain.

What it means for LLM4Agents

We settle in stablecoins over x402 and EIP-3009, and nothing in this audit changes that. Lightning custody is an operational business, and our buyers are agents holding USDC, not channel operators.

Three things do land on our roadmap.

First, the metering model. Aperture's bundle design is the closest thing we have seen to how an inference gateway actually bills: quote at challenge time, reserve an estimate at admission, debit the parsed usage at completion, round up, and settle streams at the estimate when the tail is unreadable. Those are the exact edge cases our reserve-proxy-settle loop has to survive, and we described our own version in the billing internals post. Their choice to book the bundle when the 402 is minted rather than when it is paid, and let unpaid bookings expire in ten minutes, is a cleaner ordering than reserving on payment.

Second, the convergence signal. Two independent 402 lineages, Lightning's and the stablecoin one, are both being pulled toward the same generic Payment scheme with method identifiers underneath. If that scheme reaches a working group and an IANA registration, the interesting question stops being "x402 or L402" and becomes "which methods does your gateway accept". A gateway that speaks one scheme with several methods is a better shape than a gateway that speaks several schemes.

Third, the threat. If a buyer's agent can pay a Lightning-metered endpoint and a stablecoin-metered endpoint through the same header vocabulary, the differentiator moves up the stack: routing, fallback, receipts, spend controls, identity. That is the layer we compete on anyway. But it means being scheme-agnostic at the edge is no longer optional.

Staying on the frontier

Concretely, in order.

One: implement a Payment-scheme parser on the buyer side before we need it. Aperture proves the scheme is now emitted by real servers, and the parsing surface is small: challenge parameters bound by an HMAC the client echoes verbatim, base64url with strict decoding, RFC 9457 problem documents on failure. An agent leaving our gateway should be able to satisfy a Payment challenge with the usdc or evm method even while we settle x402 internally.

Two: adopt the compressed-spec pattern. We should publish an agent-spec.md for our own payment and routing surface, in the low hundreds of tokens, so a coding agent can integrate without fetching our full docs. This is cheap and it directly reduces the cost of someone choosing us.

Three: track bLIP-26 and draft-httpauth-payment as protocol risk, not curiosity. The draft expires 2026-12-21. Whether it is refreshed, adopted by a working group, or replaced tells us how much of the 402 layer converges in 2027. We should watch for a working-group adoption call and for the first IANA registration request in the http-authschemes registry.

Four: bring the metering edge cases into our own conformance tests. Truncated stream tails, missing usage objects, concurrent reservations against a nearly exhausted balance, and estimate-versus-actual reconciliation are the failure modes that silently give away inference. Aperture has written them down; we should be able to prove we handle each one.

Five: keep denominating in stablecoins and stay honest about why. Not because Lightning is worse at micropayments, it is measurably better at very small amounts, but because our buyers hold dollars, our sellers invoice in dollars, and the reconciliation trail is the product. The moment that stops being true, the audit above is where we would start.

Pay per request, settle in stablecoins

One OpenAI-compatible endpoint, x402 settlement, no accounts to provision.

Register your agent