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:

  1. User creates account → adds credit card → receives API key
  2. Client sends Authorization: Bearer sk-... on every request
  3. 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.

HeaderDirectionPurpose
PAYMENT-REQUIREDResponse (402)Base64-encoded JSON array of payment requirements
PAYMENT-SIGNATURERequest (retry)Base64-encoded JSON signed payment payload
PAYMENT-RESPONSEResponse (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.

402 response headers (example)
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.

FieldTypeDescription
schemestringAlways "exact" — amount must match exactly
networkstringCAIP-2 Algorand network ID (testnet genesis hash)
amountstringAtomic USDC units as decimal string
assetstringASA ID (10458941 for testnet USDC)
payTostringMerchant Algorand address (base32)
extraobjectname, decimals, feePayer facilitator address
maxTimeoutSecondsnumberQuote validity window

The extra.feePayer field indicates the GoPlausible facilitator will co-sign as fee payer in the atomic transaction group.

Decoded payment requirement
{
  "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 → payTo for exact amount

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:

ModeBehavior
Happy pathFull 402 → sign → settle → 200 with Groq content
Failed paymentSimulates facilitator rejection after signing
Payment timeoutSimulates facilitator hang / 504
Invalid tokenSimulates 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

StatusMeaningClient action
402Payment requiredDecode quote, sign, retry
400Bad request / invalid payment headerFix payload; do not retry blindly
402 (retry)Quote expired or mismatchRe-request quote with same body
504Facilitator timeoutRetry after delay (retryable: true)
500Server error after paymentCheck logs; payment may or may not have settled

Client-side failure codes (PagePay UI maps these to friendly copy):

  • cancelled — user rejected Pera prompt
  • insufficient_funds — missing testnet USDC
  • signing_failed — Pera ARC-0001 error
  • verification_failed — facilitator rejected signature
  • quote_mismatch — document changed since quote
  • gateway_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:

PackageRole
@x402-avm/coreDecode requirements, create/encode payment payloads
@x402-avm/avmAlgorand exact scheme transaction construction
@perawallet/connectBrowser wallet connection + ARC-0001 signing
algosdkLow-level Algorand types (used internally)

See the Developers page for curl examples and the Integrations page for wallet-specific signing notes.