One API key. 124 models. Three wire formats.
unbottled.ai speaks OpenAI chat completions, the OpenAI Responses API and the Anthropic Messages API on one endpoint. Your SDK stays. Your tools stay. Only the base URL changes.
GPT from OpenAI, Claude from Anthropic, Gemini from Google. Three SDKs, three keys, three bills, three dashboards. Or worse: the tool you like only speaks one format, so it only gets one vendor's models.
unbottled.ai puts 124 chat models from 17 labs behind one key and one credit balance. Call them in the OpenAI format, the Responses format or the Anthropic format. Same models on every endpoint. Here is exactly how it works, what it costs, and where going direct or using a router is the better call.
Five endpoints, one key
Every endpoint takes the same key, bills the same balance and serves the same models.
- POST /v1/chat/completions: OpenAI Chat Completions. Streaming over SSE that ends with data: [DONE], stream_options.include_usage, tool calling. The format almost every OpenAI compatible client speaks.
- POST /v1/responses: the OpenAI Responses API, the format Codex CLI speaks. Streaming and tools. Stateless: store is false and previous_response_id is rejected with 400, so send the full input each turn.
- POST /v1/messages: the Anthropic Messages API. Streaming and tool use. This is what Claude Code and the Anthropic SDKs talk to.
- POST /v1/messages/count_tokens: free. A local estimate, no model call, and it does not count against your per-minute rate limit. Claude Code calls it constantly to size its context.
- GET /v1/models: every model your key can call right now, with context length, tool support and prices. One response body that both the OpenAI and the Anthropic SDKs parse.
Auth works two ways, on every endpoint. Authorization: Bearer sk-unb-... for OpenAI clients and for Claude Code with ANTHROPIC_AUTH_TOKEN. x-api-key: sk-unb-... for the Anthropic SDKs. Keys start with sk-unb-, are shown once and stored only as a hash. Create them under Settings > API keys, up to 20 active keys per account.
For OpenAI SDKs and OpenAI-style tools. The locale is part of the path. It only sets the language of error messages, and any supported locale works, but it has to be there.
Anthropic base URL: https://unbottled.ai/api/en-US
For the Anthropic SDKs and Claude Code. Same URL without /v1: they append /v1/messages themselves.
Code: your SDK, our base URL
No new client library. The official OpenAI and Anthropic SDKs work as they are. Replace sk-unb-YOUR_KEY with your key.
curl
The fastest proof that your key works. A plain chat completion, nothing to install.
curl https://unbottled.ai/api/en-US/v1/chat/completions \
-H "Authorization: Bearer sk-unb-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "kimi-k3.1-pro",
"messages": [
{ "role": "system", "content": "You answer in one sentence." },
{ "role": "user", "content": "Why is the sky blue?" }
]
}'OpenAI Python SDK
Set base_url and api_key on the client, then call chat.completions.create as usual. Any model from GET /v1/models goes in the model field, Claude and Gemini included.
from openai import OpenAI
client = OpenAI(
base_url="https://unbottled.ai/api/en-US/v1",
api_key="sk-unb-YOUR_KEY",
)
reply = client.chat.completions.create(
model="kimi-k3.1-pro",
messages=[{"role": "user", "content": "Why is the sky blue?"}],
)
print(reply.choices[0].message.content)The same client also speaks the Responses API. Call client.responses.create. Remember it is stateless here: pass the whole conversation as input every turn.
reply = client.responses.create(
model="kimi-k3.1-pro",
input="Why is the sky blue?",
)
print(reply.output_text)Anthropic Python SDK
Set base_url without /v1 and your key as api_key, then call messages.create. Reasoning models put a thinking block first, so the sample prints the text block, not the first block.
import anthropic
client = anthropic.Anthropic(
base_url="https://unbottled.ai/api/en-US",
api_key="sk-unb-YOUR_KEY",
)
reply = client.messages.create(
model="kimi-k3.1-pro",
max_tokens=1024,
messages=[{"role": "user", "content": "Why is the sky blue?"}],
)
# Reasoning models put a thinking block first: print the text block.
print(next(block.text for block in reply.content if block.type == "text"))Need a size before you send? count_tokens returns an estimate for free, without calling a model.
curl https://unbottled.ai/api/en-US/v1/messages/count_tokens \
-H "x-api-key: sk-unb-YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-sonnet-4-5-20250929",
"messages": [{ "role": "user", "content": "Why is the sky blue?" }]
}'List the models
GET /v1/models is the source of truth. It shows exactly which ids your key can call, with context length, tool support and price per token.
curl https://unbottled.ai/api/en-US/v1/models \
-H "Authorization: Bearer sk-unb-YOUR_KEY"Model ids: ours, or the vendor's
You do not have to rewrite configs that already name a model. We accept the common spellings.
- Our ids, as GET /v1/models lists them: claude-sonnet-5.5, gpt-6.1-sol, glm-5.3. Use these when you start fresh.
- Vendor spellings work too. Date-stamped Anthropic ids (claude-sonnet-4-5-20250929 resolves to claude-sonnet-4.5), dashed version numbers, -latest suffixes, the [1m] context suffix, and dotted ids like gpt-5.5.
- Provider prefixes such as anthropic/... or openai/..., so OpenRouter-style ids from an existing config keep working.
- On /v1/messages only: a Claude id your account cannot call, like the built-in ids Claude Code sends for its background calls, falls back to the newest Claude of the same family (Opus, Sonnet or Haiku) that you can call. Claude Code works without extra env vars. Any other unknown id returns 404 model_not_found.
Use Claude Code and Codex CLI with other models
Both connect directly. No proxy, no translation layer, nothing to install.
Every snippet defaults to glm-5.3. It passed real Claude Code and Codex CLI runs, calls tools reliably and costs little per output token. Swap it for any id once things work.
Claude Code
ANTHROPIC_BASE_URL="https://unbottled.ai/api/en-US" \
ANTHROPIC_AUTH_TOKEN="sk-unb-YOUR_KEY" \
ANTHROPIC_MODEL="glm-5.3" \
ANTHROPIC_DEFAULT_OPUS_MODEL="glm-5.3" \
ANTHROPIC_DEFAULT_SONNET_MODEL="glm-5.3" \
ANTHROPIC_DEFAULT_HAIKU_MODEL="glm-5.3-flash" \
CLAUDE_CODE_SUBAGENT_MODEL="glm-5.3" \
CLAUDE_CODE_MAX_CONTEXT_TOKENS="1048576" \
CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC="1" \
claudeThat is the whole answer to using Claude Code with other models. ANTHROPIC_BASE_URL points it at us, ANTHROPIC_AUTH_TOKEN carries your key, and the model variables decide what runs. Replace the model id with any id from GET /v1/models: GPT, Gemini, Kimi, DeepSeek or an uncensored model. CLAUDE_CODE_MAX_CONTEXT_TOKENS is set to that model's real context window, so Claude Code compacts at the right point.
Codex CLI
UNBOTTLED_API_KEY="sk-unb-YOUR_KEY" codex \
-c 'model_providers.unbottled={name="unbottled.ai",base_url="https://unbottled.ai/api/en-US/v1",env_key="UNBOTTLED_API_KEY",wire_api="responses"}' \
-c model_provider=unbottled \
-m glm-5.3Codex CLI gets a custom model provider with wire_api set to responses. It talks the Responses API to us exactly as it does to OpenAI. Change the model with -m.
OpenCode, Continue, Aider and Cline work too, all tested. Their setups, the permanent config files and the gotchas we hit are in the coding tools guide.
Set up every coding toolWhich model for which job
Every model below supports tool calling. Click a name for its price and specs, copy the id into your code.
Frontier: the hardest code and reasoning
Large refactors, unfamiliar codebases, long reasoning chains. Higher price per token, fewer wrong turns.
- Claude Sonnet 5.5claude-sonnet-5.5
- GPT-6.1 Solgpt-6.1-sol
- Gemini 4 Argongemini-4-argon
- Kimi K3.1 Prokimi-k3.1-pro
- DeepSeek V4 Prodeepseek-v4-pro
Cheap and fast: loops, bulk, background calls
Agent loops that send big prompts, batch jobs, classification, the background calls coding tools fire all day. A fraction of frontier prices.
- GLM-5.3glm-5.3
- GLM-5.3 Flashglm-5.3-flash
- Qwen 3.8 Flashqwen-3.8-flash
- Claude Haiku 5.5claude-haiku-5.5
Uncensored: no refusal reflex
GLM 5.3 Uncensored and Qwen 3.6 Plus Uncensored are mainstream models with the refusals removed. UncensoredLM v1.2 is different: its own worldview, not just a stripped model. Same API, same tools.
- GLM 5.3 Uncensoredglm-5.3-uncensored
- Qwen 3.6 Plus Uncensoredqwen-3.6-plus-uncensored
- UncensoredLM v1.2uncensored-lm-v1.2
Torn between two? The comparison pages put two models side by side.
What it costs
Credits, billed per token. No seat fees.
- Most models bill at their listed per-token price plus our markup. Cached input tokens bill at the model's cache price. Models served through OpenRouter bill the real cost OpenRouter charged for the call, plus the same markup.
- Every response reports usage.credits_charged. You never have to guess what a call cost.
- Before a call runs, your balance is checked against a worst-case estimate. Not enough means HTTP 402 insufficient_credits: nothing runs, nothing is charged.
- Streaming: close the connection and generation stops. You pay only for what ran. Same if the provider fails mid-stream.
- Chat and API bill the same way. OpenRouter spreads a model across several hosts, and some charge more than the cheapest one we list. So for those models the listed price is an estimate, and usage.credits_charged is the real number. If OpenRouter reports no cost for a call, it bills at the listed price.
- Same credit balance as the chat app, which also covers image, video, music, voice and web search there. The API itself needs a paid account: an active subscription or at least one credit pack. Free credits do not unlock it.
- Subscription: 800 credits a month for $8.00.
- Credit pack: 500 credits for $5.00. Packs never expire. Pay by card or crypto.
Go direct, use a router, or use us?
Three honest options. Each is the right one for somebody.
Going direct to OpenAI, Anthropic or Google
The newest first-party features land there first. No middleman markup. One vendor's terms to read. If you only ever use one vendor's models, go direct.
An aggregator such as OpenRouter
Many models, pay as you go. Full disclosure: many of our models are served through OpenRouter. If raw routing is all you need, go there.
unbottled.ai
One key across three wire formats: chat completions, Responses, and Anthropic Messages with count_tokens. Claude Code and Codex CLI connect without a proxy. Uncensored models sit next to mainstream ones, behind a one-time 18+ confirmation. The same balance pays for the chat app and the API, from subscription credits or packs. And unbottled.ai is open source and self-hostable.
Limits you should know
No surprises in production. These are the hard edges.
- Stateless. The Responses API runs with store set to false and rejects previous_response_id. Send the full history every turn. That holds for every endpoint.
- Output is capped at 32768 tokens per request.
- 60 requests per minute per key by default. Over the limit you get 429 with a Retry-After header. Agents that fire many calls get their own key.
- count_tokens is an estimate, not the provider's exact tokenizer. Good for sizing context, not for billing math.
- Tool calls only work on models that support them. Otherwise you get 400 tools_not_supported. GET /v1/models shows supports_tools for every model.
- Uncensored models need a one-time 18+ confirmation on the API keys page. Without it you get 403 uncensored_consent_required, and nothing is charged.
What happens to your prompts
Short version: we keep the bill, not the conversation.
- The API saves no conversation and creates no threads. What stays on our side is the billing record: which model, how many credits.
- Your prompt goes to the provider that serves the model. Its terms apply to what it receives.
- In the chat app, incognito chats live only in your browser's local storage, not on our servers.
FAQ
Is unbottled.ai an OpenRouter alternative?
For many uses, yes: one key, many models, pay per token. The differences: unbottled.ai speaks the Anthropic Messages API and the OpenAI Responses API natively, not just chat completions. It carries uncensored models. And the chat app runs on the same balance. Many of our models are served through OpenRouter underneath.
Can I use Claude Code with non-Claude models?
Yes. Set ANTHROPIC_BASE_URL to the unbottled.ai Anthropic base URL, put your key in ANTHROPIC_AUTH_TOKEN and pick any model id from GET /v1/models. GPT, Gemini, GLM, Kimi, DeepSeek and the uncensored models all run in Claude Code that way.
Do I need a new SDK?
No. Use the official OpenAI and Anthropic SDKs. Change the base URL and the key. Nothing else.
Is there a free tier for the API?
No. The chat app has free credits, the API does not. It needs a subscription (800 credits a month for $8.00) or one credit pack (500 credits for $5.00). A pack bought once keeps the API working until the balance runs out.
Is the listed price what I pay?
For most models, yes: listed per-token price plus our markup. Models served through OpenRouter bill the real cost OpenRouter charged for the call, plus the same markup, in the chat app and on the API alike. Their listed price is an estimate. Every response reports the exact charge in usage.credits_charged.
Which models can I call?
124 chat models right now: Claude, GPT, Gemini, DeepSeek, Kimi, GLM, Qwen and uncensored models. GET /v1/models lists exactly what your key can call, with prices.
Does unbottled.ai store my prompts?
Not from the API. No conversation is stored, only the billing record: model and credits charged. The provider that serves the model does see the prompt, under its own terms.
One key. Every model. Start now.
Create a key, change one base URL, keep your SDK. The API docs cover every endpoint, field and error code.