# List your API in the catalog — instructions for a coding agent

You are helping an API vendor get listed in this deployment's tool catalog. The deliverable is a
**pull request adding three JSON entries** to `server/seed-data/catalog.json` (`providers`,
`capabilities`, `bindings`), plus a way for the maintainers to reach your team.

This file is v1's `vendor-listing.md`, retargeted: v1 took one YAML file per provider and a Python
registry entry; this stack takes one seed file and one idempotent loader. The eligibility rules,
the capability-first rule and the self-verification ledger are unchanged — they are what makes a
listing usable by an agent, not what made v1's tree look the way it did.

## Before you write anything

Read these three, in this order — they are the authority, this page is only the summary:

- `server/seed-data/catalog.json` — the whole catalog: `providers[]`, `capabilities[]`,
  `bindings[]`. 450 capabilities and two providers ship today; your listing is a diff of it,
  not a new format.
- `server/internal/seed/catalog.go` — how each entry is loaded (business unique keys, which
  columns a re-seed owns and which an admin's edits keep).
- `server/internal/service/data.*` — how a call is executed: auth kinds, pricing, and the
  envelope the agent sees.

Confirm eligibility first. Hard requirements: self-serve API keys (no sales call), the key rides
in a **header or query param** (never the URL path), a free or near-free probe endpoint that
**rejects an invalid key** with a distinguishable response, a published pricing page, and docs
with example parameter values. If any of these fail, stop and tell your user which one — a PR
that fails them will be declined.

## What the PR contains

1. **A `providers[]` row** — the vendor itself, once:
   ```json
   {"slug": "yourapi", "title": "Your API", "base_url": "https://api.yourapi.com",
    "auth_kind": "bearer_header", "auth_config": {"kind": "bearer_header"},
    "catalog_source": "docs-snapshot", "priority_default": 100, "markup": 1,
    "icon_url": "https://yourapi.com/favicon.ico"}
   ```
   `auth_kind` is one of the kinds `server/internal/service` implements (`bearer_header`,
   `hmac_signed`, …). A kind that is not implemented is a rejected PR, not a TODO: the loader
   will accept the row and every call will fail at the auth step.
2. **A `capabilities[]` row per job** — what an agent asks for, independent of you:
   `id` (`travel.airbnb.search` style: domain → product → action), `title_zh` / `title_en`,
   `summary`, `category_path`, and `params_schema` (JSON Schema; typed, `additionalProperties:
   false`, every property described in one sentence an agent can act on).
3. **A `bindings[]` row per endpoint** — how YOUR API does that job: `capability_id`,
   `provider_slug`, `provider_ref` (your path plus the display metadata: `defaultLimit`,
   `maxLimit`, `responseFields`, `returnsList`), `priority`, `strategy`, `pricing_override`
   (`model`, `currency`, `unitPrice`, `unit`, `minCharge`, `chargeOnFailure`, `chargeOnEmpty`),
   and `param_map` when your parameter names differ from the capability's.

## Capability first

For every endpoint, before writing its `capability_id`:

1. **Reuse.** Search `capabilities[]` for the job it does. If a capability exists, use that id —
   never a near-duplicate.
2. **Propose only when missing.** If another provider already has an endpoint doing the same job
   but no capability covers it, add one capability row and name that endpoint in the PR so
   reviewers attach both.
3. **Prefer overlap.** Endpoints sharing a capability with other providers are the ones agents
   compare and route between; a new capability with a single provider is a shelf of one.

## Map the FULL surface before selecting

List every documented operation your API exposes, then choose the 8–15 you catalog. The PR
description must carry that map as a short "catalogued / excluded, because…" list — reviewers
check curation against it, and "we didn't know it existed" is the gap this prevents. Include the
**free count / preview / pre-flight routes** that let an agent size a query before paying for
rows, and include your **cheapest tier** of an operation, not only the default one.

## Self-verify with your OWN key before opening the PR

Docs drift; meters don't. Before the PR goes up, run **every** endpoint live against your own
account and reconcile each `pricing_override` against what the meter actually charged (a per-call
charge field in the response, a rate-card endpoint, or the balance delta). A price transcribed
from a docs page has been wrong by 5× in a real submission — the live meter is the authority, and
a mismatch you find now is a one-line fix instead of a review round-trip.

While you're there:

- Quote the probe's bad-key behavior **from the wire** (run it with a garbage key; record the
  exact status and body, with the date) — not from memory or docs.
- If an endpoint is a **deliberate miss** (a target chosen so a pay-on-success endpoint charges
  nothing), label it as such in the binding's `notes` — and observe the HIT price once on a real
  target so the number is metered, not assumed.

```sh
go run ./cmd/seed --dry-run --domain catalog   # validates and reports the payloads; writes nothing
go test ./internal/seed/... ./internal/service/...   # must pass
```

Do NOT stamp anything as verified and do NOT commit example responses — the maintainers run their
own verification with an independent credential regardless of your evidence. And **never put a
credential value anywhere in the diff**: no API keys in the JSON, the tests, the PR description,
or commit messages.

## The PR description — required

- **A contact email** for your team, stated plainly (e.g. `Contact: partnerships@yourapi.com`).
  The maintainers reach out on this address to arrange a test credential for live verification —
  a PR without it cannot be verified or merged.
- **The self-verification ledger**: one line per endpoint — HTTP status of your live call, the
  price the binding claims, and the price the meter reported, with the date. A PR whose ledger
  disagrees with its own JSON will be bounced.
- **The full-surface map** — every documented operation, marked catalogued or excluded-because.
- Your probe endpoint's exact bad-key behavior (status + body, observed on a dated live call).
- Your pricing page URL and billing model; a machine-readable rate-card endpoint if you have one.
- Whether you publish an OpenAPI spec at a stable URL (enables a machine-generated "extended
  tier" listing of your full endpoint surface).

## What happens next

Maintainers run the live checks: a garbage key presented at your probe must come back rejected,
and every endpoint is called with the test credential you arrange over email. Passing endpoints
are enabled for the deployment; then your API is discoverable by every agent using the catalog —
compared side by side with other providers on price, measured success rate, and speed.
