# Discovery Spec

Build once, register reliably, and keep your MPP resources discoverable.

## Why This Matters

If agents cannot discover your API, they cannot call it. Bulletproof discovery turns your endpoint from merely listed to reliably invocable.

When metadata and runtime `402` behavior agree, agents succeed on the first pass. You get fewer MPPScan registration failures, less debugging churn, and more real agent traffic.

- Publish OpenAPI as the canonical machine-readable contract.
- Treat runtime `402` challenge behavior as the final source of truth.

## OpenAPI Requirements

MPPScan resolves your OpenAPI document at `/openapi.json`. This is the canonical machine-readable contract: it gives agents the cleanest invocation surface and the best tooling compatibility.

- Top-level fields: `openapi`, `info.title`, `info.x-guidance`, `info.version`, and `paths`.
- For paid operations: `responses.402` and `x-payment-info`.
- Set `x-payment-info.protocols` as an array of protocol objects, such as `mpp` and `x402`.
- Set `x-payment-info.price` as fixed or dynamic pricing metadata.
- Use OpenAPI `security` and `components.securitySchemes` for auth declaration.
- For identity-only endpoints, set the price amount to `"0"` so the client proves key ownership with zero-dollar auth and no funds transfer.
- For MPP runtime challenges, return `402` with `WWW-Authenticate`; keep the realm aligned with the public origin agents call.
- Add high-level guidance in `info.x-guidance` for agent-friendly discovery.
- If `servers[0].url` has a non-root path, do not repeat that base path in each `paths` entry.

### Recommended

- `info.contact.email` — your contact email. Lets you verify ownership of your origin, allows users to contact you, and lets you customize your merchant pages on [Poncho](https://tryponcho.com).

```json
{
  "openapi": "3.1.0",
  "info": {
    "title": "My API",
    "version": "1.0.0",
    "x-guidance": "Use POST /api/search for neural web search.",
    "contact": {
      "email": "you@example.com"
    }
  },
  "paths": {
    "/api/search": {
      "post": {
        "responses": {
          "200": { "description": "Successful response" },
          "402": { "description": "Payment Required" }
        },
        "x-payment-info": {
          "price": {
            "mode": "fixed",
            "currency": "USD",
            "amount": "0.010000"
          },
          "protocols": [
            { "mpp": { "method": "", "intent": "", "currency": "" } },
            { "x402": {} }
          ]
        }
      }
    }
  }
}
```

## What MPPScan Checks

MPPScan resolves `/openapi.json` and verifies runtime `402` challenge behavior through the `WWW-Authenticate` header.

Common checks include:

- The OpenAPI document is reachable at the registered origin.
- Paid operations include schemas, `x-payment-info`, and `402` responses.
- Runtime requests return a valid MPP-based `WWW-Authenticate` challenge.
- Proxies preserve `WWW-Authenticate` and do not rewrite the realm to an internal host.
- Payment and auth mode metadata can be resolved from `x-payment-info.protocols`.

## Free / Public Routes

Free routes don't require payment or identity, but they still need an explicit auth mode so discovery classifies them correctly.

- Add `security: []` (empty array) to each free operation in the OpenAPI spec.
- This overrides any global security requirement and tells discovery the endpoint is intentionally open.
- Without it, the endpoint is flagged as "no auth mode in the spec" during registration.

```json
{
  "paths": {
    "/api/status": {
      "get": {
        "summary": "Health check (free, no auth)",
        "security": [],
        "responses": { "200": { "description": "OK" } }
      }
    }
  }
}
```

## Common Failure Reasons

| Error | Likely Cause | Fix |
|---|---|---|
| Not Found | OpenAPI not found at `{origin}/openapi.json` | Add an OpenAPI document at `{origin}/openapi.json` |
| Input/Output Schema Missing | Operation has no input or output schema | Add input and output schemas to the operation |
| WWW-Authenticate Header Missing | Invalid or missing `WWW-Authenticate` header | Add a valid MPP-based challenge header |
| Expected 402, got 400 | Request validation rejected the unauthenticated probe before payment middleware ran | Let probes reach the `402` challenge before body/query validation, or add schemas/examples that let probes send valid input |
| Realm Mismatch | MPP realm points at a Railway/internal host or another non-public origin | Set the realm to the public origin agents call and preserve it through proxies |
| Payment/Auth Mode Missing | `x-payment-info.protocols` is missing | Add `x-payment-info.protocols` and `x-payment-info.price` |
| No Auth Mode | Endpoint has no security declaration | Add `security: []` for free routes or `security: [{ "siwx": [] }]` for identity-gated routes |

## Next Steps

- Use the quickstart prompt at `/discovery/quickstart` if you want an agent to wire this up in your repo.
- Use the proxy pattern at `/discovery/architecture` if you want to expose an existing backend without restructuring it.
- Register your origin at `/register` last — only once the API is live at its final public origin, `/openapi.json` and runtime `402` behavior are ready, and you've reviewed what will be listed. Registration publishes a listing agents will call and pay for, so an agent following the quickstart prompt should stop and ask you before registering.
