gate402-next
v0.2.1
Published
Plug-and-play Next.js / Node.js middleware for x402 HTTP 402 payments. Monetize any API route in USDC on Base — 5 lines, no signup, no Coinbase SDK.
Maintainers
Readme
gate402-next — Next.js middleware for x402 (HTTP 402) payments
Plug-and-play Next.js / Express / Hono middleware that monetizes any API route with x402 — HTTP 402 Payment Required, settled in USDC on Base.
No Coinbase SDK. No facilitator boilerplate. No x402ResourceServer. Five lines and the route is paid.
Built by Gate402 — the pay-per-call API gateway for AI agents.
npm install gate402-nextNext.js middleware (App Router)
// middleware.ts
import { gate402 } from 'gate402-next/next';
export const middleware = gate402({
wallet: process.env.GATE402_WALLET!, // 0x… receives USDC
routes: {
'/api/weather': 0.001,
'/api/premium/*': { price: 0.05, description: 'Premium API' }
}
});
export const config = {
matcher: ['/api/weather', '/api/premium/:path*']
};That's it. Unpaid calls get HTTP 402 with a v1 JSON body + v2 PAYMENT-REQUIRED header. Agents retry with PAYMENT-SIGNATURE. Browsers get a small HTML paywall.
How the middleware handshake works
When an AI agent or client script hits a developer's protected Next.js API route, gate402-next intercepts the call before the route handler runs:
- Match the route. The middleware checks
routes(exact path or/api/premium/*). Unmatched paths pass through unpaid. - Look for proof. It reads
PAYMENT-SIGNATURE(x402 v2) orX-PAYMENT(v1). - No proof → HTTP 402. It does not run your handler. The response quotes price, USDC asset, network (Base by default), and
payTo(your wallet). Agents get JSON; browsers thatAccept: text/htmlget a paywall page. The v2 quote is also Base64 in thePAYMENT-REQUIREDheader. - The agent pays. It signs an EIP-3009 USDC
transferWithAuthorization(gasless) and retries the same URL with that payload inPAYMENT-SIGNATURE. - Verify. Middleware POSTs
{ paymentPayload, paymentRequirements }to the facilitator (https://x402.org/facilitatorby default). Invalid signatures die at 401/402 — still no handler. - Settle, then continue. On valid proof, the facilitator broadcasts the USDC transfer to your wallet. Middleware attaches
PAYMENT-RESPONSEand callsNextResponse.next(). Your route handler runs as a normal request. - Replay guard. That payment header is consumed once in-process so the same proof cannot fetch the endpoint twice.
Agent Next.js (gate402-next) Facilitator Base
| | | |
| GET /api/weather | | |
|------------------------->| | |
| 402 + PAYMENT-REQUIRED | | |
|<-------------------------| | |
| sign USDC authorization | | |
| GET /api/weather | | |
| + PAYMENT-SIGNATURE | | |
|------------------------->| POST /verify | |
| |-------------------------------->| |
| | POST /settle | USDC → your 0x… |
| |-------------------------------->|------------------->|
| 200 + PAYMENT-RESPONSE | | |
| + your API body | | |
|<-------------------------| | |withPayment() in an App Router handler is the same handshake except settle waits until your handler returns HTTP < 400, so a 500 does not charge the agent. Middleware (middleware.ts) settles before the handler — cheaper to write, charges even if the route later fails.
App Router handler (settle only on success)
Middleware charges even if your handler later returns 500. For JSON APIs, wrap the route instead — settlement runs only when the response is < 400:
// app/api/weather/route.ts
import { withPayment } from 'gate402-next/next';
export const GET = withPayment(
{ wallet: process.env.GATE402_WALLET!, price: 0.001, description: 'Current weather' },
async () => Response.json({ tempC: 22 })
);Next.js 16 proxy.ts is the same function:
export { gate402 as proxy } from 'gate402-next/next';Express
import express from 'express';
import { gate402 } from 'gate402-next/express';
const app = express();
app.post(
'/api/weather',
gate402({ wallet: process.env.GATE402_WALLET!, price: 0.001 }),
(_req, res) => res.json({ tempC: 22 })
);Hono / Cloudflare Workers
import { Hono } from 'hono';
import { gate402 } from 'gate402-next/hono';
const app = new Hono();
app.use('/api/*', gate402({ wallet: process.env.GATE402_WALLET!, price: 0.01 }));Zero Node-only APIs — the core uses fetch + Request/Response, so it runs on the Edge.
What a 402 looks like
HTTP/1.1 402 Payment Required
PAYMENT-REQUIRED: eyJ4NDAyVmVyc2lvbiI6MiwiYWNjZXB0cyI6Wy4uLl19
Content-Type: application/json
{
"x402Version": 1,
"error": "Payment Required",
"accepts": [{
"scheme": "exact",
"network": "base",
"maxAmountRequired": "1000",
"payTo": "0xYourWallet",
"asset": "0x833589fcd6edb6e08f4c7c32d4f71b54bda02913"
}]
}Compatible with x402 v1 (X-PAYMENT) and v2 (PAYMENT-SIGNATURE) clients. The facilitator never holds funds — it only verifies the signature and submits the transfer. USDC moves payer → wallet in one hop.
Config
| Option | Default | What |
|---|---|---|
| wallet | GATE402_WALLET | EVM address that receives USDC |
| price | — | Default USDC price when a route does not set its own |
| routes | all traffic | path → number \| { price, description, network, wallet } |
| network | base | base · polygon · arbitrum · base-sepolia · or CAIP-2 |
| networks | — | Extra networks advertised in accepts[] |
| facilitator | https://x402.org/facilitator | Override with X402_FACILITATOR_URL |
| htmlPaywall | true | HTML 402 when Accept: text/html |
Unmatched routes are free (the request continues). Put the Next.js matcher on the paid paths only.
Call Gate402 APIs (buyer client)
Same package — auto-claims a free-credit key, same as pip install gate402:
import { Gate402 } from 'gate402-next';
const g = new Gate402(); // or { apiKey: process.env.GATE402_API_KEY }
const risk = await g.tokenRisk('0x4ed4e862860bed51a9570b96d89af5e1b0efefed');
const md = await g.scrape('https://example.com');
const json = await g.jsonRepair('{"name": "Bob", "age": 32,}');
const jpg = await g.heicToJpg({ file: 'IMG_1234.HEIC' });Every live catalog route has a typed helper (onchain, dex, tokenRisk, momentum, bestSwap, launches, demand, news, edgar, scrape, minify, dedup, infer, compute, jsonRepair, csvJson, contractScan, abiDecode, siteScreenshot, invoicePro, cryptoTaxCsv, uploadfix, heicToJpg, underMb, imageFit, metadataStrip, photoToPdf, bgRemove, videoUnderMb, ocrStructured, atsResume, pdfFillable, pdfA11y, docChecker, plus free catalog / providers). File tools take { file: path | Uint8Array } or { fileBase64, filename }. Use g.call('/v1/…', body) for anything else.
marketInfer is x402-native (the API-key rail cannot pay it). Catalog + discovery: gate402.app/v1 · llms.txt
Why this instead of @x402/next
Official @x402/next is the full protocol SDK: you construct an x402ResourceServer, register ExactEvmScheme, pass CAIP-2 networks, and wire a facilitator client. That's correct — and ~40 lines before the first paid route.
gate402-next is the 5-line version. Prices are numbers (0.01, not "$0.01"). The facilitator defaults to the same public endpoint Gate402 runs in production. Express and Hono are included.
Use @x402/next when you need custom schemes or Solana. Use this when you want a Next.js API to start charging USDC today.
Env
GATE402_WALLET=0xYourAddress # required for middleware
X402_FACILITATOR_URL= # optional
GATE402_API_KEY=sk_live_… # optional buyer client
GATE402_BASE_URL=https://gate402.app # optional buyer clientLicense
MIT © Gate402
