X402 Protocol + Payment Channels

Complete Integration Guide: Transform HTTP 402 from theory to reality with instant, cost-effective micropayments on Solana

Overview

A complete payment system that combines:

  • x402 Protocol: HTTP 402 Payment Required standard for micropayments
  • Payment Channels: Off-chain scaling solution for instant, gasless payments
  • Solana: High-performance blockchain for settlement

Result: APIs that accept payments as naturally as they handle authentication, with <10ms latency and $0 fees per payment.

The Problem This Solves

Traditional On-Chain Payments (scheme: 'exact')

Every API call → Blockchain transaction → 400-800ms latency → $0.0005 fee
❌ Too slow for real-time APIs
❌ Too expensive for sub-cent payments
❌ Can't scale to 100+ requests/minute

Payment Channels Solution (scheme: 'channel')

Setup: 1 on-chain transaction (open channel)
Usage: Unlimited off-chain payments → <10ms latency → $0 fees
Settle: 1 on-chain transaction (claim batch)

✅ 91% faster than on-chain
✅ 94% cheaper overall
✅ Scales to thousands of req/min

Quick Start: Add Payment Channels to Your x402 API

Step 1: Install the Package

npm install @x402-solana/core@latest

Version requirement: >= 0.3.0 (payment channels support)

Step 2: Update Your Server Code

Before (On-Chain Only):

import { TransactionVerifier } from '@x402-solana/core';

const verifier = new TransactionVerifier({
  rpcUrl: 'https://api.devnet.solana.com',
  commitment: 'confirmed',
});

// Only supports scheme: 'exact' (on-chain)

After (Hybrid: On-Chain + Channels):

import {
  TransactionVerifier,
  ChannelPaymentVerifier,  // ✨ NEW
  parseX402Payment,         // ✨ NEW
} from '@x402-solana/core';

// For on-chain payments (scheme: 'exact')
const onChainVerifier = new TransactionVerifier({
  rpcUrl: 'https://api.devnet.solana.com',
  commitment: 'confirmed',
});

// For payment channel payments (scheme: 'channel') ✨
const channelVerifier = new ChannelPaymentVerifier({
  connection: new Connection('https://api.devnet.solana.com'),
  programId: 'H8SsYx7Z8qp12AvaX8oEWDCHWo8JYmEK21zWLWcfW4Zc',
});

// Now your API supports BOTH payment methods!

Step 3: Handle Both Payment Types

app.get('/api/premium-data', async (req, res) => {
  const paymentHeader = req.headers['x-payment'];

  if (!paymentHeader) {
    // Return 402 with BOTH payment options
    return res.status(402).json({
      x402Version: 1,
      accepts: [
        {
          // Option 1: On-chain (slower, per-payment fees)
          scheme: 'exact',
          network: 'solana-devnet',
          payTo: 'YourUSDCTokenAccount...',
          maxAmountRequired: '100000', // $0.10
          asset: 'USDC',
        },
        {
          // Option 2: Payment channel (instant, zero fees) ✨
          scheme: 'channel',
          network: 'solana-devnet',
          payTo: 'YourServerWallet...',
          maxAmountRequired: '100000',
          asset: 'USDC',
          programId: 'H8SsYx7Z8qp12AvaX8oEWDCHWo8JYmEK21zWLWcfW4Zc',
        },
      ],
    });
  }

  // Parse the payment header
  const parsed = parseX402Payment(paymentHeader);
  if (!parsed.success || !parsed.payment) {
    return res.status(400).json({ error: 'Invalid payment header' });
  }

  // Route to appropriate verifier based on scheme
  let verificationResult;

  if (parsed.payment.scheme === 'exact') {
    // On-chain verification (400-800ms)
    const payload = parsed.payment.payload as any;
    verificationResult = await onChainVerifier.verifyPayment({
      signature: payload.transactionSignature,
      expectedRecipient: 'YourUSDCTokenAccount...',
      expectedAmountUSD: 0.10,
    });
  }
  else if (parsed.payment.scheme === 'channel') {
    // Channel verification (<10ms) ✨
    const payload = parsed.payment.payload as any;
    verificationResult = await channelVerifier.verifyChannelPayment(
      {
        channelId: payload.channelId,
        amount: payload.amount,
        nonce: payload.nonce,
        signature: payload.channelSignature,
        expiry: payload.expiry,
      },
      'YourServerWallet...',
      { minClaimIncrement: 1000n }
    );
  }

  if (!verificationResult.valid) {
    return res.status(402).json({ error: verificationResult.error });
  }

  // Payment verified! Return the premium data
  res.json({ data: 'Your premium API response' });
});

That's it! Your API now supports both payment methods, and clients can choose based on their usage pattern.

Package Ecosystem

Our payment channel solution consists of 4 packages that work together:

┌─────────────────────────────────────────────────────────────┐
│  Package Ecosystem                                          │
├─────────────────────────────────────────────────────────────┤
│                                                             │
│  1. @x402-solana/core (npm) ← Foundation                    │
│     └─ HTTP 402 protocol + on-chain payment verification    │
│                                                             │
│  2. @solana-payment-channel/core (local) ← Core Logic       │
│     └─ Payment channel management + off-chain signatures    │
│                                                             │
│  3. @solana-payment-channel/client (local) ← Browser SDK    │
│     └─ Automatic payment client + wallet integration        │
│                                                             │
│  4. @solana-payment-channel/server (local) ← Server SDK     │
│     └─ Express/Fastify/NestJS middleware                    │
└─────────────────────────────────────────────────────────────┘

@x402-solana/core (Foundation)

Basic HTTP 402 protocol with on-chain USDC verification.

npm install @x402-solana/core

When to use: Simple APIs with low request frequency (<10 req/min), or as fallback.

@solana-payment-channel/core (Core Logic)

Payment channel management, off-chain signatures, state management.

npm install @solana-payment-channel/core @solana/web3.js @coral-xyz/anchor

When to use: Building custom integrations, need full control over channel lifecycle.

@solana-payment-channel/client (Browser SDK)

Automatic payment client for browsers with wallet integration.

npm install @solana-payment-channel/client @solana/wallet-adapter-react

When to use: Building frontend apps, need automatic payment handling.

@solana-payment-channel/server (Server SDK)

Express/Fastify/NestJS middleware for automatic payment verification.

npm install @solana-payment-channel/server

When to use: Building Node.js servers, need plug-and-play payment protection.

Package Comparison

PackageUse CaseComplexitySetup Time
@x402-solana/coreBasic on-chain paymentsLow5 min
@solana-payment-channel/coreCustom channel logicMedium30 min
@solana-payment-channel/clientBrowser auto-payLow10 min
@solana-payment-channel/serverServer middlewareVery Low3 min

Real-World Performance Comparison

Based on test suite: 50 API Payments × $0.10 = $5.00 Total

MetricOn-Chain (exact)Channel (channel)Improvement
Total Cost$0.0250$0.001594% cheaper
Cost/Payment$0.0005$0.0000100% savings
Avg Latency2,019ms175ms91% faster
RPC Calls150696% fewer
On-Chain Txs50394% reduction

Payment Channel Program Features

Program ID: H8SsYx7Z8qp12AvaX8oEWDCHWo8JYmEK21zWLWcfW4Zc

1. open_channel - Lock funds, establish trust

pub fn open_channel(
    channel_id: [u8; 32],
    initial_deposit: u64,     // Micro-USDC (e.g., 5_000_000 = $5)
    expiry: i64,              // Unix timestamp
    credit_limit: u64,        // Optional overdraft (0-1000 USDC)
)
  • • Minimum deposit: 1 USDC (prevents spam)
  • • Maximum credit limit: 1000 USDC
  • • USDC locked in program-controlled PDA
  • • Emits ChannelOpened event

2. claim_payment - Server claims accumulated payments

pub fn claim_payment(
    amount: u64,              // Total claimed so far (cumulative)
    nonce: u64,               // Must increase monotonically
    client_signature: [u8; 64], // Ed25519 signature
)
  • • Ed25519 signature verification using domain separator
  • • Nonce protection: prevents replay (max increment: 10,000)
  • • Overdraft support: can claim up to deposit + credit_limit
  • • Batch claiming: 100s of payments → 1 transaction

3. add_funds - Top up without closing

pub fn add_funds(
    amount: u64,
)
  • • Auto debt settlement: if client has overdraft debt, payment goes to server first
  • • Remaining funds added to channel balance
  • • No need to close/reopen channel

4. close_channel - Reclaim remaining funds

pub fn close_channel()
  • • Client can close anytime (gets refund of unused funds)
  • • Anyone can close after expiry
  • • Cannot close with outstanding debt (must settle first)
  • • Returns remaining USDC to client

Complete Client Example

Client opens a channel, makes 50 payments, server claims once

import { ChannelManager, createPaymentAuthorizationV2 } from '@solana-payment-channel/core';
import { Connection, Keypair, PublicKey } from '@solana/web3.js';

const connection = new Connection('https://api.devnet.solana.com');
const clientWallet = Keypair.fromSecretKey(/* your secret */);
const serverPubkey = new PublicKey('ServerWallet...');

// Step 1: Open channel (1 on-chain tx, ~$0.0005)
const manager = new ChannelManager({
  rpcUrl: 'https://api.devnet.solana.com',
  programId: new PublicKey('H8SsYx7Z8qp12AvaX8oEWDCHWo8JYmEK21zWLWcfW4Zc'),
  usdcMint: new PublicKey('Gh9ZwEmdLJ8DscKNTkTqPbNwLNNBjuSzaG9Vp2KGtKJr'),
  network: 'devnet',
}, clientWallet);

const channelId = await manager.openChannel({
  serverPubkey,
  initialDeposit: BigInt(5_000_000), // $5.00
  // Optional: creditLimit: BigInt(1_000_000) // $1 overdraft
});

console.log('Channel opened:', channelId);

// Step 2: Make 50 API calls (all off-chain, $0 fees, <10ms each)
for (let i = 1; i <= 50; i++) {
  const cumulativeAmount = BigInt(i * 100_000); // $0.10 per call
  const nonce = BigInt(i);

  // Create signed authorization (off-chain, <1ms)
  const authorization = await createPaymentAuthorizationV2(
    new PublicKey(channelId),
    serverPubkey,
    cumulativeAmount,
    nonce,
    BigInt(Math.floor(Date.now() / 1000) + 3600), // 1 hour expiry
    clientWallet
  );

  // Make API call with X-PAYMENT header
  const response = await fetch('https://your-api.com/premium-data', {
    headers: {
      'X-Payment': createChannelPaymentHeader(
        channelId,
        cumulativeAmount.toString(),
        nonce.toString(),
        authorization.signature.toString('base64'),
        'solana-devnet',
      ),
    },
  });

  const data = await response.json();
  console.log(`Call ${i}/50: ${response.status}`, data);
}

// Step 3: Close channel when done (1 on-chain tx, ~$0.0005)
await manager.closeChannel(channelId);
console.log('Channel closed, unused funds returned');

Step-by-Step Integration Tutorials

Tutorial 1: Add Channels to Existing x402 API

Current state: You have an API using @x402-solana/core for on-chain payments
Goal: Support payment channels without breaking existing clients

// 1. Install latest version
npm install @x402-solana/core@latest

// 2. Import channel verifier
import { ChannelPaymentVerifier, parseX402Payment } from '@x402-solana/core';

// 3. Initialize verifier
const channelVerifier = new ChannelPaymentVerifier({
  connection: new Connection(process.env.SOLANA_RPC_URL),
  programId: process.env.CHANNEL_PROGRAM_ID,
});

// 4. Update payment endpoint
app.post('/api/verify-payment', async (req, res) => {
  const paymentHeader = req.headers['x-payment'];
  const parsed = parseX402Payment(paymentHeader);

  // Route based on scheme
  if (parsed.payment.scheme === 'channel') {
    // Use channel verifier (<10ms)
    const result = await channelVerifier.verifyChannelPayment(/*...*/);
  } else {
    // Use existing on-chain verifier (400-800ms)
    const result = await onChainVerifier.verifyPayment(/*...*/);
  }
});

Tutorial 2: Deploy Your Own Payment Channel Program

# 1. Clone the repo
git clone https://github.com/yourusername/solana-payment-channels
cd solana-payment-channels

# 2. Build the Anchor program
anchor build

# 3. Deploy to devnet
anchor deploy --provider.cluster devnet

# 4. Copy the program ID
# Output: Program Id: H8SsYx7Z8qp12AvaX8oEWDCHWo8JYmEK21zWLWcfW4Zc

# 5. Update your .env
echo "CHANNEL_PROGRAM_ID=H8SsYx7Z..." >> .env

# 6. Test it
npm test

Monitoring & Observability

Track Channel Performance

import { ChannelPaymentVerifier } from '@x402-solana/core';

const verifier = new ChannelPaymentVerifier(/*...*/);

// Add metrics tracking
app.use((req, res, next) => {
  const start = Date.now();
  res.on('finish', () => {
    const duration = Date.now() - start;
    const scheme = req.headers['x-payment'] ?
      parseX402Payment(req.headers['x-payment']).payment.scheme :
      'none';

    // Log to your metrics service
    metrics.histogram('api.payment.latency', duration, { scheme });
    metrics.increment('api.payment.count', { scheme });
  });
  next();
});

Solana Explorer Links

// Monitor channel state on-chain
const channelPDA = PublicKey.findProgramAddressSync(
  [Buffer.from('channel'), Buffer.from(channelId, 'hex')],
  new PublicKey(programId)
);

console.log(`View channel: https://explorer.solana.com/address/${channelPDA}?cluster=devnet`);

// Monitor claim transactions
console.log(`View claim: https://explorer.solana.com/tx/${claimSignature}?cluster=devnet`);

Common Issues & Solutions

Issue: "Channel not found on-chain"

Cause: Channel not opened yet or wrong program ID

Solution: Verify program ID matches deployment, ensure open_channel succeeded

Issue: "Invalid signature"

Cause: Message format mismatch between client signing and server verification

Solution: Both must use same message structure (109 bytes with domain separator)

Issue: "Nonce increment too large"

Cause: Nonce jumped >10,000 (anti-griefing protection)

Solution: Use sequential nonces (1, 2, 3...), don't skip

Issue: "Cannot close with debt"

Cause: Client has overdraft debt

Solution: Call add_funds to settle debt before close_channel

Resources

View Examples

Check out working examples for different frameworks

View Examples →

Architecture

Learn about the technical implementation

Read Architecture →

Payment Channels

Deep dive into payment channels on Solana

Learn More →

Hackathon Info

x402 Protocol in Solana Hackathon

Hackathon Details →

Program on Solana Explorer

View the deployed payment channel program:

H8SsYx7Z8qp12AvaX8oEWDCHWo8JYmEK21zWLWcfW4Zc