Introduction
How It Works

How It Works

The x402 payment protocol follows a four-phase flow: Challenge, Payment, Authorization, and Receipt.

Complete Flow Diagram

┌─────────────┐
│   Client    │
└──────┬──────┘

       │ 1. Initial Request (no auth)
       │ GET /api/weather

┌──────────────────────────────────────┐
│     Provider API + SDK Middleware    │
└──────┬───────────────────────────────┘

       │ 2. Forward to Gateway

┌──────────────────────────────────────┐
│      Preimage Research Gateway       │
│  - Check authorization               │
│  - Generate macaroon                 │
│  - Create payment challenge          │
└──────┬───────────────────────────────┘

       │ 3. Return 402 Payment Required
       │ + x402 challenge JSON

┌─────────────┐
│   Client    │
│  Parses:    │
│  - Macaroon │
│  - Payment  │
│    details  │
└──────┬──────┘

       │ 4. Sign USDC payments
       │ (EIP-3009 transferWithAuthorization)

       │ 5. Retry request with:
       │ Authorization: x402 <macaroon>:<payload1>:<payload2>

┌──────────────────────────────────────┐
│     Provider API + SDK Middleware    │
└──────┬───────────────────────────────┘

       │ 6. Forward authorization to Gateway

┌──────────────────────────────────────┐
│      Preimage Gateway                │
│  - Verify macaroon                   │
│  - Verify USDC payment signatures    │
│  - Submit to blockchain (via facilitator) 
│  - Generate JWS receipt              │
└──────┬───────────────────────────────┘

       │ 7. Return 200 OK + receipt

┌──────────────────────────────────────┐
│     Provider API + SDK Middleware    │
│  - Attach receipt to response        │
│  - Call API handler                  │
└──────┬───────────────────────────────┘

       │ 8. Return data + receipt
       │ Preimage-Research-Receipt: <JWS>

┌─────────────┐
│   Client    │
│  Success!   │
└─────────────┘

Phase 1: Challenge

When a client makes a request to a protected endpoint without authorization:

Request

GET /api/weather?city=SF HTTP/1.1
Host: api.example.com

Response: 402 Payment Required

HTTP/1.1 402 Payment Required
Content-Type: application/json
 
{
  "x402Version": 1,
  "accepts": [
    {
      "scheme": "exact",
      "network": "base",
      "maxAmountRequired": "950000",
      "resource": "https://api.example.com/api/weather",
      "description": "Provider payment",
      "payTo": "0xPROVIDER_WALLET",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
    },
    {
      "scheme": "exact",
      "network": "base",
      "maxAmountRequired": "50000",
      "resource": "https://api.example.com/api/weather",
      "description": "Platform fee (5% - Tier 1)",
      "payTo": "0xPLATFORM_WALLET",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913"
    }
  ],
  "macaroon": "AgETd2FsbGV0LWFkZHJlc3MFIDBFOTRBRjREOTg3MzI3MDFBRDZBQTA5RTI3NTNEOEU4QjcwMTAwMDAwMDAwMDAwMDAwMDAwMDAwMDAwMDAAAhZjYXZlYXQ6ZW5kcG9pbnQtaWQFHGEwZjZhMmYyLTdlMDEtNDE3YS04ZTVhLWZhYjE2ZDkxNTg4YgACFmNhdmVhdDpwcm92aWRlci1pZAUgZWQ4OGUzNGUtYzI0ZC00NjI2LWJhYTMtYjc3YWE0MzI2NDk3AAITamF2ZWF0OmV4cGlyeQUKMTczMjYzMDQzMgACAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA=",
  "providerId": "prov_abc123",
  "endpointId": "ep_xyz789",
  "requestId": "req_unique123"
}
💡

The macaroon is a time-limited authorization token. It contains the provider ID, endpoint ID, and expiry time, all cryptographically signed by the Gateway.

Challenge Components

  • accepts: Array of payment requirements (provider + platform)
  • macaroon: Base64-encoded authorization token with caveats
  • providerId: Your provider identifier
  • endpointId: The specific endpoint being accessed
  • requestId: Unique request identifier for idempotency

Phase 2: Payment

The client signs two USDC payments using EIP-3009 (transferWithAuthorization):

Payment 1: Provider

// Sign transfer authorization for provider payment
const signature1 = await wallet.signTypedData({
  domain: {
    name: 'USD Coin',
    version: '2',
    chainId: 8453,
    verifyingContract: '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913'
  },
  types: {
    TransferWithAuthorization: [
      { name: 'from', type: 'address' },
      { name: 'to', type: 'address' },
      { name: 'value', type: 'uint256' },
      { name: 'validAfter', type: 'uint256' },
      { name: 'validBefore', type: 'uint256' },
      { name: 'nonce', type: 'bytes32' }
    ]
  },
  message: {
    from: '0xBUYER_WALLET',
    to: '0xPROVIDER_WALLET',
    value: 950000n, // 0.95 USDC (95% for $1 payment - Tier 1)
    validAfter: 0n,
    validBefore: Math.floor(Date.now() / 1000) + 3600,
    nonce: randomBytes32()
  }
})

Payment 2: Platform Fee

// Sign transfer authorization for platform fee
const signature2 = await wallet.signTypedData({
  // ... same structure
  message: {
    from: '0xBUYER_WALLET',
    to: '0xPLATFORM_WALLET',
    value: 50000n, // 0.05 USDC (5% for $1 payment - Tier 1)
    // ...
  }
})
💡

Dynamic Fee Split: The actual split varies by payment tier:

  • $0.005-$0.009: 90/10 split (Ultra-Micro: 10% fee)
  • $0.01-$0.99: 95/5 split (Micropayments: 5% fee)
  • $1-$9.99: ~92-96% to provider (Standard: 3% + $0.05)
  • $10+: ~97% to provider (Large: 2.5% + $0.05)

View detailed pricing →

No funds leave your wallet yet! These are just cryptographic signatures. The actual USDC transfers happen on-chain only after the Gateway verifies and submits them.

Phase 3: Authorization

The client retries the request with the x402 Authorization header:

Request with Authorization

GET /api/weather?city=SF HTTP/1.1
Host: api.example.com
Authorization: x402 AgETd2FsbGV0LWFkZHJlc3MFIDBFOTRBRjREOTg3MzI3...:0xBUYER,0xPROVIDER,950000,0,1234567890,0xABCD...,0xSIG1...:0xBUYER,0xPLATFORM,50000,0,1234567890,0xEF01...,0xSIG2...

Authorization Header Format

Authorization: x402 <macaroon>:<payload1>:<payload2>

Where:

  • <macaroon>: Base64 macaroon from challenge
  • <payload1>: Provider payment (comma-separated: from,to,value,validAfter,validBefore,nonce,signature)
  • <payload2>: Platform payment (same format)

Gateway Verification

The Gateway:

  1. Verifies macaroon - Checks signature, expiry, provider ID, endpoint ID
  2. Verifies payment signatures - EIP-712 signature validation
  3. Checks payment amounts - Ensures payment >= required amount
  4. Submits to blockchain - Via x402 facilitator (non-custodial)
  5. Generates receipt - JWS-signed proof of payment

Phase 4: Receipt

If verification succeeds, the Gateway returns 200 OK with a signed receipt:

Response

HTTP/1.1 200 OK
Content-Type: application/json
Preimage-Receipt: eyJhbGciOiJFUzI1NiIsInR5cCI6IkpXVCJ9.eyJwYXltZW50SWQiOiJwYXlfYWJjMTIzIiwicHJvdmlkZXJJZCI6InByb3ZfeHl6Nzg5IiwiZW5kcG9pbnRJZCI6ImVwX3dlYXRoZXIiLCJ0b3RhbFVzZGMiOiIxMDAwIiwicHJvdmlkZXJVc2RjIjoiOTgwIiwicGxhdGZvcm1Vc2RjIjoiMjAiLCJ0aW1lc3RhbXAiOiIyMDI0LTAxLTE1VDEwOjMwOjAwWiJ9.Xq2Nm8hf9k3...
 
{
  "city": "SF",
  "temperature": 62,
  "conditions": "Partly cloudy"
}

Receipt Contents

Decode the JWT receipt to get:

{
  "paymentId": "pay_abc123",
  "providerId": "prov_xyz789",
  "endpointId": "ep_weather",
  "totalUsdc": "1000000",
  "providerUsdc": "950000",
  "platformUsdc": "50000",
  "tier": "micropayment",
  "effectiveRate": "0.05",
  "timestamp": "2024-01-15T10:30:00Z",
  "transactionHash": "0x789..."
}

Store receipts for accounting! They're cryptographically signed proof of payment, perfect for reconciliation and auditing.

Mock Mode

For testing without real blockchain transactions, all SDKs support mock mode:

Provider SDK (Mock Enabled)

createX402Middleware({
  gatewayUrl: 'http://localhost:8080',
  providerId: 'prov_test',
  mockPayments: true  // Skip real Gateway
})

Client Mock Request

// In mock mode, any request with this header succeeds
Authorization: x402 mock:mock

Mock mode:

  • ✅ Returns fake challenges
  • ✅ Accepts any x402 mock:mock authorization
  • ✅ Generates mock receipts
  • ✅ No network calls to Gateway
  • ✅ No blockchain transactions
⚠️

Mock mode is for testing only! Never use it in production. It bypasses all payment verification.

Security

Macaroons

Macaroons are like cookies but with:

  • Caveats - Embedded restrictions (expiry, endpoint, provider)
  • Cryptographic signatures - Can't be tampered with
  • Attenuation - Can add more restrictions, never remove them

EIP-3009

transferWithAuthorization enables:

  • Gasless transfers - Receiver pays gas, not sender
  • Expiry times - Signatures expire automatically
  • Nonce-based replay protection - Each signature is unique

JWS Receipts

Receipts are signed with ES256 (ECDSA P-256):

  • Verifiable - Anyone can verify with public key
  • Immutable - Can't be altered without detection
  • Non-repudiable - Gateway can't deny issuing them

Next Steps