Skip to main content
Add Circle Gateway payment middleware to an Express API so that it accepts gasless USDC payments through the x402 protocol. The API returns 402 Payment Required for unpaid requests and serves resources when a valid payment signature is provided.

Prerequisites

Before you begin, ensure that you’ve:
  • Installed Node.js v22.6+.
  • Chosen an EVM wallet address to receive USDC payments.

Step 1: Set up your project

1.1. Create the project and install dependencies

1.2. Configure TypeScript (optional)

This step is optional. It helps prevent missing types in your IDE or editor.
Create a tsconfig.json file:
Then, update the tsconfig.json file:

Step 2: Create the server

Create a new file server.ts with an Express app and the Gateway middleware:
server.ts
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.

Step 3: Protect a route

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

Step 4: Test the server

4.1. Start the server

4.2. Send an unpaid request

In a separate terminal, use curl to verify the server returns a 402 response:
You should see a 402 Payment Required response with a PAYMENT-REQUIRED header. The header contains the payment options.

4.3. Pay with a buyer client

Use the buyer quickstart client to make a gasless payment to your server:
If the payment succeeds, you’ll see the JSON response from your protected endpoint. If it’s rejected, the error reference covers each error code, including insufficient_funds, expired_authorization, invalid_payload, and invalid_signature. Each entry explains the cause and how to recover. To attribute settled payments back to the requests that triggered them, see Reconcile nanopayments.

Handle payments without the middleware (advanced)

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:
server.ts
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.

Limit accepted networks (optional)

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.