Skip to main content
Nuwa’s @nuwa-ai/x402 package layers AI-friendly ergonomics on top of the upstream coinbase/x402 reference implementation. It keeps your focus on business logic while handling payment requirements, facilitator calls, and settlement bookkeeping for both MCP tools and standard HTTP/gRPC gateways.

Modules at a glance

ImportPurpose
@nuwa-ai/x402/mcpcreatePaidMcpHandler bootstraps a paid MCP server from an initializer callback—ideal for Next.js App Router, Vercel Edge, or any fetch-compatible runtime.
@nuwa-ai/x402/llmX402LlmPayments & createPaymentPlugin guard HTTP endpoints by enforcing X-PAYMENT, verifying receipts, and appending X-PAYMENT-RESPONSE metadata.
TypesShared types such as FacilitatorConfig, PaymentRequirements, and RouteConfig mirror the latest x402 schemas for strongly typed facilitators.
Every helper runs the same x402 facilitator flow, so you can swap Coinbase CDP for a self-hosted verifier as long as it exposes /verify, /settle, /supported, and (optionally) /list.

Installation

pnpm add @nuwa-ai/x402
Bring @coinbase/x402, viem, and zod if you need facilitator utilities, key derivation, or schema validation:
pnpm add @coinbase/x402 viem zod
The SDK targets Node 18+ (Node 20 recommended) and assumes you can settle to a funded Base wallet. Default network is base-sepolia; set NETWORK=base in production.

Example: paid MCP tool

Next.js App Router example—mirrors the tutorial in xnuwa/x402-mcp.mdx:
import { facilitator } from "@coinbase/x402";
import { privateKeyToAccount } from "viem/accounts";
import z from "zod";
import {
  createPaidMcpHandler,
  type FacilitatorConfig,
} from "@nuwa-ai/x402/mcp";

const handler = createPaidMcpHandler(
  (server) => {
    server.paidTool(
      "generate_report",
      "Summarize a topic after payment clears.",
      { price: 0.002 }, // USD
      { topic: z.string() },
      {},
      async ({ topic }) => ({
        content: [{ type: "text", text: `Report for ${topic} (paid).` }],
      }),
    );
  },
  {
    serverInfo: { name: "nextjs-paid-mcp", version: "0.1.0" },
  },
  {
    recipient: privateKeyToAccount(
      process.env.SERVICE_PRIVATE_KEY as `0x${string}`,
    ).address,
    network: process.env.NETWORK === "base" ? "base" : "base-sepolia",
    facilitator: facilitator as unknown as FacilitatorConfig,
  },
);

export const GET = handler;
export const POST = handler;
  • Declare tools in the initializer callback; use server.paidTool for paid methods and server.tool for free ones.
  • Incoming calls lacking _meta["x402/payment"] receive a 402 response that echoes the accepts requirements you configured.
  • After verification and settlement, a successful response includes _meta["x402/payment-response"] so clients can reconcile spend.

Example: LLM proxy with receipts

Edge-friendly handler that forwards paid calls to OpenRouter:
import { facilitator } from "@coinbase/x402";
import { privateKeyToAccount } from "viem/accounts";
import { X402LlmPayments } from "@nuwa-ai/x402/llm";
import type { FacilitatorConfig } from "@nuwa-ai/x402/mcp";

const payments = new X402LlmPayments({
  facilitator: facilitator as unknown as FacilitatorConfig,
});

export async function POST(request: Request) {
  const seller = privateKeyToAccount(
    process.env.SERVICE_PRIVATE_KEY as `0x${string}`,
  );

  return payments.gateWithX402Payment(
    request,
    {
      price: 0.01, // USD
      network: process.env.NETWORK === "base" ? "base" : "base-sepolia",
      payTo: seller.address,
      config: {
        description: "OpenRouter proxy",
        mimeType: "application/json",
      },
    },
    async () => {
      return fetch("https://openrouter.ai/api/v1/chat/completions", {
        method: "POST",
        headers: {
          "Content-Type": "application/json",
          Authorization: `Bearer ${process.env.OPENROUTER_API_KEY}`,
        },
        body: await request.text(),
      });
    },
    {
      onSettle: ({ settlement }) => {
        if (settlement?.success) {
          console.info("Settled OpenRouter proxy call", settlement.transaction);
        }
      },
    },
  );
}
gateWithX402Payment validates the X-PAYMENT header, forwards the request once paid, and appends an X-PAYMENT-RESPONSE header containing the settlement transaction hash. Use the optional onSettle hook to report usage.

Facilitator configuration

Both modules accept a FacilitatorConfig with url and createAuthHeaders() that returns per-endpoint headers for /verify, /settle, /supported, and optionally /list. Coinbase’s @coinbase/x402 package already exposes a ready-to-use implementation (facilitator). If you roll your own verifier, implement the same shape.

Environment variables

VariableDescription
SERVICE_PRIVATE_KEY32-byte EVM key used to derive the payTo address for settlements. Server-side only.
NETWORKbase-sepolia (default) or base.
ALLOWED_ORIGINOptional CORS allow-list origin when exposing endpoints to browsers.
CDP_API_KEY_ID / CDP_API_KEY_SECRET / CDP_WALLET_SECRETRequired when using Coinbase CDP as your facilitator.
OPENROUTER_API_KEYNeeded if you proxy OpenRouter in the LLM example.
On mainnet, fund the derived address with USDC and monitor balances. The helpers settle before returning, so insufficient facilitator credit or wallet funds will keep the endpoint in a 402 challenge loop.

Roadmap & support

  • Tracking x402 v2 (upto scheme) for usage-based billing.
  • Additional facilitator adapters and dynamic pricing utilities.
Follow nuwa-protocol/nuwa-x402 for changelog updates and examples. See also (ERC8004): https://github.com/nuwa-protocol/nuwa-8004/tree/main