Axo

Axo Fetch

Use agentFetch to parse 402 challenges, pay invoices, and retry automatically with L402 proof or MPP session authorization.

@axobot/fetch is the client half of Axo's paid-resource flow. It handles classic L402/LSAT challenges and now also supports MPP session authorization flows through @axobot/mppx.

Install

npm install @axobot/fetch

Minimal Integration

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

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

const response = await agentFetch("https://example.com/protected", {
  tokenCache,
  maxPaymentSats: 100,
  pay: async (challenge) => {
    // Pay challenge.invoice with your wallet implementation.
    return {
      preimage: "<payment-preimage>",
      paymentId: "<payment-id>",
      amountPaidSats: challenge.amountSats,
    };
  },
});

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

API Surface

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

Core Options

OptionRequiredPurpose
pay(challenge)YesPays parsed challenge and returns preimage or payment ID
waitForPayment(paymentId)NoPolls async settlement when preimage is not immediate
tokenCacheNoCache for URL-scoped authorization proofs
maxPaymentSatsNoHard cap to reject expensive challenges
requestInitNoBase request options forwarded to fetch
paymentTimeoutMsNoAsync settlement timeout
paymentPollIntervalMsNoPoll interval for async settlement

Manual Flow (Advanced)

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

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

const paid = await pay(challenge);
const authorization = payChallenge(challenge, paid);
import { fetchWithProof } from "@axobot/fetch";

const res = await fetchWithProof(
"https://example.com/protected",
{ method: "GET" },
authorization,
fetch,
);

Behavior Guarantees

Cache lookup first

If a valid token exists for the URL, request is sent with proof immediately.

Pass-through for non-402

Non-paid endpoints are returned untouched.

Challenge parsing

Supports L402, LSAT, x402, and MPP challenge schemes.

Payment and retry

Runs caller-provided payment logic, then retries with authorization proof.

Proof caching

Stores token and optional expiry for reuse.

MPP Sessions

For session-based resources, provide payMpp instead of only pay:

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

const payMpp = zbdPayMpp({
  apiKey: process.env.ZBD_API_KEY!,
  returnLightningAddress: "agent@axo.bot",
});

const response = await agentFetch("https://api.zbdpay.com/stream", {
  pay: async () => {
    throw new Error("L402 pay hook should not run for MPP");
  },
  payMpp,
});

Runnable Examples

The repository includes maintained scripts under examples/:

  • the paid fetch example in axobot-fetch
  • the proof-based fetch example in axobot-fetch

From the agents workspace, run:

npm --prefix axobot-fetch run build
PROTECTED_URL="https://api.zbdpay.com/protected" ZBD_API_KEY=<your_api_key> npm --prefix axobot-fetch run example:zbd

If you already have an authorization token:

PROTECTED_URL="https://api.zbdpay.com/protected" L402_AUTHORIZATION="L402 <macaroon>:<preimage>" npm --prefix axobot-fetch run example:proof

Warning

pay is mandatory. Axo Fetch does not call the wallet service directly unless you implement that behavior in your payment hook.

On this page