Dunmore

Hono Middleware

Add x402 payment verification to your Hono API with the Dunmore SDK.

The @dunmore/hono package adds x402 payment verification to Hono APIs with a single middleware function.

Installation

npm install @dunmore/hono

Quick Start

import { Hono } from "hono";
import { serve } from "@hono/node-server";
import { dunmorePaywall } from "@dunmore/hono";

const app = new Hono();

app.get(
  "/api/weather",
  dunmorePaywall({
    apiUrl: "https://api.dunmore.xyz",
    apiKey: "gf_live_...",
    projectId: "proj_...",
    priceUsd: "0.001",
    payTo: "0x...",
  }),
  (c) => {
    return c.json({ temperature: 72, city: "San Francisco" });
  }
);

serve({ fetch: app.fetch, port: 3000 }, () => {
  console.log("Running on http://localhost: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/hono hono @hono/node-server

3. Configure the Paywall

Create a config object with your Dunmore credentials and pricing:

import { dunmorePaywall } from "@dunmore/hono";

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 { Hono } from "hono";
import { serve } from "@hono/node-server";

const app = new Hono();

// This route requires payment
app.get("/api/weather", dunmorePaywall(paywallConfig), (c) => {
  return c.json({ temperature: 72, unit: "F" });
});

// This route is free
app.get("/api/health", (c) => {
  return c.json({ status: "ok" });
});

serve({ fetch: app.fetch, port: 3000 });

5. Access Payment Info

After verification, payment metadata is available via c.get("dunmore"):

app.get("/api/weather", dunmorePaywall(paywallConfig), (c) => {
  const { paymentId, verified } = c.get("dunmore");
  console.log(`Payment ${paymentId} verified: ${verified}`);
  return c.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 the Hono context, fires off settlement asynchronously, and calls your handler.
  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