x402 Protocol Reference

HTTP 402 Payment Flow

The x402 protocol enables HTTP payments using blockchain transactions. Sigwei implements this protocol to monetize API access.

Standard Payment Flow

  1. Initial Request: Client requests PayGate URL without payment

    GET /abc123
  2. Payment Required: Server responds with HTTP 402 and payment token

    HTTP/1.1 402 Payment Required
    Content-Type: application/json
    
    {
      "x402": {
        "token": "payment_token_here",
        "amount": "0.01",
        "address": "0x742d35Cc6634C0532925a3b8c2414F4e456C10F4"
      }
    }
  3. Payment Execution: Client creates blockchain payment using wallet

  4. Payment Submission: Client retries request with payment proof

    GET /abc123
    X-Payment: <base64-encoded-payment-data>
  5. Payment Verification: Server verifies signature and blockchain transaction

  6. Access Granted: Client receives proxied response from target URL

Authentication + Payment Flow

For PayGates with requireAuth: true:

  1. Initial Request: Client requests without authentication

    GET /xyz789
  2. Authentication Required: Server returns 401

    HTTP/1.1 401 Unauthorized
    {
      "error": {
        "type": "authentication",
        "code": "AUTH_REQUIRED",
        "message": "This route requires user authentication."
      }
    }
  3. Authenticated Request: Client includes JWT token

    GET /xyz789
    Authorization: Bearer <jwt_token>
  4. Payment Required: Server returns 402 with payment requirements

  5. Final Request: Client includes both auth and payment

    GET /xyz789
    Authorization: Bearer <jwt_token>
    X-Payment: <payment_proof>

x402 Headers

Request Headers

X-Payment: <base64-encoded-payment-data>
Authorization: Bearer <jwt_token>  // Optional, for auth-required PayGates

Response Headers

X-Payment-Response: <payment-confirmation-data>  // Optional
X402-Version: 1
Content-Type: application/json

Payment Data Structure

The X-Payment header contains base64-encoded JSON with payment information:

{
  "x402Version": 1,
  "scheme": "exact",
  "network": "base-sepolia",
  "payload": {
    "signature": "0x1234567890abcdef...",
    "authorization": {
      "from": "0x742d35cc6634c0532925a3b8c2414f4e456c10f4",
      "to": "0x9876543210fedcba...",
      "value": "1000000",  // Amount in USDC microdollars (1 USDC = 1,000,000)
      "validAfter": "0",
      "validBefore": "1735689600",  // Unix timestamp
      "nonce": "0xabcdef1234567890..."  // 32-byte random nonce
    }
  }
}

Field Descriptions

Field
Description

x402Version

Protocol version (always 1)

scheme

Payment scheme (always "exact")

network

Blockchain network ("base-sepolia" or "base-mainnet")

signature

EIP-712 signature of the authorization

from

Payer's wallet address

to

Payment recipient address (from PayGate configuration)

value

Payment amount in USDC microdollars (6 decimals)

validAfter

Earliest valid timestamp (usually "0")

validBefore

Latest valid timestamp

nonce

Unique 32-byte identifier to prevent replay attacks

EIP-712 Typed Data Signature

Payments use EIP-712 structured signatures for security:

{
  "domain": {
    "name": "USD Coin",
    "version": "2",
    "chainId": 84532,  // Base Sepolia
    "verifyingContract": "0x036CbD53842c5426634e7929541eC2318f3dCF7e"  // USDC contract
  },
  "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" }
    ]
  },
  "primaryType": "TransferWithAuthorization",
  "message": {
    "from": "0x742d35cc6634c0532925a3b8c2414f4e456c10f4",
    "to": "0x9876543210fedcba...",
    "value": "1000000",
    "validAfter": "0",
    "validBefore": "1735689600",
    "nonce": "0xabcdef1234567890..."
  }
}

Network Configurations

Base Sepolia (Testnet)

  • Chain ID: 84532

  • USDC Contract: 0x036CbD53842c5426634e7929541eC2318f3dCF7e

  • RPC: https://sepolia.base.org

Base Mainnet

  • Chain ID: 8453

  • USDC Contract: 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913

  • RPC: https://mainnet.base.org

JavaScript Implementation Example

import { createWalletClient, http } from 'viem';
import { privateKeyToAccount } from 'viem/accounts';
import { baseSepolia } from 'viem/chains';

async function createPayment(paymentRequest, privateKey) {
  const account = privateKeyToAccount(privateKey);
  const walletClient = createWalletClient({
    account,
    chain: baseSepolia,
    transport: http()
  });

  // Generate payment authorization
  const authorization = {
    from: account.address,
    to: paymentRequest.address,
    value: (parseFloat(paymentRequest.amount) * 1e6).toString(), // Convert to microdollars
    validAfter: "0",
    validBefore: Math.floor(Date.now() / 1000) + 3600, // 1 hour validity
    nonce: "0x" + Array.from(crypto.getRandomValues(new Uint8Array(32)))
      .map(b => b.toString(16).padStart(2, '0')).join('')
  };

  // Sign with EIP-712
  const signature = await walletClient.signTypedData({
    domain: {
      name: 'USD Coin',
      version: '2',
      chainId: 84532,
      verifyingContract: '0x036CbD53842c5426634e7929541eC2318f3dCF7e'
    },
    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' }
      ]
    },
    primaryType: 'TransferWithAuthorization',
    message: authorization
  });

  // Create x402 payment data
  const paymentData = {
    x402Version: 1,
    scheme: "exact",
    network: "base-sepolia",
    payload: {
      signature: signature,
      authorization: authorization
    }
  };

  // Return base64-encoded payment header
  return btoa(JSON.stringify(paymentData));
}

// Usage with HTTP client
const paymentHeader = await createPayment(paymentRequest, "0xYOUR_PRIVATE_KEY");
const response = await fetch('/abc123', {
  headers: {
    'X-Payment': paymentHeader
  }
});

Error Handling

Common payment-related errors:

// Invalid signature
{
  "error": {
    "type": "payment",
    "code": "INVALID_SIGNATURE",
    "message": "Payment signature verification failed"
  }
}

// Insufficient amount
{
  "error": {
    "type": "payment", 
    "code": "INSUFFICIENT_AMOUNT",
    "message": "Payment amount is less than required"
  }
}

// Expired payment
{
  "error": {
    "type": "payment",
    "code": "PAYMENT_EXPIRED",
    "message": "Payment authorization has expired"
  }
}

// Already used nonce
{
  "error": {
    "type": "payment",
    "code": "NONCE_ALREADY_USED",
    "message": "Payment nonce has already been used"
  }
}

Client Libraries

For automatic x402 payment handling, use compatible HTTP clients:

  • JavaScript: x402-axios - Intercepts 402 responses and handles payments automatically

  • Python: x402-requests - Python requests library with x402 support

  • Go: Manual implementation or x402-compatible HTTP transport

  • cURL: Manual payment header creation for testing

These libraries abstract away the complexity of payment creation and signature handling, making x402 integration seamless for developers.

Last updated