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.

HeaderDirectionContent
PAYMENT-REQUIREDServer → client, with the 402PaymentRequired: the resource and its offers
PAYMENT-SIGNATUREClient → server, on the retryPaymentPayload: the chosen offer and the signed payment
PAYMENT-RESPONSEServer → client, with the 200SettleResponse: 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

PAYMENT-REQUIRED (decoded)
{
  "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

PAYMENT-SIGNATURE (decoded)
{
  "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

EndpointTakesReturns
POST /verifyx402Version, paymentPayload, paymentRequirementsisValid, invalidReason, payer
POST /settlex402Version, paymentPayload, paymentRequirementssuccess, transaction, network, payer
GET /supportednothingkinds (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

inspect.ts
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

SchemeIdeaOn Axonpay
exactFixed price, one transfer per callSupported, and settled by Axonpay's facilitator
uptoAuthorize a ceiling, settle actual usagePlanned
batch-settlementPayment channel with cumulative vouchers, periodic payoutsPlanned