Dunmore

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

  1. No Payment-Signature header — Returns 402 Payment Required with x402 v2 payment requirements (accepts array with scheme, network, USDC asset address, amount, payTo).
  2. Has Payment-Signature header — Decodes the base64 payment payload and sends it to the Dunmore facilitator for on-chain verification.
  3. Verification passes — Attaches payment info to req.dunmore, fires off settlement asynchronously, and calls next().
  4. Verification fails — Returns 402 with an error describing why the payment was invalid.

Configuration Options

OptionTypeRequiredDefaultDescription
apiUrlstringYesDunmore API base URL
apiKeystringYesYour gf_live_... API key
projectIdstringYesYour proj_... project ID
priceUsdstringYesPrice per request in USD (e.g. "0.001")
payTostringYesWallet address to receive USDC payments
networkstringNoeip155:8453Chain ID. Use eip155:84532 for Base Sepolia testnet

Error Responses

StatusCodeWhen
402PAYMENT_REQUIREDNo Payment-Signature header provided
400INVALID_PAYMENTPayment header is not valid base64 JSON
402PAYMENT_INVALIDPayment failed on-chain verification
500GATEWAY_ERRORDunmore facilitator is unreachable