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.
How It Works
- Client Request: Client makes a request to a paid API endpoint
- 402 Response: Server returns HTTP 402 with payment requirements (amount, token, recipient)
- Payment Execution: Client automatically builds and signs a blockchain transaction
- Payment Proof: Client retries request with X-PAYMENT header containing transaction proof
- Verification: Server verifies payment with facilitator service
- Resource Delivery: Server processes request and returns the paid resource
- 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
npm install x402-solana
Or with pnpm:
pnpm add x402-solana
Or with yarn:
yarn add x402-solana
Required Dependencies
The package has peer dependencies that you'll need to install:
npm install @solana/web3.js @solana/spl-token zod
@solana/web3.js v1.90.0+ and @solana/spl-token v0.4.0+
Quick Start
Client-Side Setup (React)
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)
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)
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:
interface WalletAdapter {
address: string;
signTransaction: (tx: VersionedTransaction) => Promise<VersionedTransaction>;
}
Compatible wallets include:
- Privy wallets (
useSolanaWallets()) - Phantom SDK
- Solflare SDK
- Any wallet with
signTransactionmethod
Methods
client.fetch(input, init)
Make a fetch request with automatic 402 payment handling. Uses the same API as the standard Fetch API.
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.
const paymentHeader = x402.extractPayment(req.headers);
// Returns: string | null
createPaymentRequirements(routeConfig)
Create payment requirements object using x402 RouteConfig format.
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.
const response = x402.create402Response(paymentRequirements);
// Returns: { status: 402, body: {...} }
verifyPayment(header, requirements)
Verify payment with the facilitator service.
const isValid = await x402.verifyPayment(paymentHeader, requirements);
// Returns: Promise<boolean>
settlePayment(header, requirements)
Settle payment and transfer funds to treasury.
await x402.settlePayment(paymentHeader, requirements);
// Returns: Promise<void>
RouteConfig Format
The x402 protocol uses a standardized RouteConfig format:
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
# 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
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
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
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
- Push to GitHub:
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
- Deploy on Render:
- Go to dashboard.render.com
- Click New → Blueprint
- Connect your GitHub repository
- Render will detect
render.yamland create services
- Set Environment Secrets:
- Navigate to your API service settings
- Go to Environment tab
- Add required secret variables:
ANTHROPIC_API_KEY=sk-ant-YOUR_KEY_HERE
TREASURY_ADDRESS=YOUR_SOLANA_WALLET_ADDRESS
- 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 |
Deploy to Vercel (Next.js)
- Push your code to GitHub
- Connect your repository to Vercel
- Add environment variables in Vercel dashboard
- Deploy automatically on push to main
Deploy with Docker
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
// 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
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
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_ORIGINenvironment variable matches your frontend URL exactly - Protocol: Include
https://orhttp://in the origin - Port: Include port number if not using standard ports (80/443)
Wallet Connection Issues
- Adapter interface: Ensure wallet implements
signTransactionmethod - 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
// 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 |
Architecture & Design
Project Structure
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
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
- GitHub Issues: Report bugs or request features
- NPM Package: x402-solana
- Version: 0.1.1 (Beta)
Related Projects
- @solana/web3.js - Solana JavaScript SDK
- @solana/spl-token - SPL Token Program
- Zod - TypeScript schema validation
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.