Use this file to discover all available pages before exploring further.
In this quickstart, you will add Circle Gateway payment middleware to an Express
API so that it accepts gasless USDC payments via the x402 protocol. By the end,
your API will return 402 Payment Required for unpaid requests and serve
resources when a valid payment signature is provided.
# Set up your directory and initialize a Node.js projectmkdir nanopayments-sellercd nanopayments-sellernpm init -y# Set up module type and start commandnpm pkg set type=modulenpm pkg set scripts.start="tsx server.ts"# Install runtime dependenciesnpm install @circle-fin/x402-batching @x402/core @x402/evm viem express tsx typescript# Install dev dependenciesnpm install --save-dev @types/node @types/express
Create a new file server.ts with an Express app and the Gateway middleware:
server.ts
import express from "express";import { createGatewayMiddleware } from "@circle-fin/x402-batching/server";import { formatUnits } from "viem";// Extended Express Request type to include payment informationtype PaidRequest = express.Request & { payment?: { verified: boolean; payer: string; amount: string; network: string; transaction?: string; };};const app = express();const gateway = createGatewayMiddleware({ sellerAddress: "0xYOUR_WALLET_ADDRESS", facilitatorUrl: "https://gateway-api-testnet.circle.com",});
Replace 0xYOUR_WALLET_ADDRESS with a valid EVM address where you want to
receive payments. This quickstart uses Arc Testnet, so it points to the testnet
Gateway API. The middleware still accepts payments from
all supported networks.
Use gateway.require() to protect any route with a price. When a request
arrives without a valid payment, the middleware returns 402 Payment Required
with the payment details. When a valid payment signature is attached, the
middleware settles it with Gateway using the
Settle x402 Payment API
endpoint and calls next():
server.ts
app.get("/premium-data", gateway.require("$0.01"), (req: PaidRequest, res) => { const { payer, amount, network } = req.payment!; const formattedAmount = formatUnits(BigInt(amount), 6); console.log(`Paid ${formattedAmount} USDC by ${payer} on ${network}`); res.json({ secret: "The treasure is hidden under the doormat.", paid_by: payer, });});app.listen(3000, () => { console.log("Server listening at http://localhost:3000");});
If you are not using Express, or need custom logic like dynamic pricing, use the
BatchFacilitatorClient directly. The settle() method calls the
Settle x402 Payment API
endpoint:
Gateway’s settle() endpoint is optimized for low latency and guarantees
settlement. Use settle() directly rather than calling verify() followed by
settle() in production flows.
By default, the middleware accepts payments from any Gateway-supported
blockchain, discovered through the
Get Supported x402 Payment Kinds
API endpoint. This maximizes your reach since any buyer with a Gateway balance
on one of those accepted networks can pay you.If you need to restrict payments to specific networks:
Payment signatures must have at least 7 days plus a small buffer of validity.
The validBefore timestamp in the buyer’s EIP-3009 authorization must be at
least 7 days in the future, or Gateway will reject it.