Dunmore

Full API Specification

Complete Dunmore REST API specification. Give this page to an AI agent to get started.

Complete REST API specification for Dunmore. This single page contains everything an AI agent needs to create a project, register paid endpoints, configure integrations, and monitor revenue.

Base URL: https://api.dunmore.xyz

Authentication

All /api/* routes require an Authorization header.

Authorization: Bearer gf_live_...

Two auth methods are supported:

MethodToken formatUsed byScope
API Keygf_live_...Agents, SDK middlewareProject-scoped (/api/projects/:projectId/*)
Clerk JWTeyJhbG...Console UI, humansUser-scoped (/api/projects CRUD)

Agents should use API keys. Create one in the console or via the API keys endpoint below.

Quick Start (5 API calls)

# 1. Create a project (requires Clerk JWT — do this in the console)
# Then use your gf_live_... API key for everything else:

# 2. Register a paid endpoint
curl -X POST https://api.dunmore.xyz/api/projects/proj_xxx/endpoints \
  -H "Authorization: Bearer gf_live_..." \
  -H "Content-Type: application/json" \
  -d '{"path": "/analyze", "upstreamUrl": "https://my-agent.fly.dev/analyze", "priceUsd": "0.05"}'

# 3. Set up Slack notifications
curl -X POST https://api.dunmore.xyz/api/projects/proj_xxx/connectors \
  -H "Authorization: Bearer gf_live_..." \
  -H "Content-Type: application/json" \
  -d '{"type": "slack", "config": {"webhookUrl": "https://hooks.slack.com/..."}, "eventTypes": ["payment.settled"]}'

# 4. Check revenue
curl https://api.dunmore.xyz/api/projects/proj_xxx/analytics/revenue \
  -H "Authorization: Bearer gf_live_..."

# 5. List transactions
curl https://api.dunmore.xyz/api/projects/proj_xxx/transactions \
  -H "Authorization: Bearer gf_live_..."

Response Format

All responses use this envelope:

// Success
{ "data": { ... } }

// Error
{ "error": { "code": "NOT_FOUND", "message": "Project not found", "status": 404 } }

ID Prefixes

PrefixEntity
proj_Project
ep_Endpoint
pay_Payment
key_API Key
wh_Webhook
whd_Webhook Delivery
conn_Connector
evt_Event
gf_live_API Key secret
whsec_Webhook signing secret

Projects

Projects are the top-level container. All endpoints, keys, webhooks, and connectors belong to a project.

Create Project

POST /api/projects
Auth: Clerk JWT
FieldTypeRequiredDescription
namestringYesProject display name
slugstringYesURL-safe identifier (lowercase, alphanumeric, hyphens)
walletAddressstringYesEVM address to receive USDC payments
networkstringNoChain ID (default: "eip155:8453" for Base mainnet)
// Response 201
{
  "data": {
    "id": "proj_xxx",
    "name": "My Agent",
    "slug": "my-agent",
    "ownerId": "user_xxx",
    "walletAddress": "0x...",
    "network": "eip155:8453",
    "createdAt": "2025-02-22T12:00:00Z",
    "updatedAt": "2025-02-22T12:00:00Z"
  }
}

List Projects

GET /api/projects
Auth: Clerk JWT

Returns all projects owned by the authenticated user.

// Response 200
{ "data": [ { "id": "proj_xxx", "name": "...", ... } ] }

Get Project

GET /api/projects/:projectId
Auth: Clerk JWT

Update Project

PATCH /api/projects/:projectId
Auth: Clerk JWT
FieldTypeRequiredDescription
namestringNoNew project name
walletAddressstringNoNew wallet address
networkstringNoNew network

Delete Project

DELETE /api/projects/:projectId
Auth: Clerk JWT

Deletes the project and all child records (endpoints, keys, webhooks, connectors, payments).


Endpoints

Endpoints represent individual paid API routes behind the Dunmore gateway.

Create Endpoint

POST /api/projects/:projectId/endpoints
Auth: API Key
FieldTypeRequiredDescription
pathstringYesURL path, must start with / (e.g., "/api/weather")
upstreamUrlstringYesYour API's public URL
priceUsdstringYesPrice per request in USD (e.g., "0.001")
// Response 201
{
  "data": {
    "id": "ep_xxx",
    "projectId": "proj_xxx",
    "path": "/api/weather",
    "upstreamUrl": "https://my-agent.fly.dev/api/weather",
    "priceUsd": "0.00100000",
    "isActive": true,
    "createdAt": "2025-02-22T12:00:00Z",
    "updatedAt": "2025-02-22T12:00:00Z"
  }
}

List Endpoints

GET /api/projects/:projectId/endpoints
Auth: API Key

Update Endpoint

PATCH /api/projects/:projectId/endpoints/:endpointId
Auth: API Key
FieldTypeRequiredDescription
priceUsdstringNoNew price (must be positive)
upstreamUrlstringNoNew upstream URL
isActivebooleanNoEnable/disable

Delete Endpoint

DELETE /api/projects/:projectId/endpoints/:endpointId
Auth: API Key

API Keys

API keys are scoped to a project and used for programmatic access. Secrets start with gf_live_.

Create API Key

POST /api/projects/:projectId/keys
Auth: API Key
FieldTypeRequiredDescription
namestringYesDisplay name for the key
// Response 201
{
  "data": {
    "id": "key_xxx",
    "name": "Agent Key",
    "keyPrefix": "gf_live_xxxx",
    "secret": "gf_live_xxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "createdAt": "2025-02-22T12:00:00Z"
  }
}

The secret is only returned on creation. Store it securely.

List API Keys

GET /api/projects/:projectId/keys
Auth: API Key

Returns keys with prefixes only (no secrets). Only shows non-revoked keys.

Revoke API Key

DELETE /api/projects/:projectId/keys/:keyId
Auth: API Key

Webhooks

Webhooks deliver real-time event notifications to your URL via HTTP POST. Signed with HMAC-SHA256.

Create Webhook

POST /api/projects/:projectId/webhooks
Auth: API Key
FieldTypeRequiredDescription
urlstringYesPublic HTTPS endpoint
eventTypesstring[]YesEvents to subscribe to (see Event Types)
// Response 201
{
  "data": {
    "id": "wh_xxx",
    "projectId": "proj_xxx",
    "url": "https://my-agent.fly.dev/webhooks",
    "secret": "whsec_xxx",
    "eventTypes": ["payment.settled", "payment.failed"],
    "isActive": true,
    "createdAt": "2025-02-22T12:00:00Z"
  }
}

The secret is only returned on creation. Use it to verify webhook signatures.

List Webhooks

GET /api/projects/:projectId/webhooks
Auth: API Key

Update Webhook

PATCH /api/projects/:projectId/webhooks/:webhookId
Auth: API Key
FieldTypeRequiredDescription
urlstringNoNew webhook URL
eventTypesstring[]NoNew event types
isActivebooleanNoEnable/disable

Delete Webhook

DELETE /api/projects/:projectId/webhooks/:webhookId
Auth: API Key

Get Delivery Logs

GET /api/projects/:projectId/webhooks/:webhookId/deliveries
Auth: API Key

Returns the 50 most recent deliveries with status, HTTP response code, and timing.


Connectors

Connectors are pre-built integrations that subscribe to payment events. Each project can have one connector per type.

Supported Types

slack, discord, email, telegram, twilio, zapier, n8n, make, bigquery, supabase, google-sheets, dune, linear, segment, amplitude, posthog, pagerduty, datadog, opsgenie, teams

Create Connector

POST /api/projects/:projectId/connectors
Auth: API Key
FieldTypeRequiredDescription
typestringYesConnector type (see list above)
configobjectYesType-specific configuration
eventTypesstring[]YesEvents to subscribe to

Example — Slack:

curl -X POST https://api.dunmore.xyz/api/projects/proj_xxx/connectors \
  -H "Authorization: Bearer gf_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "slack",
    "config": { "webhookUrl": "https://hooks.slack.com/services/T.../B.../xxx" },
    "eventTypes": ["payment.settled"]
  }'

Example — Discord:

curl -X POST https://api.dunmore.xyz/api/projects/proj_xxx/connectors \
  -H "Authorization: Bearer gf_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "discord",
    "config": { "webhookUrl": "https://discord.com/api/webhooks/..." },
    "eventTypes": ["payment.settled", "payment.failed"]
  }'

Example — Email:

curl -X POST https://api.dunmore.xyz/api/projects/proj_xxx/connectors \
  -H "Authorization: Bearer gf_live_..." \
  -H "Content-Type: application/json" \
  -d '{
    "type": "email",
    "config": { "to": "alerts@example.com" },
    "eventTypes": ["payment.failed"]
  }'

List Connectors

GET /api/projects/:projectId/connectors
Auth: API Key

Update Connector

PATCH /api/projects/:projectId/connectors/:connectorId
Auth: API Key
FieldTypeRequiredDescription
configobjectNoUpdated configuration
eventTypesstring[]NoNew event types
isActivebooleanNoEnable/disable

Delete Connector

DELETE /api/projects/:projectId/connectors/:connectorId
Auth: API Key

Transactions

Payments processed through your endpoints.

List Transactions

GET /api/projects/:projectId/transactions
Auth: API Key
Query paramTypeDefaultDescription
pagenumber1Page number
pageSizenumber50Results per page (max 100)
statusstringFilter: "verified", "settled", "failed"
// Response 200
{
  "data": [
    {
      "id": "pay_xxx",
      "projectId": "proj_xxx",
      "endpointId": "ep_xxx",
      "payerWallet": "0x...",
      "amountUsd": "0.00100000",
      "status": "settled",
      "txHash": "0x...",
      "network": "eip155:8453",
      "requestedAt": "2025-02-22T12:00:00Z",
      "verifiedAt": "2025-02-22T12:00:01Z",
      "settledAt": "2025-02-22T12:00:05Z",
      "failedAt": null,
      "errorMessage": null
    }
  ],
  "pagination": {
    "total": 142,
    "page": 1,
    "pageSize": 50,
    "hasMore": true
  }
}

Get Transaction

GET /api/projects/:projectId/transactions/:paymentId
Auth: API Key

Analytics

Revenue Overview

GET /api/projects/:projectId/analytics/revenue
Auth: API Key
Query paramTypeDefaultDescription
periodstring"30d""today", "7d", "30d", or "all"
// Response 200
{
  "data": {
    "overview": {
      "totalRevenue": "14.25000000",
      "transactionCount": 1420,
      "settledCount": 1400,
      "failedCount": 20,
      "totalCount": 1420,
      "uniquePayers": 38,
      "period": "30d"
    },
    "series": [
      { "date": "2025-02-22", "revenue": "0.50000000", "transactionCount": 50 }
    ]
  }
}

Conversion Funnel

GET /api/projects/:projectId/analytics/funnel
Auth: API Key

Returns verification-to-settlement conversion rates per endpoint.

Top Customers

GET /api/projects/:projectId/analytics/customers
Auth: API Key
Query paramTypeDefaultDescription
limitnumber20Max results
// Response 200
{
  "data": [
    {
      "payerWallet": "0x...",
      "totalSpend": "5.25000000",
      "paymentCount": 525,
      "avgPayment": "0.01000000",
      "firstPaymentAt": "2025-02-01T12:00:00Z",
      "lastPaymentAt": "2025-02-22T12:00:00Z"
    }
  ]
}

Event Types

Events are emitted to the PostgreSQL outbox and dispatched to webhooks and connectors.

EventWhen
payment.verifiedPayment signature verified off-chain
payment.settledPayment confirmed on-chain
payment.failedPayment verification or settlement failed
endpoint.createdNew endpoint registered
endpoint.pricing_changedEndpoint price updated
customer.first_paymentA wallet makes its first payment to your project
customer.milestoneA wallet crosses a spending threshold ($10, $100, $1K, $10K)

Event Payload Shape

{
  "id": "evt_xxx",
  "type": "payment.settled",
  "timestamp": "2025-02-22T12:00:00Z",
  "data": {
    "payment_id": "pay_xxx",
    "endpoint": "/api/weather",
    "amount": "1000",
    "currency": "USDC",
    "network": "eip155:8453",
    "payer_wallet": "0x...",
    "seller_wallet": "0x...",
    "tx_hash": "0x..."
  },
  "metadata": {
    "project_id": "proj_xxx",
    "environment": "production"
  }
}

x402 Payment Flow

When a client hits a paid endpoint:

Client                  Gateway                  Facilitator
  │                       │                          │
  │── GET /api/weather ──▶│                          │
  │◀── 402 + accepts[] ──│                          │
  │                       │                          │
  │ (sign EIP-3009)       │                          │
  │                       │                          │
  │── GET /api/weather ──▶│                          │
  │   Payment-Signature   │── POST /verify ────────▶│
  │                       │◀── { valid: true } ─────│
  │                       │                          │
  │                       │── Forward to upstream ──▶│
  │◀── 200 + data ───────│                          │
  │                       │                          │
  │                       │── POST /settle (async) ─▶│
  │                       │                          │── on-chain tx

402 Response Format (x402 v2)

{
  "x402Version": 2,
  "resource": { "url": "/api/weather" },
  "accepts": [
    {
      "scheme": "exact",
      "network": "eip155:8453",
      "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
      "amount": "1000",
      "payTo": "0x...",
      "maxTimeoutSeconds": 30,
      "extra": { "name": "USD Coin", "version": "2" }
    }
  ]
}

Payment Header Format (x402 v2)

Base64-encoded JSON in the Payment-Signature header:

{
  "x402Version": 2,
  "accepted": {
    "scheme": "exact",
    "network": "eip155:8453",
    "asset": "0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913",
    "amount": "1000",
    "payTo": "0x...",
    "maxTimeoutSeconds": 30,
    "extra": { "name": "USD Coin", "version": "2" }
  },
  "payload": {
    "signature": "0x...",
    "authorization": {
      "from": "0x...",
      "to": "0x...",
      "value": "1000",
      "validAfter": "0",
      "validBefore": "1740240000",
      "nonce": "0x..."
    }
  },
  "resource": { "url": "/api/weather" }
}

The accepted field must echo back one of the requirements from the accepts array in the 402 response.


Networks and Assets

NetworkChain IDUSDC Address
Base Mainneteip155:84530x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913
Base Sepolia (testnet)eip155:845320x036CbD53842c5426634e7929541eC2318f3dCF7e

All amounts are in USDC atomic units (6 decimals). "1000" = $0.001 USDC.


SDK Middleware (Alternative to Gateway)

Instead of routing through the Dunmore gateway, you can embed payment verification directly in your server using SDK middleware.

Hono

npm install @dunmore/hono
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...",
  network: "eip155:84532", // omit for mainnet
}), (c) => {
  return c.json({ temperature: 72, unit: "F" });
});

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

Express

npm install @dunmore/express
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...",
  network: "eip155:84532", // omit for mainnet
}), (req, res) => {
  res.json({ temperature: 72, unit: "F" });
});

app.listen(3000);

Route Summary

MethodPathAuthDescription
POST/api/projectsClerk JWTCreate project
GET/api/projectsClerk JWTList projects
GET/api/projects/:idClerk JWTGet project
PATCH/api/projects/:idClerk JWTUpdate project
DELETE/api/projects/:idClerk JWTDelete project
POST/api/projects/:pid/endpointsAPI KeyCreate endpoint
GET/api/projects/:pid/endpointsAPI KeyList endpoints
PATCH/api/projects/:pid/endpoints/:eidAPI KeyUpdate endpoint
DELETE/api/projects/:pid/endpoints/:eidAPI KeyDelete endpoint
POST/api/projects/:pid/keysAPI KeyCreate API key
GET/api/projects/:pid/keysAPI KeyList API keys
DELETE/api/projects/:pid/keys/:kidAPI KeyRevoke API key
POST/api/projects/:pid/webhooksAPI KeyCreate webhook
GET/api/projects/:pid/webhooksAPI KeyList webhooks
PATCH/api/projects/:pid/webhooks/:widAPI KeyUpdate webhook
DELETE/api/projects/:pid/webhooks/:widAPI KeyDelete webhook
GET/api/projects/:pid/webhooks/:wid/deliveriesAPI KeyDelivery logs
POST/api/projects/:pid/connectorsAPI KeyCreate connector
GET/api/projects/:pid/connectorsAPI KeyList connectors
PATCH/api/projects/:pid/connectors/:cidAPI KeyUpdate connector
DELETE/api/projects/:pid/connectors/:cidAPI KeyDelete connector
GET/api/projects/:pid/transactionsAPI KeyList transactions
GET/api/projects/:pid/transactions/:tidAPI KeyGet transaction
GET/api/projects/:pid/analytics/revenueAPI KeyRevenue data
GET/api/projects/:pid/analytics/funnelAPI KeyConversion funnel
GET/api/projects/:pid/analytics/customersAPI KeyTop customers
GET/healthNoneHealth check