Documentation

Complete guide to ClaudePay and the x402 payment protocol

Introduction

What is x402?

The x402 protocol is a standardized HTTP-based payment protocol that enables seamless cryptocurrency payments for API requests. It extends the traditional HTTP 402 Payment Required status code to work with blockchain-based payments, making it easy to monetize APIs with crypto payments.

What is ClaudePay?

ClaudePay is a production-ready implementation of the x402 protocol built specifically for Solana blockchain (with EVM support in development). It provides both client and server libraries that are completely framework-agnostic, allowing you to integrate blockchain payments into any JavaScript/TypeScript application.

Key Concept: When a client makes a request to a paid endpoint, the server returns a 402 status with payment requirements. The client automatically handles payment execution, signs the transaction with their wallet, and retries the request with payment proof. The server verifies the payment and returns the requested resource.

How It Works

  1. Client Request: Client makes a request to a paid API endpoint
  2. 402 Response: Server returns HTTP 402 with payment requirements (amount, token, recipient)
  3. Payment Execution: Client automatically builds and signs a blockchain transaction
  4. Payment Proof: Client retries request with X-PAYMENT header containing transaction proof
  5. Verification: Server verifies payment with facilitator service
  6. Resource Delivery: Server processes request and returns the paid resource
  7. Settlement: Payment is settled and funds are transferred to treasury

Features

✅ Client-Side Payment Handling

Automatic 402 payment detection and transaction execution with any wallet provider

✅ Server-Side Verification

Built-in payment verification and settlement with facilitator services

✅ Framework Agnostic

Works with any wallet provider (Phantom, Privy, Solflare) and any HTTP framework (Express, Next.js, Fastify)

✅ TypeScript First

Full type safety with Zod validation and comprehensive TypeScript definitions

✅ Solana Native

Built on @solana/web3.js and @solana/spl-token with native USDC support

✅ EVM Support (Beta)

Growing support for Ethereum and EVM-compatible chains

Supported Networks

  • Solana Mainnet - Production network
  • Solana Devnet - Development and testing
  • EVM Chains (Beta) - Ethereum, Base, Polygon, etc.

Installation

NPM Package

bash
npm install x402-solana

Or with pnpm:

bash
pnpm add x402-solana

Or with yarn:

bash
yarn add x402-solana

Required Dependencies

The package has peer dependencies that you'll need to install:

bash
npm install @solana/web3.js @solana/spl-token zod
Note: The package supports @solana/web3.js v1.90.0+ and @solana/spl-token v0.4.0+

Quick Start

Client-Side Setup (React)

typescript
import { createX402Client } from 'x402-solana/client';
import { useSolanaWallets } from '@privy-io/react-auth/solana';

function MyComponent() {
  const { wallets } = useSolanaWallets();
  const wallet = wallets[0];

  // Create x402 client
  const client = createX402Client({
    wallet,
    network: 'solana-devnet',
    maxPaymentAmount: BigInt(10_000_000), // Optional: max 10 USDC
  });

  // Make a paid request - automatically handles 402 payments
  const response = await client.fetch('/api/paid-endpoint', {
    method: 'POST',
    body: JSON.stringify({ data: 'your request' }),
  });

  const result = await response.json();
}

Server-Side Setup (Next.js API Route)

typescript
import { NextRequest, NextResponse } from 'next/server';
import { X402PaymentHandler } from 'x402-solana/server';

const x402 = new X402PaymentHandler({
  network: 'solana-devnet',
  treasuryAddress: process.env.TREASURY_WALLET_ADDRESS!,
  facilitatorUrl: 'https://facilitator.payai.network',
});

export async function POST(req: NextRequest) {
  // 1. Extract payment header
  const paymentHeader = x402.extractPayment(req.headers);
  
  // 2. Create payment requirements
  const paymentRequirements = await x402.createPaymentRequirements({
    price: {
      amount: "2500000",  // $2.50 USDC (in micro-units, as string)
      asset: {
        address: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
      }
    },
    network: 'solana-devnet',
    config: {
      description: 'AI Chat Request',
      resource: `${process.env.NEXT_PUBLIC_BASE_URL}/api/chat`,
    }
  });
  
  if (!paymentHeader) {
    // Return 402 with payment requirements
    const response = x402.create402Response(paymentRequirements);
    return NextResponse.json(response.body, { status: response.status });
  }

  // 3. Verify payment
  const verified = await x402.verifyPayment(paymentHeader, paymentRequirements);
  if (!verified) {
    return NextResponse.json({ error: 'Invalid payment' }, { status: 402 });
  }

  // 4. Process your business logic
  const result = await yourBusinessLogic(req);

  // 5. Settle payment
  await x402.settlePayment(paymentHeader, paymentRequirements);

  // 6. Return response
  return NextResponse.json(result);
}

Server-Side Setup (Express)

typescript
import express from 'express';
import { X402PaymentHandler } from 'x402-solana/server';

const app = express();
const x402 = new X402PaymentHandler({
  network: 'solana-devnet',
  treasuryAddress: process.env.TREASURY_WALLET_ADDRESS!,
  facilitatorUrl: 'https://facilitator.payai.network',
});

app.post('/api/paid-endpoint', async (req, res) => {
  const paymentHeader = x402.extractPayment(req.headers);
  
  const paymentRequirements = await x402.createPaymentRequirements({
    price: {
      amount: "2500000",
      asset: {
        address: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
      }
    },
    network: 'solana-devnet',
    config: {
      description: 'API Request',
      resource: `${process.env.BASE_URL}/api/paid-endpoint`,
    }
  });
  
  if (!paymentHeader) {
    const response = x402.create402Response(paymentRequirements);
    return res.status(response.status).json(response.body);
  }

  const verified = await x402.verifyPayment(paymentHeader, paymentRequirements);
  if (!verified) {
    return res.status(402).json({ error: 'Invalid payment' });
  }

  const result = await yourBusinessLogic(req);
  await x402.settlePayment(paymentHeader, paymentRequirements);

  res.json(result);
});

Client API Reference

createX402Client(config)

Creates a new x402 client instance with automatic payment handling.

Configuration Options

Property Type Required Description
wallet WalletAdapter Yes Wallet instance with signTransaction method
network 'solana' | 'solana-devnet' Yes Blockchain network to use
rpcUrl string No Custom RPC endpoint URL
maxPaymentAmount bigint No Maximum payment amount in micro-units (safety limit)

Wallet Adapter Interface

The client works with any wallet that implements:

typescript
interface WalletAdapter {
  address: string;
  signTransaction: (tx: VersionedTransaction) => Promise<VersionedTransaction>;
}

Compatible wallets include:

  • Privy wallets (useSolanaWallets())
  • Phantom SDK
  • Solflare SDK
  • Any wallet with signTransaction method

Methods

client.fetch(input, init)

Make a fetch request with automatic 402 payment handling. Uses the same API as the standard Fetch API.

typescript
const response = await client.fetch('/api/endpoint', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ data: 'your data' })
});

const data = await response.json();

Server API Reference

X402PaymentHandler

Main class for handling x402 payments on the server side.

Constructor Options

Property Type Required Description
network 'solana' | 'solana-devnet' Yes Blockchain network
treasuryAddress string Yes Wallet address to receive payments
facilitatorUrl string Yes Facilitator service URL
rpcUrl string No Custom RPC endpoint URL
defaultToken object No Default token configuration (auto-detected if not provided)
middlewareConfig object No Middleware configuration options

Methods

extractPayment(headers)

Extract the X-PAYMENT header from HTTP request headers.

typescript
const paymentHeader = x402.extractPayment(req.headers);
// Returns: string | null

createPaymentRequirements(routeConfig)

Create payment requirements object using x402 RouteConfig format.

typescript
const requirements = await x402.createPaymentRequirements({
  price: {
    amount: "2500000",  // Amount as string in micro-units
    asset: {
      address: "4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU"
    }
  },
  network: 'solana-devnet',
  config: {
    description: 'Payment description',
    resource: 'https://example.com/api/endpoint',
    mimeType: 'application/json',  // Optional
    maxTimeoutSeconds: 300,         // Optional
  }
});

create402Response(requirements)

Create a 402 Payment Required response with payment requirements.

typescript
const response = x402.create402Response(paymentRequirements);
// Returns: { status: 402, body: {...} }

verifyPayment(header, requirements)

Verify payment with the facilitator service.

typescript
const isValid = await x402.verifyPayment(paymentHeader, requirements);
// Returns: Promise<boolean>

settlePayment(header, requirements)

Settle payment and transfer funds to treasury.

typescript
await x402.settlePayment(paymentHeader, requirements);
// Returns: Promise<void>

RouteConfig Format

The x402 protocol uses a standardized RouteConfig format:

typescript
interface RouteConfig {
  price: {
    amount: string;           // Payment amount in token micro-units
    asset: {
      address: string;        // Token mint address (e.g., USDC)
    }
  },
  network: 'solana' | 'solana-devnet';
  config: {
    description: string;      // Human-readable description
    resource: string;         // API endpoint URL
    mimeType?: string;        // Response MIME type (default: 'application/json')
    maxTimeoutSeconds?: number; // Timeout (default: 300)
    outputSchema?: object;    // Optional JSON schema for response
  }
}

Configuration

Environment Variables

bash
# Network (optional, defaults to devnet)
NEXT_PUBLIC_NETWORK=solana-devnet

# Treasury wallet address (where payments are sent)
TREASURY_WALLET_ADDRESS=your_treasury_address

# Facilitator service URL
FACILITATOR_URL=https://facilitator.payai.network

# Optional: Custom RPC URLs
NEXT_PUBLIC_SOLANA_RPC_DEVNET=https://api.devnet.solana.com
NEXT_PUBLIC_SOLANA_RPC_MAINNET=https://api.mainnet-beta.solana.com

# Base URL for resource field
NEXT_PUBLIC_BASE_URL=http://localhost:3000

USDC Token Addresses

When creating payment requirements, specify the appropriate USDC mint address:

Network USDC Mint Address
Solana Devnet 4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU
Solana Mainnet EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v

Environment-Based Token Selection

typescript
const USDC_MINT = process.env.NODE_ENV === 'production'
  ? 'EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v'  // mainnet
  : '4zMMC9srt5Ri5X14GAgXhaHii3GnPAEERYPJgZJDncDU'; // devnet

Payment Amounts

Payment amounts are specified in USDC micro-units (6 decimals) as strings:

  • 1 USDC = "1000000" micro-units
  • $0.01 = "10000" micro-units
  • $2.50 = "2500000" micro-units

Helper Functions

typescript
import { usdToMicroUsdc, microUsdcToUsd } from 'x402-solana/utils';

// Convert USD to micro-units
const microUnits = usdToMicroUsdc(2.5);  // Returns: "2500000"

// Convert micro-units to USD
const usd = microUsdcToUsd("2500000");   // Returns: 2.5

RPC Endpoints

Default RPC endpoints:

  • Devnet: https://api.devnet.solana.com
  • Mainnet: https://api.mainnet-beta.solana.com
Production Tip: For production deployments, use a dedicated RPC provider like Helius, QuickNode, or Alchemy for better reliability and performance.

Deployment Guide

Deploy to Render

Prerequisites

  • Render account (sign up at render.com)
  • Anthropic API key (for Claude AI features)
  • Solana wallet address (treasury)
  • GitHub repository

Quick Deploy via Blueprint

  1. Push to GitHub:
bash
git init
git add .
git commit -m "Initial commit"
git remote add origin https://github.com/YOUR_USERNAME/claudepay.git
git push -u origin main
  1. Deploy on Render:
  • Go to dashboard.render.com
  • Click New → Blueprint
  • Connect your GitHub repository
  • Render will detect render.yaml and create services
  1. Set Environment Secrets:
  • Navigate to your API service settings
  • Go to Environment tab
  • Add required secret variables:
env
ANTHROPIC_API_KEY=sk-ant-YOUR_KEY_HERE
TREASURY_ADDRESS=YOUR_SOLANA_WALLET_ADDRESS
  1. Update API URL: After deployment, update your frontend to use the deployed API URL

Environment Variables for Deployment

Variable Required Description
ANTHROPIC_API_KEY Yes Claude API key for AI features
TREASURY_ADDRESS Yes Solana wallet to receive payments
NETWORK No Default: solana-devnet
WEB_ORIGIN No CORS origin for web frontend
PORT No Default: 3001
Free Tier Note: Render's free tier will sleep after 15 minutes of inactivity. The first request after sleep takes ~30s to wake up. Upgrade to a paid plan for always-on service.

Deploy to Vercel (Next.js)

  1. Push your code to GitHub
  2. Connect your repository to Vercel
  3. Add environment variables in Vercel dashboard
  4. Deploy automatically on push to main

Deploy with Docker

dockerfile
FROM node:18-alpine

WORKDIR /app

COPY package*.json ./
RUN npm install

COPY . .
RUN npm run build

EXPOSE 3001

CMD ["node", "server/index.js"]

Example Use Cases

AI API with Payments

typescript
// Server: Protected Claude AI endpoint
app.post('/api/chat', async (req, res) => {
  const paymentHeader = x402.extractPayment(req.headers);
  
  const requirements = await x402.createPaymentRequirements({
    price: {
      amount: "2500000",  // $2.50 per request
      asset: { address: USDC_MINT }
    },
    network: 'solana',
    config: {
      description: 'Claude AI Chat Request',
      resource: 'https://api.example.com/chat',
    }
  });
  
  if (!paymentHeader) {
    const response = x402.create402Response(requirements);
    return res.status(402).json(response.body);
  }
  
  const verified = await x402.verifyPayment(paymentHeader, requirements);
  if (!verified) {
    return res.status(402).json({ error: 'Invalid payment' });
  }
  
  // Call Claude API
  const result = await callClaudeAPI(req.body.message);
  
  await x402.settlePayment(paymentHeader, requirements);
  
  res.json({ response: result });
});

File Download with Payment

typescript
app.get('/api/download/:fileId', async (req, res) => {
  const paymentHeader = x402.extractPayment(req.headers);
  const { fileId } = req.params;
  
  const requirements = await x402.createPaymentRequirements({
    price: {
      amount: "1000000",  // $1.00 per download
      asset: { address: USDC_MINT }
    },
    network: 'solana',
    config: {
      description: 'File Download',
      resource: `https://api.example.com/download/${fileId}`,
      mimeType: 'application/octet-stream',
    }
  });
  
  if (!paymentHeader) {
    const response = x402.create402Response(requirements);
    return res.status(402).json(response.body);
  }
  
  const verified = await x402.verifyPayment(paymentHeader, requirements);
  if (!verified) {
    return res.status(402).json({ error: 'Invalid payment' });
  }
  
  // Serve file
  const fileStream = fs.createReadStream(`./files/${fileId}`);
  
  await x402.settlePayment(paymentHeader, requirements);
  
  res.setHeader('Content-Type', 'application/octet-stream');
  fileStream.pipe(res);
});

Premium API with Tiered Pricing

typescript
function getPriceForTier(tier: string): string {
  switch (tier) {
    case 'basic': return "100000";    // $0.10
    case 'pro': return "500000";      // $0.50
    case 'premium': return "2000000"; // $2.00
    default: return "100000";
  }
}

app.post('/api/service/:tier', async (req, res) => {
  const { tier } = req.params;
  const paymentHeader = x402.extractPayment(req.headers);
  
  const requirements = await x402.createPaymentRequirements({
    price: {
      amount: getPriceForTier(tier),
      asset: { address: USDC_MINT }
    },
    network: 'solana',
    config: {
      description: `${tier.toUpperCase()} API Access`,
      resource: `https://api.example.com/service/${tier}`,
    }
  });
  
  if (!paymentHeader) {
    const response = x402.create402Response(requirements);
    return res.status(402).json(response.body);
  }
  
  const verified = await x402.verifyPayment(paymentHeader, requirements);
  if (!verified) {
    return res.status(402).json({ error: 'Invalid payment' });
  }
  
  const result = await processServiceRequest(tier, req.body);
  
  await x402.settlePayment(paymentHeader, requirements);
  
  res.json(result);
});

Troubleshooting

Common Issues

Payment Verification Fails

  • Check network: Ensure client and server use same network (solana vs solana-devnet)
  • Verify token address: Confirm correct USDC mint address for the network
  • Facilitator URL: Ensure facilitator service is accessible
  • Transaction status: Check if transaction was confirmed on-chain

CORS Errors

  • Check origins: Verify WEB_ORIGIN environment variable matches your frontend URL exactly
  • Protocol: Include https:// or http:// in the origin
  • Port: Include port number if not using standard ports (80/443)

Wallet Connection Issues

  • Adapter interface: Ensure wallet implements signTransaction method
  • Network mismatch: Verify wallet is on correct network (devnet/mainnet)
  • Insufficient funds: Check wallet has enough SOL for fees and USDC for payment

Transaction Failures

  • RPC issues: Try a different RPC endpoint if transactions timeout
  • Fee payer: Ensure wallet has enough SOL for transaction fees (~0.000005 SOL)
  • Token account: Verify token account exists for the payment token

Debugging Tips

typescript
// Enable detailed logging on client
const client = createX402Client({
  wallet,
  network: 'solana-devnet',
  // Add custom fetch for logging
});

// Check facilitator status
const healthCheck = await fetch('https://facilitator.payai.network/health');
console.log(await healthCheck.json());

// Verify transaction on explorer
// Devnet: https://explorer.solana.com/?cluster=devnet
// Mainnet: https://explorer.solana.com/

Error Messages

Error Cause Solution
"Invalid payment" Payment verification failed Check transaction was confirmed, verify amounts match
"Wallet not connected" No wallet adapter provided Ensure wallet is connected before creating client
"Transaction failed" Blockchain transaction error Check RPC status, wallet balance, network congestion
"Payment exceeds limit" Amount > maxPaymentAmount Increase maxPaymentAmount or reduce payment requirement
Need Help? Open an issue on GitHub with detailed error messages and transaction signatures.

Architecture & Design

Project Structure

text
src/
├── client/                    # Client-side code
│   ├── transaction-builder.ts # Solana transaction construction
│   ├── payment-interceptor.ts # 402 payment fetch interceptor
│   ├── evm-transaction-builder.ts # EVM support (beta)
│   └── index.ts              # Main client export
├── server/                    # Server-side code
│   ├── facilitator-client.ts # Facilitator API communication
│   ├── payment-handler.ts    # Payment verification & settlement
│   └── index.ts              # Main server export
├── types/                     # TypeScript types
│   ├── x402-protocol.ts      # x402 spec types (Zod schemas)
│   ├── solana-payment.ts     # Solana-specific types
│   ├── evm-payment.ts        # EVM-specific types
│   └── index.ts
├── utils/                     # Utilities
│   ├── helpers.ts            # Helper functions
│   ├── evm-helpers.ts        # EVM utilities
│   └── index.ts
└── index.ts                   # Main package export

Payment Flow Diagram

text
Client                          Server                      Facilitator
  │                               │                              │
  ├── 1. Request paid resource ──>│                              │
  │                               │                              │
  │<── 2. 402 + Requirements ─────┤                              │
  │    (amount, token, recipient) │                              │
  │                               │                              │
  ├── 3. Build transaction        │                              │
  ├── 4. Sign with wallet         │                              │
  ├── 5. Submit to blockchain     │                              │
  │                               │                              │
  ├── 6. Retry with X-PAYMENT ───>│                              │
  │                               │                              │
  │                               ├── 7. Verify payment ────────>│
  │                               │<── 8. Confirmation ──────────┤
  │                               │                              │
  │                               ├── 9. Process request         │
  │                               │                              │
  │<── 10. Return resource ────────┤                              │
  │                               │                              │
  │                               ├── 11. Settle payment ───────>│
  │                               │<── 12. Transfer funds ───────┤
  │                               │    (to treasury)             │

Security Considerations

  • No Private Keys: Client never sends private keys; all signing happens locally
  • Payment Verification: Server verifies all payments with facilitator before processing
  • Amount Limits: Client can set maxPaymentAmount to prevent excessive charges
  • Treasury Control: Payments go directly to your specified treasury address
  • Transaction Replay: Each payment is tied to specific request parameters

Additional Resources

Documentation

Community & Support

Related Projects

Contributing: Contributions are welcome! Check out the GitHub repository to get started.

Frequently Asked Questions

Q: Is x402-solana production-ready?

A: The package is in beta (v0.1.1). It's being used in production but the API may change. Please test thoroughly and report any issues.

Q: What tokens are supported?

A: Currently, USDC is the primary supported token on Solana. The architecture supports any SPL token, and additional tokens may be added in future releases.

Q: Do I need to run my own facilitator?

A: No, you can use the public facilitator at https://facilitator.payai.network. However, you can run your own facilitator for additional control.

Q: What are the fees?

A: You pay standard Solana transaction fees (~$0.000005 per transaction). The facilitator may charge a small service fee. Check with your facilitator service for details.

Q: Can I use this with EVM chains?

A: EVM support is in beta. Basic functionality is available for Ethereum and EVM-compatible chains, but it's not as mature as Solana support yet.

Q: How do refunds work?

A: Refunds must be handled at the application level. The protocol itself doesn't include automatic refunds. You'll need to implement refund logic using standard blockchain transactions.

Q: Is the wallet connection secure?

A: Yes. The wallet never exposes private keys. All transaction signing happens locally in the user's wallet. Only signed transactions are transmitted.

Q: Can I customize the payment flow?

A: Yes. You can implement custom logic in the payment handler, adjust timeouts, add custom validation, and more. The package is designed to be flexible and extensible.