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 100Call it a second time to confirm cache reuse:
axo fetch "https://api.zbdpay.com/premium" --max-sats 100When 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.