pay.sh docs
Building with pay

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 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.

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
starter.yml

Run it:

pay --sandbox server start starter.yml

Call 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.

FieldTypeDescription
namestringMachine-readable provider name. Lowercase, hyphenated.
subdomainstringSubdomain slug — your provider's stable identifier in the catalog.
titlestringHuman-readable provider title.
descriptionstringOne-line summary shown in catalog and 402 challenges.
categoryenumOne of: ai_ml, cloud, compute, data, devtools, finance, identity, maps, media, messaging, productivity, search, security, shopping, storage, translation, other.
versionstringProvider 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_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.

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.001

Full 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: USDC

Full 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.

BlockPurpose
envMap of environment variables set on spec load. Static values are set directly; ${VAR} references the runtime environment. Useful for upstream API keys.
accountingpooled (shared counter across all callers, default) or per_agent (per-wallet counter for volume tiers).
recipientsNamed 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_tierA request budget that's served free before metering kicks in. Useful for evaluation tiers.
quotasPer-window rate limits independent of payment. Use this to cap absolute throughput.
notesFree-form merchant notes shown in the catalog. Not used by the runtime.
sessionSession-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: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

On this page