Documentation Index
Fetch the complete documentation index at: https://docs.polygon.technology/llms.txt
Use this file to discover all available pages before exploring further.
This tutorial shows how to add x402 v2 payment middleware to your API or
service. By the end, buyers and AI agents will automatically pay in USDC when
accessing your protected endpoints.
These snippets are for demonstration only.
Store private keys and facilitator URLs in a secure vault. Never hardcode secrets.
Prerequisites
| Requirement | Example / Notes |
|---|
| Wallet to receive USDC | Any EVM-compatible wallet (Metamask, Rabby, Safe, etc.) |
| Node.js | Node.js 18+ with npm or Bun |
| Existing API / server | Express, Next.js, or Hono |
| Polygon network | Amoy testnet or mainnet |
This guide starts with Amoy testnet configuration. See
Running on Polygon mainnet when you are ready for
production.
Install dependencies
Wherever bun is used, replace it with npm or your preferred package manager.
bun install @x402/express @x402/core @x402/evm express
bun install @x402/next @x402/core @x402/evm
bun install @x402/hono @x402/core @x402/evm hono @hono/node-server
Add payment middleware
Integrate payment middleware with:
- A facilitator client pointing at the Polygon Amoy facilitator
- An
x402ResourceServer with the EVM scheme registered
- Route config using an
accepts array with scheme, price, network, and payTo
Full example in the x402 repo.import express from "express";
import { paymentMiddleware, x402ResourceServer } from "@x402/express";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";
const app = express();
const payTo = "0xYourEvmAddress";
const facilitatorClient = new HTTPFacilitatorClient({
url: process.env.FACILITATOR_URL || "https://x402-amoy.polygon.technology",
});
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "eip155:80002",
payTo,
},
],
description: "Get current weather data for any location",
mimeType: "application/json",
},
},
new x402ResourceServer(facilitatorClient).register(
"eip155:80002",
new ExactEvmScheme()
)
)
);
app.get("/weather", (_req, res) => {
res.send({
report: { weather: "sunny", temperature: 70 },
});
});
app.listen(4021, () => {
console.log("Server running at http://localhost:4021");
});
Full example in the x402 repo.Use withX402 for API routes. It settles payment only after a successful
response (status below 400).// lib/x402-server.ts
import { x402ResourceServer, HTTPFacilitatorClient } from "@x402/core/server";
import { ExactEvmScheme } from "@x402/evm/exact/server";
export const payTo = "0xYourEvmAddress";
const facilitatorClient = new HTTPFacilitatorClient({
url: process.env.FACILITATOR_URL || "https://x402-amoy.polygon.technology",
});
export const server = new x402ResourceServer(facilitatorClient).register(
"eip155:80002",
new ExactEvmScheme()
);
// app/api/weather/route.ts
import { NextRequest, NextResponse } from "next/server";
import { withX402 } from "@x402/next";
import { payTo, server } from "../../../lib/x402-server";
const handler = async (_: NextRequest) => {
return NextResponse.json(
{
report: { weather: "sunny", temperature: 72 },
},
{ status: 200 }
);
};
export const GET = withX402(
handler,
{
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "eip155:80002",
payTo,
},
],
description: "Access to weather API",
mimeType: "application/json",
},
server
);
Full example in the x402 repo.import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { paymentMiddleware, x402ResourceServer } from "@x402/hono";
import { ExactEvmScheme } from "@x402/evm/exact/server";
import { HTTPFacilitatorClient } from "@x402/core/server";
const app = new Hono();
const payTo = "0xYourEvmAddress";
const facilitatorClient = new HTTPFacilitatorClient({
url: process.env.FACILITATOR_URL || "https://x402-amoy.polygon.technology",
});
app.use(
paymentMiddleware(
{
"GET /weather": {
accepts: [
{
scheme: "exact",
price: "$0.001",
network: "eip155:80002",
payTo,
},
],
description: "Weather data",
mimeType: "application/json",
},
},
new x402ResourceServer(facilitatorClient).register(
"eip155:80002",
new ExactEvmScheme()
)
)
);
app.get("/weather", (c) => {
return c.json({
report: { weather: "sunny", temperature: 70 },
});
});
serve({ fetch: app.fetch, port: 4021 });
Buyers calling protected routes receive a 402 challenge, pay via the facilitator,
and then receive the response.
Running on Polygon mainnet
Once you have tested on Amoy, switch to mainnet:
1. Update the facilitator URL
const facilitatorClient = new HTTPFacilitatorClient({
url: "https://x402.polygon.technology",
});
2. Update the network identifier
Change eip155:80002 (Amoy) to eip155:137 (Polygon mainnet) in every
accepts entry and scheme registration:
// Testnet → Mainnet
network: "eip155:137",
// ...
server.register("eip155:137", new ExactEvmScheme());
Both Polygon facilitators run x402 v2. See
Using the Polygon Facilitator for signer
addresses and health endpoints.
Reference
Schema
| name | type | required | example | description |
|---|
payTo | string | yes | 0xYourAddress | Address that receives USDC |
network | string | yes | eip155:80002 | CAIP-2 network ID (Amoy or eip155:137 for mainnet) |
scheme | string | yes | "exact" | Payment scheme |
price | string | yes | "$0.001" | Cost per request in USDC |
FACILITATOR_URL | string | optional | "https://x402-amoy.polygon.technology" | Polygon facilitator endpoint |
description | string | optional | "Weather data" | Used for discoverability in x402 Bazaar |
mimeType | string | optional | "application/json" | Response content type |
Errors
| case / code | meaning | fix |
|---|
402_LOOP | Client cannot fulfill payment | Check facilitator URL, network ID, and wallet |
INVALID_NETWORK | Wrong network identifier | Use eip155:80002 (Amoy) or eip155:137 (mainnet) |
BAD_CONFIG | Missing route config | Define accepts, price, network, and payTo per route |
Do / Don’t Do Guardrails
| Do | Don’t |
|---|
Use https://x402-amoy.polygon.technology for Amoy testing | Use legacy x402-express against Polygon facilitators |
Use https://x402.polygon.technology for mainnet | Expose private keys in middleware |
| Test on Amoy before mainnet | Use V1 network strings like "polygon-amoy" or "polygon" |
Include description and mimeType for AI discoverability | Skip payTo in route config |
References