Express Middleware
Add x402 payment verification to your Express.js API with the Dunmore SDK.
The @dunmore/express package adds x402 payment verification to Express.js APIs with a single middleware function.
Installation
npm install @dunmore/express
Quick Start
import express from "express";
import { dunmorePaywall } from "@dunmore/express";
const app = express();
app.get(
"/api/weather",
dunmorePaywall({
apiUrl: "https://api.dunmore.xyz",
apiKey: "gf_live_...",
projectId: "proj_...",
priceUsd: "0.001",
payTo: "0x...",
}),
(req, res) => {
res.json({ temperature: 72, city: "San Francisco" });
}
);
app.listen(3000);
Step-by-Step Guide
1. Create a Dunmore Project
Sign in at console.dunmore.xyz and create a project. Note your project ID (proj_...) and generate an API key (gf_live_...).
2. Install the Package
npm install @dunmore/express express
3. Configure the Paywall
Create a config object with your Dunmore credentials and pricing:
import { dunmorePaywall } from "@dunmore/express";
const paywallConfig = {
apiUrl: "https://api.dunmore.xyz",
apiKey: process.env.DUNMORE_API_KEY!,
projectId: process.env.DUNMORE_PROJECT_ID!,
priceUsd: "0.001",
payTo: "0xYourWalletAddress",
};
4. Apply to Routes
Add dunmorePaywall() as middleware on any route you want to monetize:
import express from "express";
const app = express();
// This route requires payment
app.get("/api/weather", dunmorePaywall(paywallConfig), (req, res) => {
res.json({ temperature: 72, unit: "F" });
});
// This route is free
app.get("/api/health", (req, res) => {
res.json({ status: "ok" });
});
app.listen(3000);
5. Access Payment Info
After verification, payment metadata is attached to req.dunmore:
app.get("/api/weather", dunmorePaywall(paywallConfig), (req, res) => {
const { paymentId, verified } = (req as any).dunmore;
console.log(`Payment ${paymentId} verified: ${verified}`);
res.json({ temperature: 72, unit: "F" });
});
6. Use Testnet for Development
Set network to Base Sepolia during development:
const testConfig = {
...paywallConfig,
network: "eip155:84532", // Base Sepolia testnet
};
How It Works
- No
Payment-Signatureheader — Returns402 Payment Requiredwith x402 v2 payment requirements (acceptsarray with scheme, network, USDC asset address, amount, payTo). - Has
Payment-Signatureheader — Decodes the base64 payment payload and sends it to the Dunmore facilitator for on-chain verification. - Verification passes — Attaches payment info to
req.dunmore, fires off settlement asynchronously, and callsnext(). - Verification fails — Returns
402with an error describing why the payment was invalid.
Configuration Options
| Option | Type | Required | Default | Description |
|---|---|---|---|---|
apiUrl | string | Yes | — | Dunmore API base URL |
apiKey | string | Yes | — | Your gf_live_... API key |
projectId | string | Yes | — | Your proj_... project ID |
priceUsd | string | Yes | — | Price per request in USD (e.g. "0.001") |
payTo | string | Yes | — | Wallet address to receive USDC payments |
network | string | No | eip155:8453 | Chain ID. Use eip155:84532 for Base Sepolia testnet |
Error Responses
| Status | Code | When |
|---|---|---|
402 | PAYMENT_REQUIRED | No Payment-Signature header provided |
400 | INVALID_PAYMENT | Payment header is not valid base64 JSON |
402 | PAYMENT_INVALID | Payment failed on-chain verification |
500 | GATEWAY_ERROR | Dunmore facilitator is unreachable |