English | 中文
Friends: LINUX DO - 新的理想型社区
Sync pricing, channels, and models from upstream providers to your new-api instance. Supports new-api, sub2api, OpenRouter, and NVIDIA NIM upstreams.
First install Bun if you don't have it.
bun install
cp config.example.yml config.yml # edit with your config
bun sync run # run sync
bun sync run --only myprovider # sync one provider
bun sync run --models "claude-*,gpt-4*" # sync only matching models
bun sync run --verbose # run with debug logging
bun sync reset # delete all synced dataIf you'd rather click than type, launch the bundled dashboard:
bun ui # shortcut for `bun sync ui`
bun sync ui --port 4000 # custom port (default 3000)Then open http://localhost:3000. Everything the CLI can do is exposed through the UI, no YAML editing required:
- Dashboard: run or reset pipelines live. A streaming log panel shows every provider, model, and price in real time, with colors preserved from the CLI output. Pick which providers to touch (matches
--only), restrict to specific models with glob wildcards (matches--models, e.g.claude-*, gpt-4*), and hit Start. The models filter persists per config, so switching between configs restores your last selection. - Configuration: edit every provider, target, blacklist, price adjustment, model mapping, and per-model overrides through structured forms. Invalid YAML is validated before save and rolled back if it fails.
- Multiple configs: create named variants (
debug,staging,prod) from the dropdown next to the tabs. Each is stored asconfig.<name>.ymlnext to the binary (or in the project root in dev mode) and can be switched, duplicated, or deleted without touching the filesystem directly. Cross-config settings (locale, theme, shared blacklist, shared model mapping) live inconfig.global.yml. - History: browse past runs (
logs/YYYY-MM-DD-*.json) with per-model pass/fail results, costs, and authenticity status. Authenticity auto-blacklist entries are manageable from the same tab. - Themes & locales: toggle dark/light/system and switch between English and 中文; both are remembered across sessions.
The UI is bundled as a single-file binary for every platform, so the target machine does not need Bun installed. Grab the right one from dist/ after bun run build (or release artifacts) and run it directly:
./new-api-sync-linux-x64 ui # Linux
./new-api-sync-darwin-arm64 ui # macOS (Apple silicon)
new-api-sync-windows-x64.exe ui # WindowsTwo files are loaded on startup:
config.yml(or a named variantconfig.<name>.yml): the active sync config (target, providers, etc.).config.global.yml(optional): cross-config settings.locale,theme, and UI state are stored here.blacklistandmodelMappingdefined here merge into every config (global blacklist entries are unioned with per-config; global mapping wins on key collisions).
| Field | Description |
|---|---|
baseUrl |
Your new-api instance URL |
systemAccessToken |
System Access Token (Settings > Other) |
userId |
Your user ID |
targetPrefix |
Optional prefix for sync resources |
| Field | Description |
|---|---|
testModelTypes |
Model types to test during sync: ["text", "image", "video", "audio", "embedding"] (default: ["text"]). Per-provider setting overrides. |
skipUnprofitableText |
Drop text models whose effective ratio >= 1 (default: true). See Behaviors to Know. |
globalConcurrency |
Total simultaneous test/probe HTTP requests across the whole run (default: 50). |
perUpstreamConcurrency |
Default per-baseUrl request cap (default: 5). Per-provider override allowed for upstreams that tolerate more or less. |
blacklist |
Exclude matching groups/models (text only, case-insensitive). Supports glob wildcards and provider-scoped patterns. See Blacklist below. |
modelMapping |
Rename models: { "claude-sonnet-4-5-20250929-thinking": "claude-sonnet-4-5-20250929" } |
| Field | Required | Description |
|---|---|---|
name |
yes | Unique identifier, used as channel tag |
baseUrl |
yes | Provider URL |
systemAccessToken |
yes | System Access Token from provider |
userId |
yes | Your user ID on the provider |
enabledVendors |
Filter by vendor: anthropic, openai, google, etc. |
|
enabledModels |
Glob patterns or per-model overrides (see below) | |
testModelTypes |
Override global test types: ["text", "image"] |
|
priceAdjustment |
Number or per-key object (see Price Adjustment below) | |
perUpstreamConcurrency |
Override the global per-upstream concurrency cap |
Provide either adminApiKey (auto-discovers groups) or groups (explicit group API keys).
| Field | Required | Description |
|---|---|---|
name |
yes | Unique identifier, used as channel tag |
baseUrl |
yes | Sub2API instance URL |
adminApiKey |
Admin API key, auto-discovers groups, accounts, and models | |
groups |
Explicit groups: [{ "key": "sk-...", "platform": "anthropic" }] |
|
enabledVendors |
Filter by vendor: anthropic, openai, google |
|
enabledModels |
Glob patterns or per-model overrides (see below) | |
testModelTypes |
Override global test types | |
priceAdjustment |
Number or per-key object (see Price Adjustment below) | |
perUpstreamConcurrency |
Override the global per-upstream concurrency cap |
Pulls from OpenRouter. Free models (prompt=0 and completion=0) are emitted as a free tier; paid models are bucketed under a per-vendor channel and a single shared group_ratio is picked from the candidate ladder [1, 0.5, 0.25, 0.1, 0.05, 0.01] such that every kept model stays at or below canonical retail. Models that don't fit at any candidate are dropped.
| Field | Required | Description |
|---|---|---|
name |
yes | Unique identifier, used as channel tag |
apiKey |
yes | OpenRouter API key |
baseUrl |
Defaults to https://openrouter.ai/api |
|
models |
Explicit model IDs (e.g. moonshotai/kimi-k2.6:free); skips discovery |
|
enabledVendors |
Filter discovered models by vendor prefix (anthropic, openai, ...) |
|
enabledModels |
Glob patterns. Bare IDs (no *) are also added to the candidate set |
|
ratio |
Free-tier group ratio (default 0) |
|
testModelTypes |
Override global test types | |
priceAdjustment |
Number or per-key object (see Price Adjustment below) | |
perUpstreamConcurrency |
Override the global per-upstream concurrency cap |
Pulls from NVIDIA NIM. Text models are emitted as a free tier; image models are emitted with fixed per-request pricing (quotaType: 1) against a separate imageBaseUrl.
| Field | Required | Description |
|---|---|---|
name |
yes | Unique identifier, used as channel tag |
apiKey |
yes | NVIDIA API key |
baseUrl |
Defaults to https://integrate.api.nvidia.com |
|
imageBaseUrl |
Defaults to https://ai.api.nvidia.com |
|
models |
Explicit model IDs; skips auto-discovery | |
enabledVendors |
Filter by inferred vendor | |
enabledModels |
Glob patterns. Bare image-model IDs (no *) are added to the set |
|
ratio |
Text-tier group ratio (default 1) |
|
testModelTypes |
Override global test types | |
priceAdjustment |
Number or per-key object (see Price Adjustment below) | |
perUpstreamConcurrency |
Override the global per-upstream concurrency cap |
blacklist removes matching text models from sync. Non-text types (image, video, audio, embedding) are never filtered by the blacklist.
-
Case-insensitive match against the model ID.
-
Glob wildcards supported:
gpt-5.*-codex,*-preview. -
Provider-scoped patterns use
provider/patternsyntax. The part before the slash must match the provider'sname; the part after is the glob. Example:blacklist: - nsfw # unscoped: blocks any provider's model containing "nsfw" - "*-preview" # unscoped: blocks any provider's preview models - duck/gpt-5* # scoped: only blocks gpt-5* models from the "duck" provider - yun/claude-*-opus # scoped: only blocks claude opus models from "yun"
A small built-in blacklist is always merged in to suppress a handful of upstream IDs that are uniformly broken or mis-typed (embedding/audio/video models served as text). You don't need to add these in your config.
priceAdjustment accepts either a single number or a keyed object:
-
Number: applies uniformly. Must be in the open range
(-1, 1).-0.5= 50% cheaper,0.1= 10% more expensive. -
Object: keyed by model name glob, vendor name, model type, or
default. Resolved in that order. Must contain adefaultkey. Numeric keys for non-text types may go up to1; text-type keys (vendors, model globs that resolve to text, anddefault) must stay below1so the resulting channel never costs more than calling the upstream directly. Example:priceAdjustment: default: -0.3 image: 0.5 anthropic: -0.1 gpt-5*: -0.5
enabledModels accepts string globs or objects keyed by model:
enabledModels:
- "claude-*-4-5*" # plain glob
- model: "gpt-5"
metadata:
maxOutputTokens: 32768
isReasoning: true
- type: "image"
model: "flux-pro"
modelPricingGrid:
- { "size": "1024x1024", "price": 0.04 }
- { "size": "2048x2048", "price": 0.08 }metadatais forwarded to new-api's per-modelmetadataJSON column (consumed by client UIs to drive per-model behaviors like bumpingmax_tokensfor reasoning models).modelPricingGriddefines fixed per-request pricing tables for image/video/audio models.
- Discover: fetch models/groups from each provider, filter by vendor, blacklist, and glob patterns
- Test: verify each model with a minimal API request
- Build desired state: merge pricing (GroupRatio, ModelRatio, CompletionRatio), build channels and policy
- Diff: compare desired state against current target state
- Apply: create, update, and delete channels, models, and options
- Cleanup: remove orphaned models
Channels are named {group}-{provider}. When a provider's models split into multiple price tiers, channels get numeric suffixes: {group}-{provider}-t0, -t1, etc. Sub-splits (caused by per-model price overrides or task model pins) add a letter: -t0a, -t0b. Priority is dynamic: cheapest groups first, faster response times get higher priority.
By default, text models whose effective ratio (group ratio x priceAdjustment) is >= 1.0 are skipped so sync never creates channels more expensive than calling the upstream directly. Non-text types (image, video, audio, embedding) are unaffected.
Disable via global config:
skipUnprofitableText: falseIn addition to the unprofitable-text gate, every offer that would charge a user more than the canonical retail ratio (resolved from LiteLLM, then OpenRouter, then basellm) is dropped before sync. There is no user-facing knob for this cap; it is always 1x of canonical retail. This applies to sub2api offers and OpenRouter paid offers.
Certain video/image models are pinned to specific channel types in new-api: sora, kling, vidu, jimeng, hailuo, seedance, veo, imagen, wan. Some also append a path suffix to the provider's baseUrl (e.g., wan becomes /alibailian). This happens automatically and produces a separate sub-channel.
During sync, model descriptions and tags are fetched from two public feeds to enrich the metadata shown in new-api:
- OpenRouter
/api/v1/models: descriptions (preferred) - basellm
llm-metadata: descriptions (fallback) and tags
These calls are best-effort: failures are logged as warnings and do not block the sync. Fuzzy name matching handles version/date-suffix variants (claude-sonnet-4-5-20250929 resolves to claude-sonnet-4.5).
logs/authenticity-blacklist.json is maintained automatically by the test runner to track Anthropic Claude models from providers that failed authenticity checks. This is internal state, but entries can be reviewed and removed from the History tab in the UI.