Next.js Integration
The @shade402/nextjs package provides middleware and utilities for implementing X402 payment-protected routes in Next.js applications.
Installation
pnpm add @shade402/nextjs @shade402/coreSetup
Initialize Configuration
Initialize X402 in your Next.js application. Create a configuration file:
// lib/x402-config.ts
import { initX402 } from '@shade402/nextjs';
export function configureX402() {
if (typeof window === 'undefined') {
// Server-side only
initX402({
paymentAddress: process.env.PAYMENT_WALLET_ADDRESS!,
tokenMint: process.env.TOKEN_MINT!,
network: process.env.SOLANA_NETWORK || 'solana-devnet',
rpcUrl: process.env.SOLANA_RPC_URL,
autoVerify: true,
defaultAmount: '0.01',
paymentTimeout: 300,
});
}
}Call this in your API routes or middleware:
// middleware.ts or api route
import { configureX402 } from '@/lib/x402-config';
configureX402();API Routes
Protect API routes using the withPayment wrapper:
// app/api/premium-data/route.ts (App Router)
import { NextRequest, NextResponse } from 'next/server';
import { withPayment, X402HandlerContext } from '@shade402/nextjs';
export const GET = withPayment(
{
amount: '0.01',
description: 'Premium data access',
},
async (req: NextRequest, context: X402HandlerContext) => {
const payment = context.payment;
return NextResponse.json({
data: 'Premium content',
paymentId: payment?.paymentId,
});
}
);Pages Router
For Pages Router (app/pages directory):
// pages/api/premium-data.ts
import { NextApiRequest, NextApiResponse } from 'next';
import { withPayment, X402HandlerContext } from '@shade402/nextjs';
export default withPayment(
{
amount: '0.01',
description: 'Premium data access',
},
async (
req: NextApiRequest,
res: NextApiResponse,
context: X402HandlerContext
) => {
const payment = context.payment;
res.json({
data: 'Premium content',
paymentId: payment?.paymentId,
});
}
);Configuration Options
interface PaymentRequiredOptions {
amount: string; // Required payment amount
paymentAddress?: string; // Override global payment address
tokenMint?: string; // Override global token mint
network?: string; // Override global network
description?: string; // Payment description
expiresIn?: number; // Payment expiration in seconds
autoVerify?: boolean; // Enable automatic verification
}Accessing Payment Information
Payment information is available in the handler context:
import { withPayment, X402HandlerContext } from '@shade402/nextjs';
export const GET = withPayment(
{ amount: '0.01' },
async (req: NextRequest, context: X402HandlerContext) => {
const payment = context.payment;
if (!payment) {
return NextResponse.json(
{ error: 'Payment required' },
{ status: 402 }
);
}
return NextResponse.json({
paymentId: payment.paymentId,
amount: payment.actualAmount,
payer: payment.publicKey,
transactionHash: payment.transactionHash,
});
}
);Error Handling
The withPayment wrapper automatically handles errors and returns appropriate HTTP status codes:
402: Payment required
403: Payment verification failed
410: Payment expired
500: Internal server error
For custom error handling, you can catch errors in your handler:
export const GET = withPayment(
{ amount: '0.01' },
async (req: NextRequest, context: X402HandlerContext) => {
try {
// Your logic here
return NextResponse.json({ success: true });
} catch (error) {
return NextResponse.json(
{ error: 'Internal error' },
{ status: 500 }
);
}
}
);Multiple Payment Tiers
Implement different payment tiers:
// app/api/basic/route.ts
export const GET = withPayment(
{ amount: '0.001', description: 'Basic access' },
handler
);
// app/api/premium/route.ts
export const GET = withPayment(
{ amount: '0.01', description: 'Premium access' },
handler
);Environment Variables
Set up environment variables in .env.local:
PAYMENT_WALLET_ADDRESS=YourSolanaWalletAddress
TOKEN_MINT=EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v
SOLANA_NETWORK=solana-devnet
SOLANA_RPC_URL=https://api.devnet.solana.comComplete Example
// app/api/premium-data/route.ts
import { NextRequest, NextResponse } from 'next/server';
import { withPayment, X402HandlerContext } from '@shade402/nextjs';
import { configureX402 } from '@/lib/x402-config';
// Configure X402
configureX402();
export const GET = withPayment(
{
amount: '0.01',
description: 'Premium data access',
},
async (req: NextRequest, context: X402HandlerContext) => {
const payment = context.payment;
// Payment has been verified at this point
return NextResponse.json({
data: {
message: 'Premium data',
timestamp: new Date().toISOString(),
paymentId: payment?.paymentId,
},
});
}
);
export const POST = withPayment(
{
amount: '0.05',
description: 'Premium data write',
},
async (req: NextRequest, context: X402HandlerContext) => {
const body = await req.json();
const payment = context.payment;
// Process the request
return NextResponse.json({
success: true,
paymentId: payment?.paymentId,
processed: body,
});
}
);Client-side Integration
For client-side requests, use the @shade402/client package:
// app/components/PremiumData.tsx
'use client';
import { useEffect, useState } from 'react';
import { X402AutoClient } from '@shade402/client';
import { Keypair } from '@solana/web3.js';
export function PremiumData() {
const [data, setData] = useState(null);
const [loading, setLoading] = useState(true);
useEffect(() => {
async function fetchData() {
const wallet = Keypair.generate(); // In production, load from secure storage
const client = new X402AutoClient(wallet);
try {
const response = await client.get('/api/premium-data');
setData(response.data);
} catch (error) {
console.error('Error:', error);
} finally {
await client.close();
setLoading(false);
}
}
fetchData();
}, []);
if (loading) return <div>Loading...</div>;
return <div>{JSON.stringify(data)}</div>;
}Best Practices
Initialize X402 configuration in a shared utility file
Store sensitive configuration in environment variables
Use appropriate payment amounts for different routes
Enable automatic verification in production
Use TypeScript types for better type safety
Handle errors gracefully in your handlers
Consider rate limiting for payment-protected routes
Log payment transactions for audit purposes
Next Steps
Learn about Client Usage for making requests
Check out Express Integration for comparison
See Examples for more use cases
Last updated
