@nerochain/x402-client
A fetch-API-compatible function that auto-handles 402 responses.
@nerochain/x402-client is the agent-side package. It returns a fetch-compatible function that transparently handles 402 by signing and retrying. The signer is pluggable; the package itself contains no scheme-specific logic.
Install
pnpm add @nerochain/x402-clientUsage
import { x402Fetch, readSettlementReceipt } from "@nerochain/x402-client";
import { aaNativeSigner } from "@nerochain/x402-aa";
const f = x402Fetch({
signer: aaNativeSigner({ /* ... */ }),
});
const res = await f("https://merchant/api/resource", {
method: "POST",
body,
});
const receipt = readSettlementReceipt(res);f is a drop-in for the global fetch. Anywhere you would call fetch(...), you can call f(...).
Options
type X402FetchOptions = {
signer: PaymentSigner;
maxRetries?: number; // default 1
fetchImpl?: typeof fetch; // default global fetch
selectRequirement?: (req: PaymentRequirements) => boolean;
};signer— the only required option. See the@nerochain/x402-aapage for the canonical implementation.maxRetries— caps the 402 → retry cycle to prevent infinite loops if a merchant is broken.fetchImpl— override the underlying fetch (useful for tests, custom timeouts, or alternative HTTP clients).selectRequirement— predicate that lets the agent reject specificaccepts[]entries. Use it to enforce caps ("only pay if amount ≤ X") or merchant allowlists.
How the retry loop works
1. await fetch(input, init)
2. status !== 402? -> return response
3. no PAYMENT-REQUIRED header? -> return response
4. decode header, find compatible accepts entry
5. await signer.buildPayload(entry, resource)
6. fetch(input, { ...init, headers: { ..., PAYMENT-SIGNATURE: payload } })
7. return responseThe loop runs at most maxRetries times. The default is 1 — exactly one retry per call. If the second response is still 402 (verification failed at the facilitator), x402Fetch returns it directly to the caller.
Reading the settlement receipt
const receipt = readSettlementReceipt(res);
if (receipt) {
console.log("settled at:", receipt.transactionHash);
console.log("amount: ", receipt.amount);
console.log("payer: ", receipt.payer);
}readSettlementReceipt(response) extracts and decodes the PAYMENT-RESPONSE header. Returns null if the header is missing or malformed; callers can treat that case as "the merchant served us without insisting on a receipt".
Axios integration
For codebases that already use axios, the package exposes an interceptor that retrofits the same 402 → sign → retry behavior onto an existing axios instance. Subpath import:
import axios from "axios";
import { attachX402 } from "@nerochain/x402-client/axios";
import { aaNativeSigner } from "@nerochain/x402-aa";
const client = axios.create({ baseURL: "https://merchant" });
attachX402(client, { signer: aaNativeSigner({ ... }) });
const res = await client.post("/api/llm", { prompt: "hi" });attachX402 registers a response interceptor pair (onFulfilled + onRejected) so it works whether the instance treats 402 as a fulfilled response (validateStatus: () => true) or rejects 402 as an error (the axios default). For the success path everywhere, set validateStatus: (s) => s < 500 on the instance.
axios is an optional peer dependency: install it explicitly when you import the subpath.
pnpm add axiosImplementing a custom signer
A PaymentSigner has two methods:
interface PaymentSigner {
schemes(): string[];
buildPayload(
requirement: PaymentRequirements,
resource?: ResourceInfo,
): Promise<PaymentPayload>;
}schemes() advertises which scheme strings this signer can satisfy. x402Fetch uses this to filter the merchant's accepts[] list before calling buildPayload.
buildPayload returns the full V2 envelope (x402Version, accepted, payload, extensions). The implementation is responsible for the inner payload shape, the cryptographic signing, and any external service interactions (paymaster, bundler, etc.).
The reference aa-native signer is @nerochain/x402-aa's aaNativeSigner. A new scheme would write a parallel signer following the same interface.