Drop-in from OpenRouter
KhaBot serves every model in OpenRouter's catalog at the provider's own price, under the same model ids, plus KhaBot's own models and services. Moving an OpenRouter integration over is a two-line change: the base URL and the key. Your requests, model ids and response handling stay as they are.
Switch in two lines
| OpenRouter | KhaBot | |
|---|---|---|
| Base URL | https://openrouter.ai/api/v1 | https://khabot.com/api/v1 |
| Key | sk-or-… | kb_… — create one under API keys |
from openai import OpenAI
client = OpenAI(
base_url="https://khabot.com/api/v1", # was https://openrouter.ai/api/v1
api_key="kb_YOUR_KEY", # was sk-or-…
)
r = client.chat.completions.create(
model="anthropic/claude-opus-4.5", # any OpenRouter model id, unchanged
messages=[{"role": "user", "content": "Hello"}],
)
print(r.choices[0].message.content)
curl https://khabot.com/api/v1/chat/completions \
-H "Authorization: Bearer kb_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "openai/gpt-5.1", "messages": [{"role": "user", "content": "Hello"}]}'
Two kinds of model
| KhaBot models | Pass-through models | |
|---|---|---|
| Ids | khabot/<model> | OpenRouter's ids, as-is — e.g. openai/gpt-5.1 |
| Served by | KhaBot | Passed through to OpenRouter |
| Price | KhaBot's published per-model price | Exactly the provider's reported cost — no markup |
| Billed from | Your plan quota first, then credit | Credit only — never covered by a plan |
| Catalog | The khabot/ set | OpenRouter's whole catalog except :free variants and openrouter/* meta-models, synced daily |
Both appear in the model list and in GET /models, KhaBot models first.
Model ids on pass-through calls
- Variant suffixes work on pass-through ids:
:online,:nitro,:floor,:thinkingand the like — e.g.openai/gpt-5.1:online. modelsfallback arrays work when every model in the array is in the catalog.- Rolling aliases such as
~openai/gpt-latestare real models and work like any other id. - Account presets (
preset/…,@preset/…) aren't models and aren't available. :freeids andopenrouter/*ids are refused with400 bad_request— they aren't part of the catalog. Use the paid id instead.
The rename
KhaBot's own models now use the khabot/ prefix — for example khabot/glm-5.2. The old ids
are gone, with no aliases. Watch out: any id without the khabot/ prefix is treated as
a pass-through request. If an old id happens to match an OpenRouter model, the call is served by OpenRouter —
billed from credit at the provider's price, not from your plan. Update your ids to the khabot/ ones
listed by GET /models.
Billing
- Every pass-through call is billed at exactly the cost the provider reports for it — no markup — from your credit. Plans never cover pass-through calls, so keep credit on the account.
- When your credit is short of a call's estimated cost, it is refused with
402 insufficient_credit. - Pass-through spend counts toward your monthly spend cap (set in Billing), together with extra usage on KhaBot models.
- There is also a daily pass-through limit per account, set by KhaBot as a brake against runaway
use: it counts what you have spent on pass-through calls since 00:00 UTC, plus calls still running, plus the new
call's estimate. Past it, pass-through calls are refused with
402 passthrough_daily_cap_reacheduntil the next UTC day; KhaBot models are unaffected. - The
usage.costin a pass-through response is what KhaBot billed you for that call. - The cost shows up in your usage log immediately for JSON responses, and within a couple of minutes for streamed and file responses, while the final cost is confirmed.
- KhaBot models keep their published prices and plan coverage; see Quotas & plans.
- BYOK applies to KhaBot models' chat only — pass-through calls always use KhaBot's own key.
Errors on pass-through calls
| HTTP | code | When |
|---|---|---|
| 400 | bad_request | The model id isn't servable. The message names the reason: :free variants not available, openrouter/* meta-routers not available, or unknown or unavailable model — see GET /api/v1/models (unknown ids and ids without a price) |
| 402 | insufficient_credit | Your credit is short of the call's estimated cost — redeem a code in Billing |
| 402 | passthrough_daily_cap_reached | “Daily pass-through spend limit reached — try again tomorrow.” Your account hit today's pass-through limit; it resets at 00:00 UTC |
Everything else — authentication, per-key limits, rate limits — works as for any KhaBot call; see Errors.
What passes through
These OpenRouter endpoints work on KhaBot unchanged, for pass-through models. Paths are relative to
https://khabot.com/api/v1.
| Endpoint | Notes |
|---|---|
POST /chat/completions | Any model without the khabot/ prefix |
POST /responses | |
POST /messages | Anthropic format |
POST /embeddings, GET /embeddings/models | |
POST /images | OpenRouter's own image API — a different path from KhaBot's /images/generations |
| Read-only catalog and info routes | GET /models/count, /models/{author}/{slug}/endpoints, /model/{author}/{slug}, /images/models, /providers, /benchmarks, /tools |
Not available: endpoints that store content on the upstream account — /files,
/batches, /videos, /presets and other stored-content routes. They would be
shared between KhaBot customers, so they are switched off. POST /rerank and GET /models/user
(per-account model preferences) answer 404 not_available. The legacy /completions endpoint is not part of what
KhaBot guarantees either — use /chat/completions.
What stays KhaBot's
Where KhaBot has its own endpoint at a path, ours answers — OpenRouter's version of that path isn't reachable through KhaBot:
| Path | Served by KhaBot as |
|---|---|
/images/generations, /images/edits | Images |
/audio/* | Speech to text and text to speech — OpenRouter's audio endpoints are not reachable |
/storage/* | Object storage |
/media/* | Media search |
/web-search | Web search |
/documents, /documents/{key} | Documents storage |
/html-to-markdown | HTML to Markdown |
/key-info | Your key's own limits |
Account endpoints
OpenRouter's management endpoints — /keys, /credits, /auth,
/generation, /activity, /analytics and the like — are not proxied: your
KhaBot account is managed in the dashboard. Three answer with KhaBot's own data, so
clients that check them keep working:
GET /key— the KhaBot key you called with.GET /credits— your KhaBot credit.GET /generation?id=…— a call's details from your KhaBot usage log, for KhaBot request ids.
Every call's cost and usage is also in your usage log.
GET /key
{
"data": {
"label": "laptop",
"limit": 25.0,
"usage": 3.42,
"limit_remaining": 21.58,
"is_free_tier": false,
"is_management_key": false,
"is_provisioning_key": false,
"expires_at": null,
"credit_usd": 12.5
}
}
| Field | Meaning |
|---|---|
label | The key's name — "session" when called from a signed-in dashboard session |
limit, usage, limit_remaining | The key's binding spending limit — the one with the least left (null = no limits) — what it has counted in its current window, and what is left |
is_free_tier, is_management_key, is_provisioning_key | Always false — kept for OpenRouter clients that read them |
expires_at | When the key expires, or null |
credit_usd | Your account's credit balance |
GET /credits
{ "data": { "total_credits": 40.0, "total_usage": 27.5 } }
total_credits − total_usage is your current credit balance.
The model list: GET /models
GET https://khabot.com/api/v1/models returns the catalog in OpenRouter's shape, so tools that read
OpenRouter's model list can read ours. KhaBot models come first. Each entry adds a tier —
curated or passthrough — and pass-through entries carry their openrouter_url.
Prices are in US dollars per token, as strings, like OpenRouter's.
{
"data": [
{
"id": "khabot/glm-5.2",
"name": "GLM 5.2",
"tier": "curated",
"context_length": 200000,
"architecture": { "input_modalities": ["text"], "output_modalities": ["text"] },
"pricing": { "prompt": "0.000003", "completion": "0.000005", "input_cache_read": "0.0000003" }
},
{
"id": "openai/gpt-5.1",
"name": "OpenAI: GPT-5.1",
"tier": "passthrough",
"context_length": 400000,
"architecture": { "input_modalities": ["text", "image", "file"], "output_modalities": ["text"] },
"pricing": { "prompt": "0.00000125", "completion": "0.00001" },
"openrouter_url": "https://openrouter.ai/openai/gpt-5.1"
}
]
}
Trimmed — entries carry more of OpenRouter's metadata than shown, and the prices here are illustrative. For prices per million tokens, see the model list.