How to call Claude, GPT and Gemini with one API key
Most teams end up with three provider accounts, three keys, three bills, and three SDKs. You can drop to one key if your gateway speaks both the OpenAI and the Anthropic formats. This guide shows how to do that with AIKeys, using the SDKs you already have.
What you need
- An AIKeys account with a positive balance. You top up once and each request draws from it. There is no monthly plan.
- An inference key from the keys page. The secret is shown once, so copy it into an environment variable:
export AIKEYS_CO_KEY="paste-your-key-here"
- A model id. Ids look like
upstream/model, for examplecc/claude-opus-4-7orcx/gpt-5.6-terra. The full list, with prices, is on the models page.
The two base URLs
| SDK | Base URL | Auth header it sends |
|---|---|---|
| OpenAI SDK | https://api.aikeys.co/v1 |
Authorization: Bearer … |
| Anthropic SDK | https://api.aikeys.co |
x-api-key: … |
The Anthropic SDK adds /v1/messages to its base URL itself, so leave /v1 off. Both headers are accepted, so either SDK works with the same key.
Python with the OpenAI SDK
import os
from openai import OpenAI
client = OpenAI(base_url="https://api.aikeys.co/v1", api_key=os.environ["AIKEYS_CO_KEY"])
for model in ["cc/claude-opus-4-7", "cx/gpt-5.6-terra", "ag/gemini-3.1-pro-high"]:
reply = client.chat.completions.create(
model=model,
messages=[{"role": "user", "content": "One sentence: what is a token?"}],
)
print(model, "→", reply.choices[0].message.content)
The loop is the point: switching between Claude, GPT and Gemini is a change to one string.
Python with the Anthropic SDK
import os
from anthropic import Anthropic
client = Anthropic(base_url="https://api.aikeys.co", api_key=os.environ["AIKEYS_CO_KEY"])
message = client.messages.create(
model="cc/claude-sonnet-4-6",
max_tokens=512,
messages=[{"role": "user", "content": "One sentence: what is a token?"}],
)
print(message.content[0].text)
max_tokens is required in the Messages format. You can send a GPT or Gemini id here too. The proxy converts the request for the upstream.
TypeScript
import OpenAI from "openai";
const client = new OpenAI({ baseURL: "https://api.aikeys.co/v1", apiKey: process.env.AIKEYS_CO_KEY });
const reply = await client.chat.completions.create({
model: "cc/claude-haiku-4-5-20251001",
messages: [{ role: "user", content: "One sentence: what is a token?" }],
});
console.log(reply.choices[0].message.content);
cURL
curl https://api.aikeys.co/v1/chat/completions \
-H "Authorization: Bearer $AIKEYS_CO_KEY" \
-H "Content-Type: application/json" \
-d '{"model":"cc/claude-haiku-4-5-20251001","messages":[{"role":"user","content":"Hello"}]}'
List the models your key can call
curl https://api.aikeys.co/v1/models -H "Authorization: Bearer $AIKEYS_CO_KEY"
The id of each entry is exactly what you send as model. Ids must match exactly: cc/claude-haiku-4-5 and cc/claude-haiku-4-5-20251001 are different strings, and only listed ids work.
Errors you may see
| Status | Code | What it means |
|---|---|---|
| 401 | invalid_api_key |
The key is wrong, revoked, or missing. |
| 403 | insufficient_key_scope |
The key is a config key. Use an inference key. |
| 402 | insufficient_quota |
The balance is too low. Top up. |
| 404 | model_not_found |
The model id is not listed. Check /v1/models. |
| 429 | rate_limit_exceeded |
Too many requests. The default is 60 a minute per key. |
| 503 | no_capacity |
No publisher is serving the model at or below the cap. You are not charged. |
A 503 no_capacity is worth handling in code: retry later, or fall back to another model id.
What it costs
AIKeys is a marketplace. Publishers list capacity with an ask, and each request goes to the cheapest live ask. An ask is never more than half the official price. Live prices for every model are on the pricing page, and how per-token pricing works walks through the arithmetic.