Reference
x402 primer
A short primer on the protocol Axonpay runs on: HTTP 402 Payment Required, made machine-readable.
On this page+
Three headers
HTTP reserved status 402 decades ago and never said how to use it. x402 fills the gap: a server answers 402 with offers, the client pays one of them and retries, and the server returns the resource with proof of settlement. In v2 everything travels in three headers, each base64-encoded JSON.
| Header | Direction | Content |
|---|---|---|
PAYMENT-REQUIRED | Server → client, with the 402 | PaymentRequired: the resource and its offers |
PAYMENT-SIGNATURE | Client → server, on the retry | PaymentPayload: the chosen offer and the signed payment |
PAYMENT-RESPONSE | Server → client, with the 200 | SettleResponse: success flag, transaction, network, payer |
Version 1 used X-PAYMENT and X-PAYMENT-RESPONSE and put the offers in the 402 body. v2 clients still read both.
PaymentRequired
{
"x402Version": 2,
"resource": {
"url": "https://seller.example.com/api/forecast?city=Lisbon",
"description": "One-day weather summary for a city",
"mimeType": "application/json"
},
"accepts": [
{
"scheme": "exact",
"network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": "10000",
"payTo": "SELLER_ADDRESS",
"maxTimeoutSeconds": 60,
"extra": { "feePayer": "FACILITATOR_FEE_PAYER" }
}
]
}PaymentPayload
{
"x402Version": 2,
"resource": { "url": "https://seller.example.com/api/forecast?city=Lisbon" },
"accepted": {
"scheme": "exact",
"network": "solana:5eykt4UsFv8P8NJdTREpY1vzqKqZKvdp",
"asset": "EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v",
"amount": "10000",
"payTo": "SELLER_ADDRESS",
"maxTimeoutSeconds": 60,
"extra": { "feePayer": "FACILITATOR_FEE_PAYER" }
},
"payload": { "transaction": "<base64 partially signed transaction>" }
}accepted is a verbatim copy of the offer the client chose. On Solana, payload.transaction is the versioned transaction described in Payment scheme, signed by the payer only.
Facilitator API
| Endpoint | Takes | Returns |
|---|---|---|
POST /verify | x402Version, paymentPayload, paymentRequirements | isValid, invalidReason, payer |
POST /settle | x402Version, paymentPayload, paymentRequirements | success, transaction, network, payer |
GET /supported | nothing | kinds (scheme + network pairs), extensions, signers |
Axonpay’s own facilitator serves these paths under https://axonpay.fun/api/facilitator, plus a /status endpoint. See Axonpay facilitator.
Read a price without paying
import { decodePaymentRequiredHeader } from "@x402/core/http";
// Ask for the resource without paying and read the price tag.
// (Axonpay's demo endpoint answers a real 402 and never settles.)
const res = await fetch("https://axonpay.fun/api/x402/demo");
if (res.status === 402) {
const header = res.headers.get("PAYMENT-REQUIRED");
if (!header) throw new Error("402 without a PAYMENT-REQUIRED header (x402 v1 puts it in the body)");
const { x402Version, resource, accepts } = decodePaymentRequiredHeader(header);
console.log(`x402 v${x402Version} · ${resource.url}`);
for (const option of accepts) {
console.log(option.scheme, option.network, option.amount, option.asset, "→", option.payTo);
}
}This is what the 402 Inspector in the dApp does for you, with a friendlier view of each offer. The demo endpoint at https://axonpay.fun/api/x402/demo answers a real 402 for 0.001 USDC and never settles, so it is safe to point any client at.
Schemes
| Scheme | Idea | On Axonpay |
|---|---|---|
exact | Fixed price, one transfer per call | Supported, and settled by Axonpay's facilitator |
upto | Authorize a ceiling, settle actual usage | Planned |
batch-settlement | Payment channel with cumulative vouchers, periodic payouts | Planned |