x402 Protocol Reference

HTTP 402 Payment Flow

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

Multi-Chain Support: The x402 protocol supports both EVM (Ethereum Virtual Machine) networks like Base and Solana networks, providing a unified payment interface across multiple blockchains.

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 x402 protocol supports two payment payload structures: EVM and Solana.

EVM Payment Structure

The X-Payment header contains base64-encoded JSON with EVM 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
    }
  }
}

Solana Payment Structure

For Solana networks, the payment structure uses a pre-signed transaction:

{
  "x402Version": 1,
  "scheme": "exact",
  "network": "solana-devnet",
  "payload": {
    "transaction": "base64_encoded_solana_transaction"
  }
}

Key Differences from EVM:

  • No authorization object: Solana uses a pre-signed transaction instead

  • Transaction field: Contains a base64-encoded Solana transaction

  • Fee payer: The transaction includes a fee payer who co-signs the transaction

  • No EIP-712: Solana doesn't use EIP-712 typed signatures

EVM Field Descriptions

Field
Description

x402Version

Protocol version (always 1)

scheme

Payment scheme (always "exact")

network

Blockchain network (e.g., "base", "base-sepolia")

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

Solana Field Descriptions

Field
Description

x402Version

Protocol version (always 1)

scheme

Payment scheme (always "exact")

network

Blockchain network (e.g., "solana-devnet", "solana-mainnet")

transaction

Base64-encoded pre-signed Solana transaction

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

EVM Networks

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

Solana Networks

Solana Devnet

  • Network: solana-devnet

  • USDC Mint: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

  • RPC: https://api.devnet.solana.com

Solana Mainnet

  • Network: solana-mainnet

  • USDC Mint: EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

  • RPC: https://api.mainnet-beta.solana.com

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