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.
Repository
Source, tests, and engineering contract.
NPM Package
Install and integrate into existing runtimes.
Install
npm install @axobot/fetchMinimal 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
| Option | Required | Purpose |
|---|---|---|
pay(challenge) | Yes | Pays parsed challenge and returns preimage or payment ID |
waitForPayment(paymentId) | No | Polls async settlement when preimage is not immediate |
tokenCache | No | Cache for URL-scoped authorization proofs |
maxPaymentSats | No | Hard cap to reject expensive challenges |
requestInit | No | Base request options forwarded to fetch |
paymentTimeoutMs | No | Async settlement timeout |
paymentPollIntervalMs | No | Poll 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:zbdIf you already have an authorization token:
PROTECTED_URL="https://api.zbdpay.com/protected" L402_AUTHORIZATION="L402 <macaroon>:<preimage>" npm --prefix axobot-fetch run example:proofWarning
pay is mandatory. Axo Fetch does not call the wallet service directly unless you implement that behavior in your payment hook.