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 and Subscriptions: YAML specification.
Agent summary
- Every spec needs
name,subdomain,title,description,category,version,routing, and at least one entry inendpoints[]. routing.type: respondreturns 200 directly after payment verification — useful when you don't have an upstream yet.routing.type: proxyforwards verified-paid requests to an upstream URL.operatoris optional; when omitted, the operator signer falls back to the active account in~/.config/pay/accounts.yml.metering:andsubscription: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.
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.001Run it:
pay --sandbox server start starter.ymlCall the metered endpoint:
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.
# 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_KEYproxy 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.
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.
- 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.
- method: POST
path: 'v1/generate'
description: 'Generate content.'
metering:
dimensions:
- direction: usage
unit: requests
scale: 1
tiers:
- price_usd: 0.001Full pricing reference: Defining pricing.
Subscription endpoint
Add a subscription: block to charge a recurring fixed amount for unlimited access within a billing period.
- method: GET
path: 'v1/pro/feed'
description: 'Pro feed — monthly subscription.'
subscription:
period: '30d'
price_usd: 9.99
currency: USDCFull reference: Subscriptions: YAML specification.
Path parameters
Use {name} placeholders for variable path segments. They're forwarded to the upstream verbatim under proxy routing.
- 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.
pay --sandbox server start provider.yml --bind 127.0.0.1:1402For 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 — request, token, character, page, and volume-tiered pricing for metered endpoints.
- Subscriptions: concept — when to use a subscription endpoint over per-call pricing.
- Subscriptions: examples — six runnable subscription specs you can download and serve.