1. Get an API key
Create an account, verify your email, then open
/keys and create a key. It's shown once, in the form
llmr_sk_live_… — store it like any other secret.
Requests without a valid key, or with a key past its expires_at,
get a 401. New accounts start on prepaid credits — top up at
/settings/credits before sending live traffic.
2. Make a request
The serving API is OpenAI-compatible: POST /v1/chat/completions
with a Bearer key. Setting model:"auto" lets our router pick the
cheapest model that clears the quality bar for your prompt; pinning an explicit model id skips the router entirely.
# model:"auto" — LLMRouter picks the cheapest model that fits
curl https://api.llmrouter.sh/v1/chat/completions \
-H "Authorization: Bearer llmr_sk_live_..." \
-H "content-type: application/json" \
-d '{
"model": "auto",
"mode": "balanced",
"messages": [{"role": "user", "content": "Write a Python web scraper"}]
}'
mode is one of
cost ·
balanced ·
quality — it only affects requests routed via
"auto" and defaults to your key's configured mode.
3. Use the OpenAI SDK
No new client library. Point any existing OpenAI SDK at our base_url
and swap the key — everything else (streaming, tool calls, response shape) works unchanged.
# pip install openai
from openai import OpenAI
client = OpenAI(
base_url="https://api.llmrouter.sh/v1",
api_key="llmr_sk_live_...",
)
# model:"auto" routes; a slug (e.g. "anthropic/claude-opus-4.8") pins it
resp = client.chat.completions.create(
model="auto",
messages=[{"role": "user",
"content": "Summarize this contract..."}],
)
print(resp.choices[0].message.content)
Same idea in any OpenAI-compatible client (Node's openai package,
LangChain, LlamaIndex, etc.) — set the base URL and key, nothing else changes.
Choosing a model
You can call any model in our catalog directly by its slug (provider-prefixed, e.g.
anthropic/claude-opus-4.8,
openai/gpt-5) — see the full, current list at
GET /v1/models or browse
/models. Every model, explicit or
auto-routed, is billed the same way: provider list price plus a flat 1% fee — see
/pricing.
Not sure which model to pick? Leave model:"auto" — the
router predicts what your query needs (reasoning, code, tools, vision, context length) and picks the cheapest model in
the catalog that meets it. Every deployment also carries automatic provider failover, so a single upstream outage
doesn't fail your request.
Streaming
Set stream: true for a standard SSE stream of
chat.completion.chunk events, ending in
data: [DONE] — identical shape to the OpenAI API.
stream = client.chat.completions.create(
model="auto",
messages=[{"role": "user", "content": "Count to 5"}],
stream=True,
)
for chunk in stream:
if chunk.choices[0].delta.content:
print(chunk.choices[0].delta.content, end="")
Failover only happens before the first token — once bytes are streaming, a mid-stream upstream error surfaces as an SSE error event carrying the request's trace id instead of silently switching providers. Non-streaming requests can fail over across the full response.
Response headers
Every response — streaming or not — carries headers explaining the routing decision, so you never have to guess what actually served the request:
| x-llmrouter-model | the model slug that actually served the request |
| x-llmrouter-served-via | which deployment/transport served it (direct, fallback, sandbox) |
| x-llmrouter-cost-usd | total cost billed for this request, provider price + 1% |
| x-llmrouter-trace-id | look this up under /logs for the full request trace |
| x-llmrouter-routing-ms | time spent selecting a model, excluding the upstream call |
| x-llmrouter-difficulty / -reason | present on "auto" requests — why this model was chosen |
Send x-llmrouter-explain: true to also get an
llmrouter: {chosen, ranked, mode, reason, profile}
block inline in the JSON response body. Want to see the decision without spending anything? Call
POST /v1/route with the same body — it returns the
routing decision only, with no upstream call.
Errors & rate limits
Errors are OpenAI-shaped: {"error": {"message", "type", ...}}.
| Status | Meaning |
|---|---|
| 401 | missing, invalid, or expired API key |
| 402 | prepaid credit balance is ≤ $0, or your key's monthly spend cap is reached — top up at /settings/credits |
| 429 | per-key RPM/TPM limit hit — a Retry-After header tells you how long to back off |
A retryable upstream failure (timeout, 429, or 5xx from the provider) doesn't reach you as an error — the gateway automatically walks the ordered fallback list for that model first. You only see an error if every candidate fails.
Test keys (sandbox)
Create a test-mode key at
/keys (prefixed
llmr_sk_test_…) to exercise the full request/response
shape, streaming, and routing decision against an in-process sandbox echo — no upstream call, no spend, no credits required.
Swap in a live key when you're ready to serve real traffic.
Next steps
Authentication
Key formats, scopes, per-key limits, rolling & revoking, test vs. live keys.
Models & routing
How model:"auto" picks a model, and how to pin one explicitly.
Model fallbacks
Ordered cross-model failover when a model is down or rate-limited.
Provider selection
OpenRouter-compatible provider{} preferences within one model.
Streaming
SSE shape, usage accounting, and mid-stream failover semantics.
Tool calling & structured outputs
Cross-provider tools and response_format normalization.
Errors & rate limits
Every status code, the error body shape, and how RPM/TPM/spend caps behave.
Pricing & billing
The 1% fee, prepaid credits, top-ups, auto-reload, and per-key spend caps.
API reference
Every endpoint — request/response shape, auth, and examples.
Browse models
See every routable model, its context length, capabilities, and live price.