Skip to content
LogoLogo

Discovery

Let clients automatically discover your API's pricing

Overview

MPP's discovery system lets clients and agents learn what your endpoints cost before making a request. You serve a standard OpenAPI 3.1 document at /openapi.json with x-payment-info extensions that advertise one or more payment offers for each paid operation. Registries aggregate these documents so agents can find paid APIs automatically, and provide value-added services like reputation, search, and analytics.

Registries

Registries aggregate discovery documents from multiple services, making it easy for clients and agents to find paid APIs.

RegistryDescriptionHow to add
MPPScanPublic registry of MPP-enabled services with search and analyticsManually register in one click
MPP Services directoryCurated list of live services on mpp.devSubmit a PR to add your service

Quick start

The mppx SDK generates discovery documents from your route configuration. Add discovery() to your server and it serves /openapi.json automatically.

server.ts
import { Hono } from 'hono'
import { Mppx, discovery } from 'mppx/hono'
import { tempo } from 'mppx/server'
 
const app = new Hono()
 
const mppx = Mppx.create({
  methods: [
    tempo({
      currency: '0x20c0000000000000000000000000000000000000',
      recipient: '0x...',
      testnet: true,
    }),
  ],
  secretKey: process.env.MPP_SECRET_KEY,
})
 
app.get('/v1/fortune', mppx.charge({ amount: '0.01' }), (c) => c.json({ fortune: 'You will be rich' }))
 
discovery(app, mppx, {
  auto: true,
  info: { title: 'Fortune API', version: '1.0.0' },
})

This generates a GET /openapi.json endpoint with canonical x-payment-info.offers[] entries on each paid route.

Express

server.ts
import express from 'express'
import { Mppx, discovery } from 'mppx/express'
import { tempo } from 'mppx/server'
 
const app = express()
 
const mppx = Mppx.create({
  methods: [
    tempo({
      currency: '0x20c0000000000000000000000000000000000000',
      recipient: '0x...',
      testnet: true,
    }),
  ],
  secretKey: process.env.MPP_SECRET_KEY,
})
 
const pay = mppx.charge({ amount: '0.01' })
app.get('/v1/fortune', pay, (req, res) => res.json({ fortune: 'You will be rich' }))
 
discovery(app, mppx, {
  info: { title: 'Fortune API', version: '1.0.0' },
  routes: [{ handler: pay, method: 'get', path: '/v1/fortune' }],
})

Next.js

In Next.js, discovery() returns a route handler you export from an API route.

app/openapi.json/route.ts
import { discovery } from 'mppx/nextjs'
import { mppx, pay } from '../fortune/route'
 
export const GET = discovery(mppx, {
  info: { title: 'Fortune API', version: '1.0.0' },
  routes: [{ handler: pay, method: 'get', path: '/api/fortune' }],
})

How it works

Your server exposes a GET /openapi.json endpoint that returns an OpenAPI document. Paid operations include an x-payment-info extension with one or more payment offers, and the document root can include x-service-info for service-level metadata.

/openapi.json
{
  "openapi": "3.1.0",
  "info": { "title": "My API", "version": "1.0.0" },
  "x-service-info": {
    "categories": ["ai"],
    "docs": {
      "homepage": "https://example.com",
      "apiReference": "https://example.com/docs",
      "llms": "/llms.txt"
    }
  },
  "paths": {
    "/v1/generate": {
      "post": {
        "x-payment-info": {
          "offers": [
            {
              "amount": "1000000",
              "currency": "0x20c0000000000000000000000000000000000001",
              "description": "Generate text with Tempo",
              "intent": "charge",
              "method": "tempo"
            },
            {
              "amount": "100",
              "currency": "usd",
              "description": "Generate text with Stripe",
              "intent": "charge",
              "method": "stripe"
            }
          ]
        },
        "responses": {
          "200": { "description": "Successful response" },
          "402": { "description": "Payment Required" }
        }
      }
    },
    "/v1/models": {
      "get": {
        "responses": {
          "200": { "description": "Successful response" }
        }
      }
    }
  }
}

x-payment-info

Add this extension to any operation that requires payment. Prefer the canonical multi-offer shape:

FieldTypeDescription
offersOffer[]Ordered list of payment offers the client can choose from

offers[]

FieldTypeDescription
amountstring | nullPayment amount in base units
currencystringCurrency code or token address
descriptionstringHuman-readable description of the charge
intentstringPayment intent (charge or session)
methodstringPayment method identifier (tempo, stripe)

x-service-info

Optional root-level metadata about the service:

FieldTypeDescription
categoriesstring[]Free-form service categories (for example, ai, payments)
docs.homepagestringLink to the service homepage
docs.apiReferencestringLink to API documentation
docs.llmsstringLink to an llms.txt file for AI consumption

Build manually

You can author a discovery document by hand following the discovery specification. The document is a standard OpenAPI 3.1 file with two extensions:

Create the OpenAPI skeleton

Start with a standard OpenAPI 3.1 document:

openapi.json
{
  "openapi": "3.1.0",
  "info": {
    "title": "My API",
    "version": "1.0.0"
  },
  "paths": {}
}

Add x-payment-info to paid operations

For each endpoint that requires payment, add the x-payment-info extension with an offers array. Add more objects to offers[] when the client can choose between alternative payment methods or currencies. Amounts are in base units (for example, 1000000 for $1.00 with 6 decimals).

openapi.json
{
  "paths": {
    "/v1/generate": {
      "post": {
        "summary": "Generate text",
        "x-payment-info": {
          "offers": [
            {
              "amount": "1000000",
              "currency": "0x20c0000000000000000000000000000000000001",
              "intent": "charge",
              "method": "tempo"
            }
          ]
        },
        "responses": {
          "200": { "description": "Successful response" },
          "402": { "description": "Payment Required" }
        }
      }
    }
  }
}

Add x-service-info (optional)

Add service-level metadata to the document root:

openapi.json
{
  "x-service-info": {
    "categories": ["ai", "text-generation"],
    "docs": {
      "homepage": "https://example.com",
      "apiReference": "https://example.com/docs/api",
      "llms": "https://example.com/llms.txt"
    }
  }
}

Serve at /openapi.json

Serve the document at GET /openapi.json with appropriate caching:

HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: public, max-age=300

CLI

Generate a static discovery document from a config module:

terminal
$ npx mppx discover generate ./discovery.config.ts

Validate an existing discovery document from a file or URL:

terminal
$ npx mppx discover validate https://example.com/openapi.json

Validation

Common validation issues:

IssueSeverityDescription
Missing 402 responseErrorOperations with x-payment-info must include a 402 response
Invalid amount formatErrorEach offers[].amount value must be a non-negative integer string
Missing requestBodyWarningPOST/PUT/PATCH operations without a requestBody definition
Invalid URI in docsErrordocs links must be valid URIs or absolute paths

Specification