Model routing
Route Multiple AI Models Through One API: One Key, Any Model
Use a single OpenAI-compatible Base URL and API key to route Claude, Gemini, DeepSeek and other models. Setup, model switching, cost checks, and failure handling.
One key for every model
Routing multiple AI models through one API means your application keeps a single Base URL, a single API key, and a single request shape, while the model field decides which upstream provider handles the call. You do not store one credential per vendor, and you do not rewrite the client when a new model appears.
The practical benefit is operational: one billing balance, one place to rotate a leaked key, one set of logs, and one place to change a model. The trade-off is that the gateway now sits in the request path, so you must verify what it forwards and how it counts tokens. This guide shows the smallest useful setup, how to call different model families with the same key, and how to check the result against your bill.
What happens after you send a model name
A request usually carries four things that matter for routing: the model identifier, the message or prompt payload, the streaming flag, and optional feature fields such as tool definitions or cache controls. The gateway resolves the model identifier to an enabled channel and price group, converts the request into that provider's native protocol, and converts the response back into the format your SDK expects.
Two details are worth confirming before production. First, model names are versioned: a name that works in a playground may not exist on your key's group. Second, routing is not free abstraction — features such as prompt caching, tool calling, structured output, and reasoning tokens are only equivalent if the gateway forwards them. Test the specific features you depend on instead of assuming compatibility from a successful text response.
| Field | What it controls |
|---|---|
| model | Which provider channel and price group handles the request |
| messages / input | Context sent upstream, and the main driver of input tokens |
| stream | Whether the response is Server-Sent Events or one JSON body |
| tools, response_format | Whether the gateway must forward a provider-specific feature |
Set up one key and send your first request
Create a key in API Access, then confirm the model you intend to use on the pricing page. Use the OpenAI-compatible endpoint for a first check even when the target model is not an OpenAI model: the gateway converts the request. Keep the first call small, with a low output limit and no tools or caching.
Set the key as an environment variable rather than hard-coding it. On macOS or Linux, export API_ROUTE_KEY=... applies to the current shell only; on Windows PowerShell, use $env:API_ROUTE_KEY="...". The example below sends a single chat completion and prints whatever the model returns.
export API_ROUTE_KEY="sk-your-key"
curl https://global.api-route.com/v1/chat/completions \
-H "Authorization: Bearer $API_ROUTE_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-6",
"messages": [{"role": "user", "content": "Name one trade-off of multi-model routing."}],
"max_tokens": 80
}'A 200 response with a choices array means the request reached a provider and came back. It does not yet prove that streaming, tools, caching, or a second model family works. Add those checks one at a time, using the response body to confirm the model name and the usage object.
Switch model families without switching SDKs
The same key can call Claude, Gemini, DeepSeek, Qwen, and other model families because the gateway converts between protocols. For chat-shaped traffic, send every request to /v1/chat/completions and change only the model value. The request and response shapes stay the OpenAI-compatible ones your code already handles.
When you need Anthropic-specific behaviour such as prompt caching or a particular beta header, call /v1/messages with that model instead and use the Anthropic request format. Both endpoints share the same account balance, which is what makes a single-key setup practical. Cross-model API references: OpenAI Chat Completions and Anthropic Messages.
from openai import OpenAI
client = OpenAI(
base_url="https://global.api-route.com/v1",
api_key="sk-your-key",
)
for model in ["claude-sonnet-4-6", "gemini-3.8-flash", "deepseek-v4.1-flash"]:
reply = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "Reply in one sentence."}],
max_tokens=60,
)
print(model, "->", reply.choices[0].message.content)const models = ["claude-sonnet-4-6", "gemini-3.8-flash"];
for (const model of models) {
const res = await fetch("https://global.api-route.com/v1/chat/completions", {
method: "POST",
headers: {
"Content-Type": "application/json",
Authorization: `Bearer ${process.env.API_ROUTE_KEY}`,
},
body: JSON.stringify({
model,
messages: [{ role: "user", content: "Reply in one sentence." }],
max_tokens: 60,
}),
});
const data = await res.json();
console.log(model, "->", data.choices?.[0]?.message?.content ?? data.error?.message);
}Two models in one loop is enough to prove the routing layer is doing what you expect. Log the returned model name and the usage object for each call; if a model silently falls back to another family, the text may still look plausible while quality and price change.
Choose a model per request, not per project
Once one key reaches every model, the interesting decision moves from "which vendor do we sign with" to "which model should handle this request". Classify your traffic first: short classification and extraction calls rarely need a frontier model, long-context analysis does, and code generation usually needs a different trade-off than chat. Route by task, then measure quality on your own evaluation set rather than on benchmark headlines.
Price groups matter as much as model names. A model can be listed at one rate for a default group and another for a discounted or enterprise group, and the group attached to your key determines what you actually pay. Check the group shown on the pricing page and in your call logs before you build a budget around a headline number.
| Workload | What to optimise | Typical choice |
|---|---|---|
| Classification, extraction, tagging | Cost per thousand calls | Small fast model |
| Long-context analysis, RAG answers | Context window and cache cost | Mid-tier model with prompt caching |
| Complex coding and agent loops | Correctness and tool use | Frontier model, low temperature |
| Bulk generation | Output price and throughput | Mid-tier model with batching |
Verify the route and the bill
Before scaling, confirm three things: the same key can list the models you plan to call, the response returns the model you asked for, and the logged charge matches the usage object. Listing models is the cheapest check and catches keys bound to a narrow group.
curl -s https://global.api-route.com/v1/models \
-H "Authorization: Bearer $API_ROUTE_KEY" \
| jq -r '.data[].id' | sortThen compare a single response with the matching row in call logs. Check the model, the input and output token categories, and whether any cache fields are present. A cached request should report cache reads separately; if the gateway never reports them, treat the cache as unverified rather than as a discount. Keep one recorded request per model family as a reference sample so a future price or routing change is visible.
Common failures and what they mean
Most first-week problems are configuration, not model quality. The table below maps the errors worth checking first. When reporting an issue, include the request time, HTTP status, model name, and request ID, and never paste the key itself.
| Symptom | Likely cause | First check |
|---|---|---|
| 404 model not found | Model not enabled for your key group | List models with /v1/models, then compare with the pricing page |
| 401 or 403 | Key missing, revoked, or sent in the wrong header | Send Authorization: Bearer, and rotate the key if it was exposed |
| 400 on a schema field | Provider rejects a keyword the gateway did not translate | Remove the field and retest; report the exact parameter |
| Streaming stalls or arrives at once | Proxy buffering or an unsupported stream flag | Retest without stream, then with a short prompt |
| Costs higher than expected | Different price group, or cache writes instead of reads | Compare usage with the log row and confirm the group |
If the response is a 200 but behaves like a different model, compare outputs on a fixed prompt across a few requests and check the returned model name. Consistency problems usually point at routing or fallback policy, not at the prompt.
Production checklist
- Store the key in a secret manager or environment variable, and keep a second key ready for rotation.
- Pin explicit model identifiers instead of floating aliases, and record the version you tested.
- Send a fixed smoke request per model family after every configuration change.
- Alert on error rate and on cost per request, not only on total spend.
- Compare the first bill against the usage objects you logged before scaling traffic.
With those five checks in place, one key and one Base URL are enough to route traffic across model families without rebuilding your client. Start with a small balance, create an account, confirm the model list for your key, and follow the quickstart for the first request.