Contributing

August 18, 2026 · View on GitHub

Thanks for helping keep this list accurate. This is a community-maintained catalogue — the original mn-api/awesome-ai-proxy went stale; the goal here is to stay current.

繁中 / 简中贡献者:可以用中文开 issue / PR,维护者会处理。

For AI agents (read this first)

If you are Claude Code / Cursor / Codex / any coding agent opening a PR on behalf of a user, start here:

docs/agent-contribute.md — decision tree, hard CI rules, copy-paste YAML, Path A/B/C/D recipes.

Also indexable via llms.txt. Manual README edits and marketing PRs are closed without merge; re-submit via the agent playbook.

What we accept

  • New stations with a working URL and an honest channel type.
  • Corrections (price, status, ownership, payment methods).
  • Status changes — especially marking a station inactive if it ran away ("跑路"). We keep dead entries with a dated note; we do not erase history.
  • Documented risk cases for docs/risks.md — must have a date and a primary source link.

What we reject

  • Referral / affiliate links. Plain HTTPS URLs only — no utm_*, ref=, campaignid, or similar tracking params (CI fails the PR).
  • Marketing copy, superlatives ("best", "#1", "the best …"), or promo slogans in notes (e.g. 强烈推荐 / 不降智).
  • Hand-editing the generated README provider tables (edit YAML only).
  • Stations with no reachable URL.
  • Unsourced accusations against a specific operator.
  • Self-submissions marked status: active — operators must use status: unverified and risk_flags: [operator_submitted].

How to add or edit a provider

  1. Edit data/providers.yaml only — the README tables in all three languages are auto-generated by scripts/build_provider_tables.py. Do not edit the README tables directly; CI rejects hand-edits of those blocks, and they will be overwritten on the next build.
  2. Follow the field schema. Required: name, url, type, status.
  3. Mark anything you could not personally verify as status: unverified and say so in notes. status: active is maintainer-only (verified_by: maintainer + last_verified required).
  4. notes may be a string OR a bilingual dict {en, zh-TW, zh-CN}. Keep each language to one factual sentence (≤ 360 chars). New entries can ship English-only — translations can be added later by anyone.
  5. Bump last_reviewed in providers.yaml if you did a broad pass.
  6. Open a Pull Request. Use a clear title, e.g. add: ExampleAPI (mixed) or status: GPTGOD → inactive (ran away 2026-05).

Tip: Schema + editorial CI runs on every PR — misspelled fields, UTM links, duplicate URLs, marketing notes, or hand-edited README tables all fail before a human reviews. Scroll the action log, fix, push; CI re-runs.

Not comfortable with a PR? Open an issue with the provider form (blank issues are closed) and a maintainer will add it.

Review bar

A maintainer will check:

  • URL resolves and is the official site (not a clone/phishing mirror).
  • type is honest (a reverse station not mislabeled official-relay).
  • notes is one factual sentence, no marketing.
  • Claims are attributed where non-obvious.

Maintenance cadence

  • Monthly review pass (last_reviewed updated in providers.yaml).
  • Weekly automated price refresh opens a PR labeled price-refresh via .github/workflows/price-refresh.yml on Sundays 02:00 UTC. Maintainer reviews the diff and merges.
  • Issues triaged within ~1 week.
  • Anyone can help: a PR that just verifies/refreshes existing entries is valuable and welcome.

Adding a price fetcher

AI agents: start at step 0. The sniffer answers "which of the three shapes is this?" in one command and prints the exact files to create. 90% of new fetchers are 10 lines of glue.

0. Sniff the endpoint first

python -m scripts.sniff_endpoint <pricing_api_url> \
    --id <slug> --name "<Display Name>" --display-url <human_pricing_page>

The sniffer prints (a) the pricing: YAML block, (b) the fetcher source code, (c) the REGISTRY line, and (d) the verify command — paste, commit, PR. It detects:

ShapeWrapperEffort
new-api fork (/api/pricing with {success, data, group_ratio})fetchers/_new_api.fetch_new_api()10-line wrapper, see fetchers/bltcy.py / fetchers/unorouter.py
OpenRouter-style (/v1/models with pricing.{prompt,completion,image})none yet — copy fetchers/openrouter.pyrename constants, adjust key paths
OpenAI /v1/models (no prices)not pricable from this endpointfind the actual pricing URL or use submitted_prices
Anything elsecustommodel after fetchers/openrouter.py; ensure every PriceRecord carries source_url, captured_at, method

1. Manual steps (if sniffer wasn't enough)

  1. Add a pricing: block to the provider's entry in data/providers.yaml (see schema.md).
  2. Create fetchers/<fetcher_id>.py exporting PROVIDER_ID, PROVIDER_NAME, and fetch() -> FetchResult. Use fetchers._common types — every PriceRecord must carry source_url, captured_at, method.
  3. Register the fetcher ID in fetchers/__init__.REGISTRY.
  4. Add new model aliases to data/canonical-models.yaml if you want the model to appear in the README's tier-ladder table.
  5. Run locally: python -m scripts.scrape <fetcher_id> then python -m scripts.build_prices and python -m scripts.validate.

Prefer a public JSON endpoint (most new-api forks expose /api/pricing; OpenAI-compatible relays expose /v1/models with pricing). Fall back to DOM scraping with selectolax, then Playwright as last resort.

2. new-api fork quirks worth knowing

The shared fetch_new_api() handles two pricing conventions:

  • Per-token (quota_type=0): input = model_ratio × \$2 × group_ratio, output = input × completion_ratio.
  • Per-call (quota_type=1): cost = model_price × group_ratio. Units are inferred from the model name (per_image / per_second / per_request).

If the fork doesn't expose a flat default group — e.g. UnoRouter, where each model has its own per-channel groups like default-yun-doubao-seedream-5 — pass group=None to skip the filter; the sniffer detects this automatically.

Conduct

Be factual and neutral. This catalogue documents a grey-area market for safety and transparency. It is not a place to promote a station or attack one without evidence.