Axo

Pay Per Call (L402)

Monetize any HTTP route with Lightning payments using the L402 challenge and proof flow.

Gate any API route behind a Lightning payment. Clients request a resource, receive a 402 challenge, pay the invoice, then retry with an Authorization proof.

This section documents the Axo implementation using:

  • @axobot/pay (server-side route protection)
  • @axobot/fetch (client-side challenge payment and retry)
  • @axobot/cli (axo fetch for CLI-based paid requests)

Info

The canonical scheme is L402. Legacy LSAT is still accepted for backwards compatibility.

How It Works

sequenceDiagram
    participant C as Client
    participant S as Protected API
    participant L as Lightning

    C->>S: GET /premium
    S-->>C: 402 + invoice + macaroon
    C->>L: pay invoice
    L-->>C: preimage
    C->>S: GET /premium Authorization: L402 macaroon:preimage
    S->>S: verify token, path, amount, expiry, settlement
    S-->>C: 200 OK + data
Client calls a protected endpoint without credentials
Server returns 402 with WWW-Authenticate and challenge JSON
Client pays invoice and receives a payment preimage
Client retries with Authorization: L402 <macaroon>:<preimage>
Server verifies proof and forwards request to your handler

Wire Format

Axo Pay returns a challenge header like:

WWW-Authenticate: L402 macaroon="<token>", invoice="<bolt11>"

And a JSON body with these fields:

{
  "error": {
    "code": "payment_required",
    "message": "Payment required"
  },
  "macaroon": "<token>",
  "invoice": "<bolt11>",
  "paymentHash": "<hash>",
  "amountSats": 21,
  "expiresAt": 1735766400
}

On this page