Model names
A model name is <providerId>/<model>:
1claude/claude-sonnet-52codex/gpt-5.6-sol3openrouter/meta-llama/llama-3.1-70b
Every request names its provider. The prefix is the usual way; there are two others, and nothing else is accepted:
| You send | Example |
|---|---|
| A prefixed id | "model": "claude/claude-sonnet-5" |
A bare id plus the x-aile-provider header | "model": "claude-sonnet-5" + x-aile-provider: claude |
| A bare id on a key pinned to one provider | see API keys |
A bare id with none of these is a 400 that points at GET /v1/models, with two
exceptions for coding tools that send bare ids from their own model pickers. With no
x-aile-provider header, key pin or x-aile-capacity: local:
- from Claude Code (
User-Agent: claude-cli/…) it goes toclaude; - from the Codex CLI (an
originatorheader startingcodex_orcodex-, or acodex_cli_rs/User-Agent) it goes tocodex.
You can also name no provider on purpose: auto/ instead of a provider
(auto/claude-sonnet-5), or a bare id with x-aile-provider: any (or a comma list
of providers), sends the model to each provider that lists it, cheapest first,
never self-hosted. auto is reserved, like local: no provider is named it. See
Any provider for a bare model.
Aliases: cc, gh, kr
A provider may declare a short caller-facing alias. There are three in the catalogue today:
1cc/claude-sonnet-5 ≡ claude/claude-sonnet-52gh/<model> ≡ github/<model>3kr/<model> ≡ kiro/<model>
GET /v1/models advertises the alias form; the router accepts both. The alias is
resolved once at the input boundary and re-substituted in the response, so your
SDK sees back the same string it sent.
Header and prefix together
The header names the provider, and the model is sent to it as written. An aggregator's own ids can start with a vendor segment, so this is fine:
1x-aile-provider: openrouter2{ "model": "deepseek/deepseek-v4-flash" }
A prefix naming the same provider (claude/… or cc/… with
x-aile-provider: claude) is dropped, so an id that starts with its own
provider's name needs it twice (groq/groq/compound). Any other id goes as-is.
If the provider doesn't serve it, the request fails uncharged: a 400 from the
provider is passed through, other refusals come back as a 503.
One exception: on a provider whose own ids never carry a prefix (claude,
codex and most direct providers, but not aggregators such as openrouter), an
id prefixed with another provider is refused with a 400 before anything is
dialled, naming both. A key pinned to claude that sends codex/gpt-5.6-sol is the
usual case: use a key that is not pinned, or name a claude model.
No cross-provider fallback
If you name a provider, that provider serves you or the request fails.
- An unknown prefix is a
400that names the ids it does know. - A known provider with no available sharer is a
503that names that provider.
Why this is a guard and not a limitation
Falling through to a different provider produced errors like "The 'claude/claude-sonnet-5' model is not supported when using Codex with a ChatGPT account", an upstream complaint about a routing decision the caller never made. Failing cleanly on the provider you asked for is the more useful answer.
Caller format is independent of provider format
The endpoint you POST to decides the wire dialect, not which models you can reach:
| You call | Your SDK speaks | Models you can reach |
|---|---|---|
/v1/chat/completions | OpenAI | any provider |
/v1/messages | Anthropic | any provider |
/v1/responses | OpenAI Responses | any provider |
So POST /v1/messages with codex/gpt-5.6-sol works, and so does
POST /v1/chat/completions with cc/claude-sonnet-5. Aile pairs a source bridge
(your body → canonical OpenAI Chat) with a format translator (canonical → the
provider's bespoke shape) as needed.
Stop reasons translate with the body: a Claude answer cut by max_tokens or by
the model's context window arrives on the OpenAI endpoints as
finish_reason: "length", and a Claude refusal as "content_filter".
What GET /v1/models shows
A live aggregation over the current sharer pool, cached 60 seconds, rather than a
static catalogue. A model is present only if somebody can serve it now, and only
once a sharer's account has passed a test of that model (a self-hosted model,
once its machine has answered a probe). A model nobody has tested yet is not
listed, but naming it still reaches any sharer who offers it: listing gates
nothing. The cheapest sharer is tried first; between sharers at the same price,
one whose account passed the test goes first.
Self-hosted models appear as local/<model>. A chat row's display_name is
<model> (<provider name>).
Some things are deliberately hidden rather than advertised and then failing:
- providers whose transport format is unsupported;
- a handful of clients that are not servable through this surface;
- GitLab Duo when the relay has no OAuth client configured for it.
1curl https://api.aile.sh/v1/models2curl https://api.aile.sh/v1/models/cc/claude-sonnet-5
Both are public. GET /v1/models/{id} is registered as a wildcard because ids
contain slashes; an unknown id is a 404 in OpenAI's error shape, and a cold
cache that cannot load is a 503.
What each row carries
Beside id, type (the endpoint to POST to) and the modalities, a row may carry:
| Field | What it is |
|---|---|
context_length, max_output_tokens, knowledge_cutoff | The model's limits on that provider. A provider's own window wins where it states one (codex/… lists the ChatGPT backend's, not OpenAI's API's). Chat rows only. |
capabilities | tool_calling, structured_output, reasoning, each present only when known. Absent means unknown, not "no". |
reasoning_efforts | The effort levels this provider's copy offers, weakest first: { effort, label, description?, sends? }. Send effort as reasoning_effort (or reasoning.effort, output_config.effort). Absent when nobody declared one. |
pricing | The most a call can cost, from the published list (a sharer sells at list or below): unit plus max_usd_per_mtok_in / _out on token models (the dearest the list reaches: its long-context band, and audio or image output; audio and image input bill at their own rates), with max_usd_per_mtok_cache_read and max_usd_per_mtok_cache_write where the model publishes a cache price (the one-hour write where the route bills one), or max_usd_per_unit on a per-unit model (image, kchar, minute, second, track, search, input, page, query, webpage). An openai/gpt-image-* row, and openrouter/bytedance-seed/seedream-5-0-pro, add max_usd_per_input_image. The exact figure is in the 402 or x-aile-price. |
x402 | { keyless, networks }: whether a wallet with no account can pay for this model right now, and on which chains (CAIP-2 ids). ?x402=keyless lists only those. |
created | When the model was released, as epoch seconds (OpenRouter's field), from the publisher's release date. Chat rows only. |
deprecated | Always true, and only when the publisher has deprecated or retired the model. |
supported_parameters | The request parameters Aile forwards for this model on the wire it is served over (tools, temperature, response_format, reasoning_effort, …), narrowed by what the model can do. Listed means Aile forwards it; an unlisted parameter may still be forwarded, dropped, or refused. |
privacy | What the provider says it does with API traffic: trains_on_prompts (no, yes or account when it depends on the account's plan), and where known retention_days, jurisdiction and the source page. Absent means unknown, never a promise of anything. |
data_policy | Only on a model whose publisher trains on what you send (below). |
hosted_tools | Only on a model whose provider can run tools on its own servers (below): types (what to put in tools), endpoint (where to send it), max_usd_per_unit (the most each thing the tool fetches can cost, by its counter in the reply's usage) and a notice on how it is billed. |
1curl "https://api.aile.sh/v1/models?x402=keyless"
Live X search
Grok on grok-cli can search X while it answers. Rows that support it carry
1"hosted_tools": { "types": ["x_search"], "endpoint": "/v1/responses", "max_usd_per_unit": { "x_posts_fetched": 0.005 }, "notice": "Runs on the provider's servers. Billed on the tokens the provider reports, which can exceed x-aile-price. Not payable by x402. A stake key pays for it from its fallback key. Each unit the tool fetches is billed on top, as counted in usage.server_side_tool_usage_details: up to $0.005 per x_posts_fetched (list price; the sharer's margin applies; at most 1000 of each per request)." }
Send "tools": [{ "type": "x_search" }] to POST /v1/responses with a grok-cli/ model, or the same tool to POST /v1/chat/completions or POST /v1/messages. On those two, web_search_options (OpenAI) and web_search_20250305 (Anthropic) are sent as Grok's web_search, without their location, max_uses or context-size settings. An Anthropic web search limited to some sites is refused rather than sent unlimited. The answer comes back as text with the post links in it; the searches Grok ran never appear as tool calls for your client to run. /v1/responses also returns them as custom_tool_call items, with the citations. The searches run on the provider's servers and the posts they return count as input tokens, so the charge follows the usage the provider reports and can be several times x-aile-price. Each X post a search fetches is also billed on top of the tokens: $0.005 per post at list, times the sharer's margin (0 to 1), so max_usd_per_unit is the most a post can cost. The count is usage.server_side_tool_usage_details.x_posts_fetched in the reply, at most 1,000 posts are billed per request, and neither x-aile-max-price nor a $AILE discount applies to this part. The staker discount is not offered on such a request (x-aile-discount: ineligible). A three-search answer we measured fetched 24 posts, which is $0.12 at list. Your spendable balance when the request starts is the limit. A key's credit limit is checked against the quoted price, so one such request can go past it. Only single-turn requests have been tested. Such a request cannot be paid by x402, and a stake key pays for it from its fallback key. web_search is accepted on the same rows and billed on its tokens only. On xai and xai-oauth these tools are refused on /v1/chat/completions and ignored on /v1/responses, because that host bills them to the sharer per call.
Models that train on your prompts
Some models are sold cheap because their publisher trains on what you send
them: Meta's -contributor ids (meta/muse-spark-1.3-contributor, and the
same ids on muse-code and resellers). Their rows carry
1"data_policy": { "trains_on_prompts": true, "notice": "The model's publisher trains on the prompts and completions sent to this model." }
and every served chat reply from one says x-aile-data-notice: trains-on-prompts,
except a reply held past 25 s (x-aile-edge-hold, see
Headers) from a route entry that is not the last.
Over MCP, use_model puts the same data_policy in the result's _meta. Other
rows carry no data_policy. Pick a standard id for anything you would not
hand to the publisher.
data_policy keeps this meaning and nothing else: it marks a model, whichever
account serves it. privacy is the provider's published policy for the whole
route, and a missing privacy is not a statement that nothing is kept.
Filtering by output
Each row's output_modalities is its category, in OpenRouter's words: text,
image, video, speech, transcription, embeddings, rerank,
decisions, audio. type still names the endpoint to POST to.
1curl "https://api.aile.sh/v1/models?output_modalities=speech,transcription"
Values may be comma- or +-separated, or the parameter repeated. A row matches if
any value you list is in its output_modalities; a row with none counts as text. With no filter, or all, you get every model (OpenRouter
defaults to text). An unknown value, or all with anything else, is a 400.
Named routes are different
A key can carry aliases that map your own name to a provider, a model, and a fallback chain:
1{ "model": "fast/summarise" }
When the string matches one of the key's aliases, the slash separates your handle from your model. A route name is exempt from the provider rule; each target in it must name a provider.
Which entry in the chain served comes back as x-aile-combo-entry. See
API keys.
Self-hosted models are local/<model>
A sharer's own machine answers to the name it advertises. Send it under
local/, which Aile strips before forwarding:
1local/llama32local/Qwen/Qwen2.5-7B-Instruct
x-aile-provider: local with the bare name does the same. local is not a
provider in the catalogue; it only selects self-hosted capacity.