Paywall an HTTP Route with x402
You are adding the x402 payment protocol to an HTTP API so individual requests can be monetized — no API keys, no accounts, just per-call crypto micropayments.
Goal
A client calls GET /premium. If unpaid, the server responds 402 Payment Required with payment instructions. The client pays, retries with an x-payment header, and the server verifies and serves the response.
Environment variables
X402_PAY_TO=0xYourMerchantWalletAddress
X402_FACILITATOR_URL=https://coinpayportal.com/api/x402
X402_PRICE_USDC=0.01
Where to find them:
X402_PAY_TO— your own merchant wallet address. For crypto wallets you control already, paste it directly. For one managed by CoinPay, copy it fromhttps://coinpayportal.com/settings/wallets(the chain you intend to receive on).X402_FACILITATOR_URL— alwayshttps://coinpayportal.com/api/x402for production. CoinPay is the multi-chain x402 facilitator; no key needed.X402_PRICE_USDC— pick whatever you want to charge per request. Server-side only.
Steps (Merchant)
- Install the middleware (Node example):
``bash npm install @coinpay/x402 ``
- Wrap the route:
```js import { createX402Middleware, buildPaymentRequired, verifyX402Payment } from '@coinpay/x402';
const x402 = createX402Middleware({ price: { amount: '0.01', currency: 'USDC', chain: 'base' }, payTo: '0xYourMerchantWalletAddress', facilitator: 'https://coinpayportal.com/api/x402', });
export async function GET(request) { const paymentHeader = request.headers.get('x-payment'); if (!paymentHeader) { const body = buildPaymentRequired(x402.config); return new Response(JSON.stringify(body), { status: 402 }); } const result = await verifyX402Payment(paymentHeader, x402.config); if (!result.valid) return new Response('Invalid payment', { status: 402 }); return Response.json({ data: 'premium content' }); } ```
- Set the price server-side from your config — never trust the client's claimed amount.
Steps (Client)
import { CoinPayWallet } from '@coinpay/wallet';
const wallet = new CoinPayWallet();
const response = await wallet.x402fetch('https://api.example-business.com/premium');
const data = await response.json();
The wallet automatically handles the 402, signs a payment, and retries.
Rules
- The merchant config — including
payToandprice— must live server-side. - Verify every payment via the facilitator before serving the response.
- Use
example-business.comas the placeholder API host.
Deliverable
- A protected route that returns 402 when unpaid and 200 when paid.
- A client snippet that consumes it via
x402fetch. - A test that asserts both branches.