Axo

Call Paid APIs

Handle 402 challenges and pay invoices automatically with Axo Fetch or axo fetch.

Any HTTP client can call an L402-protected endpoint. In practice, @axobot/fetch gives you the full challenge-pay-retry loop in one function.

Programmatic Flow (Node.js)

import { agentFetch, FileTokenCache } from "@axobot/fetch";

const tokenCache = new FileTokenCache(`${process.env.HOME}/.zbd-wallet/token-cache.json`);

const response = await agentFetch("https://api.zbdpay.com/premium", {
  tokenCache,
  maxPaymentSats: 100,
  pay: async (challenge) => {
    const payment = await fetch("https://api.zbdpay.com/v0/payments", {
      method: "POST",
      headers: {
        apikey: process.env.ZBD_API_KEY!,
        "content-type": "application/json",
      },
      body: JSON.stringify({
        invoice: challenge.invoice,
        amount: challenge.amountSats,
      }),
    });

    const body = await payment.json();

    return {
      preimage: body?.preimage ?? body?.data?.preimage,
      paymentId: body?.id ?? body?.data?.id,
      amountPaidSats: challenge.amountSats,
    };
  },
});

console.log(response.status, await response.text());

What agentFetch Handles

Checks token cache first

If a valid token exists for the URL, it retries immediately with authorization proof.

Passes through non-402 responses

Normal endpoints return untouched.

Parses challenge from header and/or JSON body

Accepts both L402 and LSAT, and both macaroon or token challenge keys.

Runs your payment hook and retries

Builds Authorization: <scheme> <macaroon>:<preimage>.

Caches proof for future calls

Reuses proof until it expires or the server rejects it.

Manual Primitives (Advanced)

import { requestChallenge, payChallenge, fetchWithProof } from "@axobot/fetch";

const challenge = requestChallenge({
  status: res.status,
  headers: res.headers,
  bodyText: await res.text(),
});

const paid = await pay(challenge);
const authorization = payChallenge(challenge, paid);

const retried = await fetchWithProof(
  "https://api.zbdpay.com/premium",
  { method: "GET" },
  authorization,
  fetch,
);

CLI Flow with axo

axo fetch uses Axo Fetch internally:

axo fetch "https://api.zbdpay.com/premium" --max-sats 100

Call it a second time to confirm cache reuse:

axo fetch "https://api.zbdpay.com/premium" --max-sats 100

When cache is reused, payment_id is typically null on the second call.

Authorization Format

Authorization: L402 <macaroon>:<preimage>

LSAT is also accepted as a legacy scheme.

On this page