Skip to main content

Next.js Integration

Start accepting x402 payments in your Next.js application in 2 minutes

Share
Last updated on August 20, 2026

Start accepting x402 payments in your Next.js application in 2 minutes.

Example Code

You can find the full code for this example on GitHub.

Step 1: Install Dependencies

Install the required packages for your Next.js application:

bash
npm install x402 next react react-dom

Or with other package managers:

bash
# pnpm
pnpm add x402 next react react-dom
 
# yarn
yarn add x402 next react react-dom
 
# bun
bun add x402 next react react-dom

Step 2: Set Your Environment Variables

Create a .env.local file in your project root:

bash
echo "ADDRESS=0x...\nFACILITATOR_URL=https://x402.bex.co\nNETWORK=sui\nBEX_API_KEY=your_api_key_here" > .env.local

Your .env.local file should look like this:

env
ADDRESS=0x... # wallet public address you want to receive payments to
FACILITATOR_URL=https://x402.bex.co
NETWORK=sui # recommended for fastest settlement
BEX_API_KEY=your_api_key_here # get from https://bex.co/dash/
Network Options

bex.co supports multiple networks:

  • sui (recommended for fastest settlement)
  • ethereum
  • base
  • polygon
  • avalanche

Step 3: Create Payment-Protected API Routes

Next.js uses a file-based routing system. Create API routes in the app/api directory (App Router) or pages/api directory (Pages Router).

Using App Router (Next.js 13+)

Create app/api/weather/route.ts:

typescript
import { NextRequest } from "next/server";
import { requirePayment } from "x402-nextjs";
 
const facilitatorUrl = process.env.FACILITATOR_URL!;
const payTo = process.env.ADDRESS! as `0x${string}`;
const network = process.env.NETWORK || "sui";
const apiKey = process.env.BEX_API_KEY!;
 
export const GET = requirePayment(
  {
    price: "$0.001",
    network,
  },
  payTo,
  {
    url: facilitatorUrl,
    apiKey,
  },
  async (request: NextRequest) => {
    return Response.json({
      report: {
        weather: "sunny",
        temperature: 70,
        location: "San Francisco",
      },
    });
  },
);

Create app/api/premium/content/route.ts:

typescript
import { NextRequest } from "next/server";
import { requirePayment } from "x402-nextjs";
 
const facilitatorUrl = process.env.FACILITATOR_URL!;
const payTo = process.env.ADDRESS! as `0x${string}`;
const network = process.env.NETWORK || "sui";
const apiKey = process.env.BEX_API_KEY!;
 
export const GET = requirePayment(
  {
    price: "$0.05",
    network,
  },
  payTo,
  {
    url: facilitatorUrl,
    apiKey,
  },
  async (request: NextRequest) => {
    return Response.json({
      content: "This is premium content",
      type: "article",
      timestamp: new Date().toISOString(),
    });
  },
);

Using Pages Router (Next.js 12 and below)

Create pages/api/weather.ts:

typescript
import type { NextApiRequest, NextApiResponse } from "next";
import { requirePayment } from "x402-nextjs/pages";
 
const facilitatorUrl = process.env.FACILITATOR_URL!;
const payTo = process.env.ADDRESS! as `0x${string}`;
const network = process.env.NETWORK || "sui";
const apiKey = process.env.BEX_API_KEY!;
 
async function handler(req: NextApiRequest, res: NextApiResponse) {
  return res.status(200).json({
    report: {
      weather: "sunny",
      temperature: 70,
      location: "San Francisco",
    },
  });
}
 
export default requirePayment(
  {
    price: "$0.001",
    network,
  },
  payTo,
  {
    url: facilitatorUrl,
    apiKey,
  },
  handler,
);

Step 4: Run the Development Server

Start your Next.js development server:

bash
npm run dev
Your Next.js application is now accepting x402 payments!

Your API routes will be available at:

  • http://localhost:3000/api/weather
  • http://localhost:3000/api/premium/content

Step 5: Test the Server

You can test payments against your API routes using HTTP clients like curl, Postman, or by building a client application.

Coming Soon

Client implementation guides for fetch API and axios will be available soon.

Manual Testing with curl

bash
# This will return a 402 Payment Required response
curl http://localhost:3000/api/weather
 
# The response will include payment details in headers

Payment Configuration Options

The requirePayment wrapper accepts flexible payment configurations:

Simple Dollar Amount

typescript
export const GET = requirePayment(
  {
    price: "$0.001",
    network: "sui",
  },
  payTo,
  {
    url: facilitatorUrl,
    apiKey,
  },
  async (request: NextRequest) => {
    return Response.json({ data: "Your data" });
  },
);

Token Amount with Specific Asset

typescript
export const GET = requirePayment(
  {
    price: {
      amount: "10000",
      asset: {
        address: "0x...", // Token contract address
        decimals: 6,
        name: "USDC",
      },
    },
    network: "sui",
  },
  payTo,
  {
    url: facilitatorUrl,
    apiKey,
  },
  async (request: NextRequest) => {
    return Response.json({ data: "Premium data" });
  },
);

Accessing Payment Information

typescript
export const GET = requirePayment(
  {
    price: "$0.001",
    network: "sui",
  },
  payTo,
  {
    url: facilitatorUrl,
    apiKey,
  },
  async (request: NextRequest) => {
    // Payment information is attached to the request
    const paymentData = (request as any).paymentData;
 
    return Response.json({
      data: "Your data",
      payment: {
        txHash: paymentData?.txHash,
        network: paymentData?.network,
      },
    });
  },
);

Advanced Features

Custom Payment Verification Callback

Add custom logic when payments are verified:

typescript
import { requirePayment } from "x402-nextjs";
 
export const GET = requirePayment(
  {
    price: "$0.001",
    network: "sui",
  },
  payTo,
  {
    url: facilitatorUrl,
    apiKey,
    onPaymentVerified: (paymentData) => {
      console.log("Payment verified:", paymentData.txHash);
      // Custom logging, analytics, or business logic
    },
  },
  async (request: NextRequest) => {
    return Response.json({ data: "Your data" });
  },
);

Error Handling

Create a custom error handler in app/api/error/route.ts:

typescript
import { NextRequest } from "next/server";
 
export async function GET(request: NextRequest) {
  return Response.json(
    {
      error: "Internal server error",
      timestamp: new Date().toISOString(),
    },
    { status: 500 },
  );
}

CORS Configuration

Enable CORS for your API routes using Next.js middleware.

Create middleware.ts in your project root:

typescript
import { NextResponse } from "next/server";
import type { NextRequest } from "next/server";
 
export function middleware(request: NextRequest) {
  const response = NextResponse.next();
 
  // Set CORS headers
  response.headers.set("Access-Control-Allow-Origin", "*");
  response.headers.set(
    "Access-Control-Allow-Methods",
    "GET, POST, PUT, DELETE, OPTIONS",
  );
  response.headers.set(
    "Access-Control-Allow-Headers",
    "Content-Type, Authorization",
  );
 
  // Handle preflight requests
  if (request.method === "OPTIONS") {
    return new NextResponse(null, { status: 200, headers: response.headers });
  }
 
  return response;
}
 
export const config = {
  matcher: "/api/:path*",
};

Environment-Specific Configuration

Create different configurations for development and production:

typescript
// lib/x402-config.ts
export const x402Config = {
  facilitator: {
    url: process.env.FACILITATOR_URL || "https://x402.bex.co",
    apiKey: process.env.BEX_API_KEY!,
  },
  network: process.env.NETWORK || "sui",
  payTo: process.env.ADDRESS! as `0x${string}`,
};
 
// Validate configuration
if (!x402Config.facilitator.apiKey || !x402Config.payTo) {
  throw new Error("Missing required x402 environment variables");
}

Then use it in your routes:

typescript
import { requirePayment } from "x402-nextjs";
import { x402Config } from "@/lib/x402-config";
 
export const GET = requirePayment(
  {
    price: "$0.001",
    network: x402Config.network,
  },
  x402Config.payTo,
  x402Config.facilitator,
  async (request: NextRequest) => {
    return Response.json({ data: "Your data" });
  },
);

Production Deployment

Before deploying to production:

  1. Switch to production network (e.g., sui instead of sui-testnet)
  2. Use environment variables for all sensitive data
  3. Enable HTTPS (handled by most hosting platforms)
  4. Set up proper error logging
  5. Configure CORS for your production domains
  6. Add rate limiting to prevent abuse

Deployment on Vercel

Next.js works seamlessly with Vercel. Set your environment variables in the Vercel dashboard:

  1. Go to your project settings
  2. Navigate to "Environment Variables"
  3. Add your variables:
    • ADDRESS
    • FACILITATOR_URL
    • NETWORK
    • BEX_API_KEY

Deployment on Other Platforms

For other platforms (Netlify, AWS, etc.), ensure your environment variables are set and your build command is:

bash
npm run build

Production Example

typescript
// app/api/data/route.ts
import { NextRequest } from "next/server";
import { requirePayment } from "x402-nextjs";
 
// Production configuration
const config = {
  facilitator: {
    url: "https://x402.bex.co",
    apiKey: process.env.BEX_API_KEY!,
    onPaymentVerified: (paymentData) => {
      // Log to your analytics service
      console.log("Payment verified:", paymentData.txHash);
    },
  },
  network: "sui", // Production Sui network
  payTo: process.env.ADDRESS! as `0x${string}`,
};
 
export const GET = requirePayment(
  {
    price: "$0.01",
    network: config.network,
  },
  config.payTo,
  config.facilitator,
  async (request: NextRequest) => {
    try {
      // Your business logic here
      const data = { content: "Protected data" };
 
      return Response.json({
        data,
        payment: {
          verified: true,
        },
      });
    } catch (error) {
      console.error("Error processing request:", error);
      return Response.json({ error: "Internal server error" }, { status: 500 });
    }
  },
);

Troubleshooting

Common Issues

Payment verification fails

  • Verify your BEX_API_KEY is correct in .env.local
  • Check that the wallet address format matches the network
  • Ensure the facilitator URL is accessible
  • Restart the Next.js dev server after changing environment variables

CORS errors

  • Add the middleware configuration as shown above
  • Check that the client origin is allowed
  • Verify CORS headers are being set correctly

Network mismatch

  • Ensure client and server use the same network
  • Check that the token address is valid for the network

Environment variables not loading

  • Use .env.local for local development
  • Restart the dev server after changes
  • Use NEXT_PUBLIC_ prefix only for client-side variables
  • Never expose sensitive keys (API keys) to the client

TypeScript errors

  • Ensure you have @types/node and @types/react installed
  • Check that your tsconfig.json is properly configured
  • Use type assertions for environment variables: process.env.VAR!

Why Choose Next.js?

Next.js is an excellent choice for x402 payment applications:

  • Full-stack framework: API routes + React frontend in one project
  • Server-side rendering: Optimal performance and SEO
  • File-based routing: Intuitive API route organization
  • Edge functions: Deploy globally with low latency
  • Vercel integration: Zero-config deployments
  • TypeScript support: First-class TypeScript experience

App Router vs Pages Router

Pros:

  • Modern React features (Server Components, Suspense)
  • Better performance and smaller bundle sizes
  • Improved routing and layouts
  • Built-in loading and error states

Use when:

  • Starting a new project
  • Want the latest Next.js features
  • Need advanced routing capabilities

Pages Router (Legacy)

Pros:

  • More mature and stable
  • Extensive community resources
  • Simpler mental model

Use when:

  • Maintaining an existing project
  • Need maximum stability
  • Team is familiar with older Next.js versions

Next Steps

Need Help?

Join Our Community

Have questions or want to connect with other developers?

Join Discord

One API key for 30+ chains

bex router is a single multi-chain gateway — one key, one bill, metered in compute units instead of an account per network.

Explore bex router