Skip to main content

Server Integration

Add payment protection to your API endpoints with x402.

Installation

npm install @x402/core @x402/next @x402/fetch @x402/evm @agentokratia/x402-escrow viem

Basic Setup

import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
import { ExactEvmScheme } from '@x402/evm/exact/server';
import { EscrowScheme } from '@agentokratia/x402-escrow/server';

// Configure facilitator client with your API key
const facilitator = new HTTPFacilitatorClient({
  url: 'https://facilitator.agentokratia.com',
  createAuthHeaders: async () => ({
    verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
  }),
});

// Create escrow scheme (requires facilitator config)
const escrow = new EscrowScheme({ facilitator });

const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';

// Create x402 server with both exact and escrow support
const server = new x402ResourceServer(facilitator)
  .register('eip155:8453', new ExactEvmScheme())
  .register('eip155:8453', escrow);
The EscrowScheme server constructor requires { facilitator } config. This enables the scheme to fetch DEX quotes and auto-discover supported tokens.

Next.js with paymentProxy

Use @x402/next for Next.js applications with paymentProxy:
// middleware.ts
import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
import { ExactEvmScheme } from '@x402/evm/exact/server';
import { EscrowScheme } from '@agentokratia/x402-escrow/server';
import { paymentProxy } from '@x402/next';

const facilitator = new HTTPFacilitatorClient({
  url: 'https://facilitator.agentokratia.com',
  createAuthHeaders: async () => ({
    verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
  }),
});

const escrow = new EscrowScheme({ facilitator });

const USDC = '0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913';

const server = new x402ResourceServer(facilitator)
  .register('eip155:8453', new ExactEvmScheme())
  .register('eip155:8453', escrow);

// Auto-discovers supported tokens (USDC, WETH, DAI, USDT)
const escrowAccepts = await escrow.buildAccepts({
  network: 'eip155:8453',
  price: '$0.01',
  payTo: '0xYourWallet...',
  asset: USDC, // settlement token
});

export const middleware = paymentProxy({
  '/api/premium': {
    accepts: [
      { scheme: 'exact', network: 'eip155:8453',
        price: '$0.01', payTo: '0xYourWallet...' },
      ...escrowAccepts, // Adds USDC, WETH, DAI, USDT options
    ],
  },
}, server);
Multi-token support: The buildAccepts() method returns an array of payment options for each supported input token. Spreading ...escrowAccepts into your accepts array enables payments in USDC, WETH, DAI, and USDT. The receiver always gets USDC.

Express Middleware

Use @x402/express for Express.js applications:
import express from 'express';
import { paymentMiddleware } from '@x402/express';
import { x402ResourceServer, HTTPFacilitatorClient } from '@x402/core/server';
import { ExactEvmScheme } from '@x402/evm/exact/server';
import { EscrowScheme } from '@agentokratia/x402-escrow/server';

const app = express();

const facilitator = new HTTPFacilitatorClient({
  url: 'https://facilitator.agentokratia.com',
  createAuthHeaders: async () => ({
    verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
  }),
});

const escrow = new EscrowScheme({ facilitator });

const server = new x402ResourceServer(facilitator)
  .register('eip155:8453', new ExactEvmScheme())
  .register('eip155:8453', escrow);

// Get multi-token payment options
const escrowAccepts = await escrow.buildAccepts({
  network: 'eip155:8453',
  price: '$0.01',
  payTo: process.env.PAYMENT_ADDRESS!,
});

// Define payment-protected routes
app.use(paymentMiddleware({
  'GET /api/premium': {
    accepts: [
      { scheme: 'exact', network: 'eip155:8453',
        price: '$0.01', payTo: process.env.PAYMENT_ADDRESS! },
      ...escrowAccepts,
    ],
  },
}, server));

// Your route handlers
app.get('/api/premium', (req, res) => {
  res.json({ data: 'Premium content' });
});

app.listen(3000);

Dynamic Pricing (Custom API Routes)

For endpoints with per-request pricing (like tip amounts), use buildAcceptsResolved for eager quotes:
import { NextRequest, NextResponse } from 'next/server';
import { HTTPFacilitatorClient } from '@x402/core/server';
import { EscrowScheme, preprocessSwapPayload } from '@agentokratia/x402-escrow/server';

const facilitator = new HTTPFacilitatorClient({
  url: 'https://facilitator.agentokratia.com',
  createAuthHeaders: async () => ({
    verify: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
    settle: { Authorization: `Bearer ${process.env.X402_API_KEY}` },
  }),
});

const escrow = new EscrowScheme({ facilitator });

export async function GET(request: NextRequest) {
  const amount = request.nextUrl.searchParams.get('amount');
  const recipient = request.nextUrl.searchParams.get('to');
  const paymentSignature = request.headers.get('payment-signature');

  if (!paymentSignature) {
    // Fetch fresh DEX quotes with buildAcceptsResolved
    const accepts = await escrow.buildAcceptsResolved({
      network: 'eip155:8453',
      price: `$${amount}`,
      payTo: recipient,
    });

    const requirements = accepts.map((a) => ({
      scheme: a.scheme,
      network: a.network,
      asset: a.price.asset,
      amount: a.price.amount,
      payTo: a.payTo,
      maxTimeoutSeconds: 600,
      extra: a.price.extra || {},
    }));

    const response = NextResponse.json({ message: 'Payment required' }, { status: 402 });
    response.headers.set(
      'PAYMENT-REQUIRED',
      Buffer.from(JSON.stringify(requirements)).toString('base64')
    );
    return response;
  }

  // Process payment
  const payload = JSON.parse(Buffer.from(paymentSignature, 'base64').toString());
  const processed = preprocessSwapPayload({ x402Version: 2, ...payload });

  const verifyResult = await facilitator.verify(processed, processed.accepted);
  if (!verifyResult.isValid) {
    return NextResponse.json({ error: verifyResult.invalidReason }, { status: 402 });
  }

  const settleResult = await facilitator.settle(processed, processed.accepted);
  return NextResponse.json({ success: true, transaction: settleResult.transaction });
}
buildAccepts vs buildAcceptsResolved:
  • buildAccepts() returns lazy price functions, ideal for middleware where quotes are fetched on-demand
  • buildAcceptsResolved() returns eager quotes with actual DEX data, ideal for dynamic pricing APIs

Pricing Formats

The server accepts multiple price formats:
// Human-readable USD prices
price: '$0.01'       // 1 cent
price: '$1.00'       // 1 dollar
price: '$0.001'      // 0.1 cents

// Atomic units (6 decimals for USDC)
price: '10000'       // $0.01 (10000 / 10^6)
price: '1000000'     // $1.00

Multiple Networks

Support multiple networks by registering schemes:
const server = new x402ResourceServer(facilitator)
  .register('eip155:8453', new ExactEvmScheme())    // Base Mainnet
  .register('eip155:8453', escrow)
  .register('eip155:84532', new ExactEvmScheme())   // Base Sepolia
  .register('eip155:84532', escrow);

Environment Variables

.env
# Facilitator URL
FACILITATOR_URL=https://facilitator.agentokratia.com

# Your API key (from dashboard)
X402_API_KEY=x402_xxxxxxxxxxxxx

# Your receiving wallet
PAYMENT_ADDRESS=0xYourWalletAddress
Never commit API keys to version control. Use environment variables or a secrets manager.

Error Handling

The middleware automatically handles payment errors:
StatusDescription
402Payment required - returns requirements
400Invalid payment payload
503Facilitator unavailable
For custom error handling:
const server = new x402ResourceServer(facilitator)
  .register('eip155:8453', new ExactEvmScheme())
  .register('eip155:8453', escrow)
  .onError(async (ctx, error) => {
    console.error('Payment error:', error);
    // Custom error handling, alerting, etc.
  });

Testing

Use Base Sepolia testnet for development:
const escrowAccepts = await escrow.buildAccepts({
  network: 'eip155:84532', // Base Sepolia
  price: '$0.01',
  payTo: process.env.PAYMENT_ADDRESS!,
});

Pricing Examples

Use CasePriceAtomic Units
API call$0.0110000
Premium feature$0.10100000
Large query$1.001000000
Micro-transaction$0.0011000