x402 protocol
Complete reference for HTTP 402 payment negotiation, x402 v2 headers, exact-AVM scheme, client retry flow, simulation modes, and error handling.
Overview
x402 revives HTTP 402 Payment Required as a first-class, machine-readable payment negotiation layer for APIs, agents, and automated clients.
Instead of returning 401 Unauthorized and forcing humans through OAuth or API key dashboards, an unpaid API call returns 402 with structured payment requirements. The client signs an on-chain payment, retries the same request with a payment header, and receives the protected resource only after settlement.
PagePay implements x402 version 2 with the exact-AVM scheme on Algorand Testnet. This document covers every header, field, state transition, and failure mode you will encounter integrating against PagePay or building a compatible client.
Why HTTP 402?
Traditional API monetization stacks billing as a separate concern:
- User creates account → adds credit card → receives API key
- Client sends
Authorization: Bearer sk-...on every request - Provider meters usage in a database and invoices monthly
x402 collapses steps 1–3 into the HTTP exchange itself:
Client Server
| POST /resource ------------> |
| <----------- 402 + quote |
| sign payment (wallet) |
| POST /resource + PAYMENT-SIG -> |
| <----------- 200 + resource |
Benefits for agentic workloads: AI agents can discover price, pay, and consume in one programmatic loop without human account setup. Benefits for developers: payment requirements are self-describing JSON — no separate pricing page scrape required.
Version 2 headers
x402 v2 standardizes three HTTP headers. PagePay uses lowercase header names in logs; HTTP is case-insensitive.
| Header | Direction | Purpose |
|---|---|---|
PAYMENT-REQUIRED | Response (402) | Base64-encoded JSON array of payment requirements |
PAYMENT-SIGNATURE | Request (retry) | Base64-encoded JSON signed payment payload |
PAYMENT-RESPONSE | Response (200) | Base64-encoded settlement metadata (txId, network, payer) |
Important: x402 v1 used X-Payment. PagePay and @x402-avm v2 use PAYMENT-SIGNATURE. Clients must not send legacy v1 headers.
HTTP/1.1 402 Payment Required
Content-Type: application/json
payment-required: eyJ4NDAyVmVyc2lvbiI6MiwicGF5bWVudE9wdGlvbnMiOltdfQ==
{
"x402Version": 2,
"accepts": [ /* payment requirement objects */ ],
"error": "Payment required"
}Payment requirement object
Each entry in the accepts array describes one valid way to pay. PagePay publishes a single exact-AVM requirement per quote.
| Field | Type | Description |
|---|---|---|
scheme | string | Always "exact" — amount must match exactly |
network | string | CAIP-2 Algorand network ID (testnet genesis hash) |
amount | string | Atomic USDC units as decimal string |
asset | string | ASA ID (10458941 for testnet USDC) |
payTo | string | Merchant Algorand address (base32) |
extra | object | name, decimals, feePayer facilitator address |
maxTimeoutSeconds | number | Quote validity window |
The extra.feePayer field indicates the GoPlausible facilitator will co-sign as fee payer in the atomic transaction group.
{
"scheme": "exact",
"network": "algorand:SGO1GKSzyE7IEPItTxCByw9x8FmnrCDexi9/cOUJOiI=",
"amount": "30000",
"asset": "10458941",
"payTo": "MERCHANT_ADDRESS_HERE",
"extra": {
"name": "USDC",
"decimals": 6,
"feePayer": "FACILITATOR_FEE_PAYER_ADDRESS"
},
"maxTimeoutSeconds": 300
}Client flow (step by step)
Step 1 — Unpaid request
Send the resource request with no payment header. Expect HTTP 402.
Step 2 — Decode quote
Base64-decode PAYMENT-REQUIRED. Parse JSON. Select the requirement matching your wallet network and asset.
Step 3 — Build transaction group
Using @x402-avm/avm, construct an atomic group:
- Slot 0: fee-payer placeholder (signed by facilitator at settle time)
- Slot 1: USDC axfer from payer →
payTofor exactamount
Step 4 — Sign with Pera
Pera Wallet signs slot 1 via ARC-0001 signTransaction. Use { txn, signers: [yourAddress] } for slots you sign.
Step 5 — Encode payment payload
Call createPaymentPayload() then encodePaymentSignatureHeader() from @x402-avm/core.
Step 6 — Retry request
Repeat the identical POST with PAYMENT-SIGNATURE header. Body must match the original request (same document hash / page count).
Step 7 — Verify response
On 200, decode PAYMENT-RESPONSE for txId. Confirm on Algorand explorer independently.
Protocol sandbox simulation modes
The /x402-demo page supports four client-side simulation modes that mock facilitator and server behavior without wallet funding:
| Mode | Behavior |
|---|---|
| Happy path | Full 402 → sign → settle → 200 with Groq content |
| Failed payment | Simulates facilitator rejection after signing |
| Payment timeout | Simulates facilitator hang / 504 |
| Invalid token | Simulates malformed PAYMENT-SIGNATURE rejection |
Test Mode runs entirely client-side with mocked HTTP exchanges. Run live x402 flow hits the real /api/x402-demo route and Groq when configured.
Use simulation modes to teach the protocol, test UI error states, and capture raw header payloads for documentation.
HTTP status codes & errors
| Status | Meaning | Client action |
|---|---|---|
| 402 | Payment required | Decode quote, sign, retry |
| 400 | Bad request / invalid payment header | Fix payload; do not retry blindly |
| 402 (retry) | Quote expired or mismatch | Re-request quote with same body |
| 504 | Facilitator timeout | Retry after delay (retryable: true) |
| 500 | Server error after payment | Check logs; payment may or may not have settled |
Client-side failure codes (PagePay UI maps these to friendly copy):
cancelled— user rejected Pera promptinsufficient_funds— missing testnet USDCsigning_failed— Pera ARC-0001 errorverification_failed— facilitator rejected signaturequote_mismatch— document changed since quotegateway_unavailable— facilitator unreachable
Full sequence diagram
┌────────┐ ┌────────┐ ┌─────────────┐ ┌──────────┐
│ Client │ │ API │ │ Facilitator │ │ Algorand │
└───┬────┘ └───┬────┘ └──────┬──────┘ └────┬─────┘
│ POST /summarize │ │ │
│──────────────────>│ │ │
│ 402 PAYMENT-REQ │ │ │
│<──────────────────│ │ │
│ sign USDC (Pera) │ │ │
│ POST + PAYMENT-SIG│ │ │
│──────────────────>│ POST /verify │ │
│ │────────────────────>│ │
│ │ POST /settle │ │
│ │────────────────────>│ submit txn group │
│ │ │─────────────────────>│
│ │ │ confirmed txId │
│ │<────────────────────│<─────────────────────│
│ 200 + summary │ │ │
│ PAYMENT-RESPONSE │ │ │
│<──────────────────│ │ │
Reference libraries
PagePay uses these packages — mirror them in your own client:
| Package | Role |
|---|---|
@x402-avm/core | Decode requirements, create/encode payment payloads |
@x402-avm/avm | Algorand exact scheme transaction construction |
@perawallet/connect | Browser wallet connection + ARC-0001 signing |
algosdk | Low-level Algorand types (used internally) |
See the Developers page for curl examples and the Integrations page for wallet-specific signing notes.