# YAML Specification

> The shape of a provider YAML — top-level fields, routing, operator, endpoints, and the optional blocks.

A provider spec is a single YAML file. The gateway loads it at startup, validates every block, and uses it to drive 402 challenges, payment verification, and (optionally) upstream forwarding.

This page unpacks the typical structure section by section. For the **per-endpoint** details, see [Defining pricing](/docs/building-with-pay/pricing) and [Subscriptions: YAML specification](/docs/building-with-pay/subscriptions/yaml-specification).

## Agent summary

- Every spec needs `name`, `subdomain`, `title`, `description`, `category`, `version`, `routing`, and at least one entry in `endpoints[]`.
- `routing.type: respond` returns 200 directly after payment verification — useful when you don't have an upstream yet.
- `routing.type: proxy` forwards verified-paid requests to an upstream URL.
- `operator` is optional; when omitted, the operator signer falls back to the active account in `~/.config/pay/accounts.yml`.
- `metering:` and `subscription:` are mutually exclusive on a single endpoint.

## Starter spec

A minimal complete spec — one free endpoint plus one metered endpoint. Boots cleanly under sandbox with no upstream.

<DownloadSpec file="starter.yml">

```yaml
name: starter
subdomain: starter
title: 'Starter Provider'
description: 'Smallest complete spec — one free endpoint, one metered endpoint.'
category: data
version: v1

routing:
  type: respond
  # type: proxy
  # url: https://api.example.com/

operator:
  currencies:
    usd: ['USDC']
  network: localnet
  fee_payer: true

endpoints:
  - method: GET
    path: 'v1/health'
    description: 'Health check (free).'

  - method: POST
    path: 'v1/generate'
    description: 'Pay-per-call endpoint.'
    metering:
      dimensions:
        - direction: usage
          unit: requests
          scale: 1
          tiers:
            - price_usd: 0.001
```

</DownloadSpec>

Run it:

```sh
pay --sandbox server start starter.yml
```

Call the metered endpoint:

```sh
pay --sandbox curl -X POST http://127.0.0.1:1402/v1/generate -d '{}'
```

## Top-level fields

These six fields are required on every spec. They drive provider discovery and the catalog listing — agents and humans see them when they search for paid APIs.

| Field         | Type   | Description                                                                                                                                                                                        |
| ------------- | ------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `name`        | string | Machine-readable provider name. Lowercase, hyphenated.                                                                                                                                             |
| `subdomain`   | string | Subdomain slug — your provider's stable identifier in the catalog.                                                                                                                                 |
| `title`       | string | Human-readable provider title.                                                                                                                                                                     |
| `description` | string | One-line summary shown in catalog and 402 challenges.                                                                                                                                              |
| `category`    | enum   | One of: `ai_ml`, `cloud`, `compute`, `data`, `devtools`, `finance`, `identity`, `maps`, `media`, `messaging`, `productivity`, `search`, `security`, `shopping`, `storage`, `translation`, `other`. |
| `version`     | string | Provider version. Free-form (`v1`, `2026-01-15`, `1.4.0`).                                                                                                                                         |

## Routing

`routing:` decides what happens to a request after the gateway has verified payment.

```yaml
# Mode 1: return 200 immediately with the verified payment signature.
# No upstream call. Useful while you're prototyping the payment side.
routing:
  type: respond

# Mode 2: forward verified-paid requests to an upstream API.
# Optional `auth:` block injects upstream credentials post-payment.
routing:
  type: proxy
  url: https://api.example.com/
  auth:
    method: query_param
    key: 'api-key'
    value_from_env: UPSTREAM_API_KEY
```

`proxy` also supports `path_rewrites` for upstreams that require env-substituted path segments (e.g. Google Cloud's `v3/projects/{projectId}/...`). See `RoutingConfig` in the source for the full schema.

You can also override `routing:` per-endpoint when one path needs to forward differently than the rest.

## Operator

`operator:` controls how the gateway runs locally — which wallet signs as the operator, which currency it accepts, which network it talks to, whether it sponsors subscriber fees.

```yaml
operator:
  # Currencies the gateway will accept payment in, grouped by unit.
  currencies:
    usd: ['USDC']

  # `mainnet`, `devnet`, or `localnet`. Sandbox mode forces `localnet`.
  network: localnet

  # When true, the operator co-signs as fee-payer so subscribers
  # don't need SOL of their own to activate / pay.
  fee_payer: true

  # Optional. Override the wallet that collects payments. Defaults to
  # the operator signer's pubkey.
  # recipient: '<your-revenue-wallet>'

  # Optional. RPC URL for verification. Defaults to the network.
  # rpc_url: 'https://mainnet.helius-rpc.com/?api-key=...'

  # Optional. Signing backend (file keypair, GCP KMS, etc.). When
  # omitted, the active account in `~/.config/pay/accounts.yml` is used.
  # signer: { type: file, path: '/etc/pay/keypair.json' }
```

When `operator:` is omitted entirely, the gateway pulls every value from the active account in `~/.config/pay/accounts.yml`. That's the most common shape for local development.

## Endpoints

`endpoints[]` is the allowlist. Anything not listed here is **not exposed** through the gateway — even if the upstream serves it.

Each endpoint has a method, a path, and one of three pricing modes.

### Free endpoint

Omit `metering:` and `subscription:` for a free endpoint. The gateway still verifies the upstream signature (when `routing.type: proxy`) and rate-limits if `quotas:` is set, but no payment is required.

```yaml
- method: GET
  path: 'v1/health'
  description: 'Health check.'
```

### Metered (per-call) endpoint

Add a `metering:` block to charge per call. The pricing dimensions can be requests, tokens, characters, pages, bytes, or any other unit you want to bill on.

```yaml
- method: POST
  path: 'v1/generate'
  description: 'Generate content.'
  metering:
    dimensions:
      - direction: usage
        unit: requests
        scale: 1
        tiers:
          - price_usd: 0.001
```

Full pricing reference: [Defining pricing](/docs/building-with-pay/pricing).

### Subscription endpoint

Add a `subscription:` block to charge a recurring fixed amount for unlimited access within a billing period.

```yaml
- method: GET
  path: 'v1/pro/feed'
  description: 'Pro feed — monthly subscription.'
  subscription:
    period: '30d'
    price_usd: 9.99
    currency: USDC
```

Full reference: [Subscriptions: YAML specification](/docs/building-with-pay/subscriptions/yaml-specification).

### Path parameters

Use `{name}` placeholders for variable path segments. They're forwarded to the upstream verbatim under `proxy` routing.

```yaml
- method: GET
  path: 'v1/quote/{symbol}'
```

## Optional blocks

These live at the top level of the spec and tune the gateway's behavior without changing the per-endpoint pricing.

| Block        | Purpose                                                                                                                                                                                         |
| ------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `env`        | Map of environment variables set on spec load. Static values are set directly; `${VAR}` references the runtime environment. Useful for upstream API keys.                                       |
| `accounting` | `pooled` (shared counter across all callers, default) or `per_agent` (per-wallet counter for volume tiers).                                                                                     |
| `recipients` | Named recipient aliases used in payment splits. Lets metered endpoints route a percentage of each charge to multiple wallets. See the demo spec under `pay --sandbox server demo` for examples. |
| `free_tier`  | A request budget that's served free before metering kicks in. Useful for evaluation tiers.                                                                                                      |
| `quotas`     | Per-window rate limits independent of payment. Use this to cap absolute throughput.                                                                                                             |
| `notes`      | Free-form merchant notes shown in the catalog. Not used by the runtime.                                                                                                                         |
| `session`    | Session-channel parameters. When set, the gateway issues `intent="session"` challenges and accepts signed vouchers instead of per-request charges. Used for streaming APIs.                     |

## Validating a spec

`pay --sandbox server start <spec>` is the canonical validator. It loads the spec, runs every check (operator config, endpoint shapes, subscription plan PDAs, currency resolution), and binds to the gateway port if everything passes. Any error prints a `Configuration error` and the gateway refuses to start.

```sh
pay --sandbox server start provider.yml --bind 127.0.0.1:1402
```

For subscription endpoints, the first launch additionally prompts to publish each plan's on-chain `Plan` PDA — sandbox covers the rent. Subsequent launches reuse the same PDAs.

## Next

- [Defining pricing](/docs/building-with-pay/pricing) — request, token, character, page, and volume-tiered pricing for metered endpoints.
- [Subscriptions: concept](/docs/building-with-pay/subscriptions/concept) — when to use a subscription endpoint over per-call pricing.
- [Subscriptions: examples](/docs/building-with-pay/subscriptions/examples) — six runnable subscription specs you can download and serve.
