Getting started with Next.js
Start accepting x402 payments in your Next.js app in 2 minutes.
Step 1: Create a new app
Use your favorite package manager:
npm (npx)
npx @payai/x402-next-starter@latest my-server
pnpm
pnpm dlx @payai/x402-next-starter@latest my-server
bun
bunx @payai/x402-next-starter@latest my-server
The starter mirrors the upstream example and boostraps a ready-to-run NextJS app.
Step 2: Set your environment variables
Copy the example env and fill in your values (e.g. cp .env-local .env or cp env.example .env.local).
EVM_ADDRESS=0x... # EVM wallet address to receive payments
SVM_ADDRESS=... # Solana wallet address to receive payments
The starter uses @payai/facilitator which automatically connects to the PayAI facilitator — no URL configuration needed.
Step 3: Explore the app structure
The example uses a proxy for page routes and withX402 for API routes:
├── app/
│ ├── api/ # API routes (use withX402 for payment)
│ ├── protected/ # Protected page route
│ ├── layout.tsx
│ └── page.tsx
├── proxy.ts # x402 payment proxy (page routes)
├── next.config.ts
└── package.json
paymentProxy (in proxy.ts) protects page routes and returns a paywall when payment is required.
withX402 wraps individual API route handlers so payment is settled only after a successful response.
Step 4: Preview the example routes
Protected Page Route
The /protected page is protected using paymentProxy.
The proxy in proxy.ts configures the resource server, paywall, and protected routes:
// proxy.ts
import { paymentProxy } from "@x402/next" ;
import { x402ResourceServer , HTTPFacilitatorClient } from "@x402/core/server" ;
import { registerExactEvmScheme } from "@x402/evm/exact/server" ;
import { registerExactSvmScheme } from "@x402/svm/exact/server" ;
import { createPaywall } from "@x402/paywall" ;
import { evmPaywall } from "@x402/paywall/evm" ;
import { svmPaywall } from "@x402/paywall/svm" ;
import { facilitator } from "@payai/facilitator" ;
const facilitatorClient = new HTTPFacilitatorClient ( facilitator );
const server = new x402ResourceServer ( facilitatorClient );
// Register schemes
registerExactEvmScheme ( server );
registerExactSvmScheme ( server );
// Build paywall using builder pattern
const paywall = createPaywall ()
. withNetwork ( evmPaywall )
. withNetwork ( svmPaywall )
. withConfig ({
appName: "Next x402 Demo" ,
appLogo: "/x402-icon-blue.png" ,
testnet: true ,
})
. build ();
export const proxy = paymentProxy (
{
"/protected" : {
accepts: [
{
scheme: "exact" ,
price: "$0.001" ,
network: "eip155:84532" ,
payTo: evmAddress ,
},
{
scheme: "exact" ,
price: "$0.001" ,
network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" ,
payTo: svmAddress ,
},
],
description: "Premium music: x402 Remix" ,
mimeType: "text/html" ,
},
},
server ,
undefined , // paywallConfig (using custom paywall instead)
paywall , // custom paywall provider
);
export const config = {
matcher: [ "/protected/:path*" ],
};
Weather API Route (using withX402)
The /api/weather route demonstrates the withX402 wrapper for individual API routes:
// app/api/weather/route.ts
import { NextRequest , NextResponse } from "next/server" ;
import { withX402 } from "@x402/next" ;
import { server , paywall , evmAddress , svmAddress } from "../../../proxy" ;
const handler = async ( _ : NextRequest ) => {
return NextResponse . json ({
report: {
weather: "sunny" ,
temperature: 72 ,
},
});
};
export const GET = withX402 (
handler ,
{
accepts: [
{
scheme: "exact" ,
price: "$0.001" ,
network: "eip155:84532" ,
payTo: evmAddress ,
},
{
scheme: "exact" ,
price: "$0.001" ,
network: "solana:EtWTRABZaYq6iMfeYKouRu166VU2xqa1" ,
payTo: svmAddress ,
},
],
description: "Access to weather API" ,
mimeType: "application/json" ,
},
server ,
undefined , // paywallConfig (using custom paywall from proxy.ts)
paywall ,
);
paymentProxy vs withX402
The paymentProxy function is used to protect page routes. It can also protect API routes, however this will charge clients for failed API responses.
The withX402 function wraps API route handlers. This is the recommended approach to protect API routes as it guarantees payment settlement only AFTER successful API responses (status < 400).
Approach Use Case paymentProxyProtecting page routes or multiple routes with a single configuration withX402Protecting individual API routes where you need precise control over settlement timing
Step 5: Run the server
Your Next.js app is now accepting x402 payments!
Step 6: Test the server
The starter includes a built-in paywall at the home page. Navigate to http://localhost:3000 to test payments directly.
You can also test programmatically by following the fetch example or axios example .
Going to production
The starter works on the free tier out of the box — no API keys required.
When you’re ready for production, create a merchant account at merchant.payai.network , get your API keys, and add them to your .env:
PAYAI_API_KEY_ID=your-key-id
PAYAI_API_KEY_SECRET=your-key-secret
The @payai/facilitator package automatically detects these environment variables and authenticates your requests to the facilitator. See Facilitator Pricing for tier details and Facilitator Authentication for the full protocol reference.
x402 reference
For a deeper dive into message shapes, headers, verification and settlement responses, see the x402 Reference .
Need help?
Join our Community Have questions or want to connect with other developers? Join our Discord server.