402HTTP Payment Protocol

x402 Protocol Documentation

Enable AI agents to pay for your API resources using stablecoins over standard HTTP. PayZap acts as the facilitator — handling signature verification, gas, and on-chain settlement.

Overview

The x402 protocol extends HTTP with native payments using status code 402 Payment Required. When an AI agent requests a protected resource, the server responds with payment requirements. The agent signs an off-chain authorization, retries with a payment header, and the facilitator settles the transaction on-chain.

PayZap is an x402 facilitator. We verify EIP-712 signatures, submit on-chain transferWithAuthorization (ERC-3009) transactions, and cover gas fees. The merchant receives stablecoins directly — we never custody funds.

Gasless for buyers

Agents sign off-chain. PayZap submits and covers gas.

EIP-712 verified

Cryptographic verification before settlement.

Async settlement

Response is immediate. Settlement is background.

Protocol Flow

The x402 handshake happens in 5 steps. From the resource server's perspective, you only need to add middleware — the rest is handled by the agent and PayZap.

1

Agent → Server: Initial request

The agent requests your protected resource without a payment header.

GET /api/weather?city=london HTTP/1.1
Host: your-api.com
2

Server → Agent: 402 with PaymentRequirements

Your middleware returns payment requirements: price, token, chain, and facilitator URL.

HTTP/1.1 402 Payment Required
Content-Type: application/json

{
  "accepts": [{
    "scheme": "exact",
    "network": "eip155:8453",
    "maxAmountRequired": "10000",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "payTo": "0xYourWallet...",
    "maxTimeoutSeconds": 300,
    "extra": {
      "facilitator": "https://api.payzap.cc/x402/verify",
      "name": "PayZap",
      "version": "1.0"
    }
  }]
}
3

Agent: Sign ERC-3009 authorization

The agent signs a gasless ERC-3009 TransferWithAuthorization using EIP-712 typed data.

// Agent signs TransferWithAuthorization off-chain
const authorization = {
  from: agentWallet,
  to: "0xYourWallet...",
  value: "10000",  // 0.01 USDC (6 decimals)
  validAfter: 0,
  validBefore: deadline,
  nonce: randomBytes32()
};
const signature = await wallet.signTypedData(domain, types, authorization);
4

Agent → Server: Retry with X-PAYMENT header

The agent retries the original request with a base64-encoded payment payload in the X-PAYMENT header.

GET /api/weather?city=london HTTP/1.1
Host: your-api.com
X-PAYMENT: eyJ4NDAyVmVyc2lvbiI6MSwic2NoZW1l...
5

Server → Facilitator → Blockchain

Your middleware forwards the payment to PayZap. We verify the signature, enqueue the on-chain settlement, and return a receipt. Your handler runs immediately.

// Middleware forwards to PayZap facilitator
POST https://api.payzap.cc/x402/verify
{
  "paymentPayload": { ... },
  "paymentRequirements": { ... }
}

// PayZap verifies signature → enqueues settlement
// → transferWithAuthorization() on-chain
// → Merchant receives USDC

Middleware Setup

Add x402 payment protection to any Express endpoint with our middleware package.

npm install @payzap/x402-middleware

Express

server.ts
import express from 'express';
import { createPaywall } from '@payzap/x402-middleware';

const app = express();

// Configure the paywall
const paywall = createPaywall({
  facilitatorUrl: 'https://api.payzap.cc',
  payTo:          '0xYourWalletAddress',
  network:        'eip155:8453',   // Base mainnet
  asset:          '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913', // USDC on Base
  amountUsd:      0.01,            // Price per request
});

// Protect any route
app.get('/api/weather', paywall, (req, res) => {
  // This handler only runs after verified payment
  res.json({
    city: 'London',
    temp: 18,
    unit: 'celsius',
    receipt: req.x402Receipt, // Settlement receipt
  });
});

app.listen(3000);

createPaywall options

OptionTypeRequiredDescription
facilitatorUrlstringyesPayZap facilitator URL (https://api.payzap.cc)
payTostringyesYour wallet address (receives payments)
networkstringyesCAIP-2 chain ID (e.g. eip155:8453 for Base)
assetstringyesERC-20 token contract address
amountUsdnumberyesPrice per request in USD
maxTimeoutSecondsnumbernoPayment timeout (default: 300)
descriptionstringnoHuman-readable description of the resource
resourcestringnoResource identifier (default: request URL)

Testing with curl

# Step 1: Get the 402 response with payment requirements
curl -i https://your-api.com/api/weather?city=london
# → HTTP/1.1 402 Payment Required
# → {"accepts": [{"scheme":"exact","network":"eip155:8453",...}]}

# Step 2: Sign the payment off-chain (your agent does this)
# Step 3: Retry with the payment header
curl -H "X-PAYMENT: eyJ4NDAy..." https://your-api.com/api/weather?city=london
# → HTTP/1.1 200 OK
# → {"city":"London","temp":18,...}

Facilitator API

These are the endpoints that the middleware calls automatically. You typically don't call them directly, but they're documented here for custom integrations.

POST/x402/verify

Verify a payment signature and enqueue on-chain settlement. This is the core facilitator endpoint.

Request body

{
  "paymentPayload": {
    "x402Version": 1,
    "scheme": "exact",
    "network": "eip155:8453",
    "payload": {
      "signature": "0xabc123...",
      "authorization": {
        "from": "0xAgentWallet",
        "to": "0xMerchantWallet",
        "value": "10000",
        "validAfter": "0",
        "validBefore": "1710700000",
        "nonce": "0x..."
      }
    }
  },
  "paymentRequirements": {
    "scheme": "exact",
    "network": "eip155:8453",
    "maxAmountRequired": "10000",
    "resource": "/api/weather",
    "payTo": "0xMerchantWallet",
    "maxTimeoutSeconds": 300,
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
  }
}

Response (success)

{
  "success": true,
  "settlementId": "stl_abc123",
  "status": "submitted",
  "network": "eip155:8453"
}
GET/x402/settlement/:id

Check the status of a settlement. Useful for tracking if the on-chain transaction was confirmed.

Response

{
  "id": "stl_abc123",
  "status": "confirmed",
  "chainId": 8453,
  "caip2": "eip155:8453",
  "txHash": "0xdef456...",
  "fromAddress": "0xAgent...",
  "toAddress": "0xMerchant...",
  "amount": "10000",
  "amountUsd": "0.01",
  "feeAmount": "10",
  "createdAt": "2026-03-17T10:00:00Z",
  "settledAt": "2026-03-17T10:00:05Z"
}

Settlement statuses

submittedPayment verified, tx enqueued for on-chain submission
pendingTransaction submitted, waiting for block confirmation
confirmedTransaction confirmed on-chain, merchant received funds
failedSettlement failed (insufficient balance, reverted, etc.)
GET/x402/health

Returns facilitator status, supported chains, tokens, and current gas fund balances.

Agent Integration

If you're building an AI agent that needs to pay for x402-protected resources, here's how to implement the client-side flow.

agent-client.ts
import { createWalletClient, http } from 'viem';
import { base } from 'viem/chains';
import { privateKeyToAccount } from 'viem/accounts';

async function payForResource(url: string) {
  // 1. Make initial request
  const res = await fetch(url);

  if (res.status !== 402) return res;

  // 2. Parse payment requirements
  const { accepts } = await res.json();
  const req = accepts[0];

  // 3. Sign ERC-3009 TransferWithAuthorization
  const account = privateKeyToAccount('0x...');
  const wallet = createWalletClient({
    account, chain: base, transport: http()
  });

  const authorization = {
    from: account.address,
    to: req.payTo,
    value: req.maxAmountRequired,
    validAfter: '0',
    validBefore: String(
      Math.floor(Date.now() / 1000) + req.maxTimeoutSeconds
    ),
    nonce: `0x${crypto.randomBytes(32).toString('hex')}`,
  };

  const signature = await wallet.signTypedData({
    domain: { /* ERC-3009 token domain */ },
    types: { /* TransferWithAuthorization types */ },
    primaryType: 'TransferWithAuthorization',
    message: authorization,
  });

  // 4. Build and encode payment payload
  const payload = btoa(JSON.stringify({
    x402Version: 1,
    scheme: 'exact',
    network: req.network,
    payload: { signature, authorization },
  }));

  // 5. Retry with X-PAYMENT header
  return fetch(url, {
    headers: { 'X-PAYMENT': payload },
  });
}

Note: The agent wallet must hold the stablecoin (e.g., USDC) on the required chain. The agent does not need native tokens (ETH/MATIC) for gas — PayZap covers gas costs.

Supported Chains & Tokens

Networks

Base
eip155:8453
Arbitrum
eip155:42161
Polygon
eip155:137
TAC (Telegram)
eip155:2390
Base Sepolia (testnet)
eip155:84532

Stablecoins

UUSDC
ERC-3009
EEURC
ERC-3009
PPYUSD
ERC-3009
DDAI
ERC-2612

ERC-3009 — gasless transferWithAuthorization. The standard used by x402.
ERC-2612 — gasless permit + transferFrom. Fallback for tokens like DAI.

Pricing

PayZap charges 0.1% per settlement with a minimum fee of $0.001. No subscriptions, no monthly fees. Gas costs are included.

Payment amountFeeMerchant receives
$0.01$0.001 (min)$0.009
$1.00$0.001 (min)$0.999
$10.00$0.01$9.99
$100.00$0.10$99.90
$1,000.00$1.00$999.00

Need the PayZap REST API?

Products, payments, webhooks, merchant management — full API reference.

← API Documentation