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
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
# 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:
| Status | Description |
|---|
| 402 | Payment required - returns requirements |
| 400 | Invalid payment payload |
| 503 | Facilitator 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 Case | Price | Atomic Units |
|---|
| API call | $0.01 | 10000 |
| Premium feature | $0.10 | 100000 |
| Large query | $1.00 | 1000000 |
| Micro-transaction | $0.001 | 1000 |