API reference
Everything is served from https://api.zenllm.org and authenticated with your API key. OpenAI-compatible, Anthropic-compatible, one catalog.
Introduction
ZenLLM is one API in front of every frontier model, with automatic provider failover and prepaid per-token billing. The base URL for everything is https://api.zenllm.org.
The API is wire-compatible with the OpenAI and Anthropic SDKs: point your existing client at the base URL and keep your code. Streaming uses standard SSE, tool calling passes through natively, and responses always echo the model id you asked for, whichever upstream served it.
curl https://api.zenllm.org/v1/chat/completions \
-H "Authorization: Bearer $ZENLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-fable-5",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'Authentication
Create a key in the dashboard. Keys are shown once and stored hashed; each key can carry its own model allowlist, rate limit, IP allowlist, total spend cap and expiry.
Send it on any endpoint using whichever header your SDK already uses.
# Any one of these works on every endpoint
Authorization: Bearer sk-zenllm-...
x-api-key: sk-zenllm-...
anthropic-api-key: sk-zenllm-... # for Anthropic SDKsErrors and limits
Errors are JSON with a stable shape and never leak upstream provider details. Account rate limits scale with your balance plus lifetime spend (spending credits never lowers your tier): $5+ gives 15 rpm, $10+ 30 rpm, $50+ 70 rpm, $100+ 135 rpm and $200+ 250 rpm; contact support for more.
Failed requests are refunded automatically: billing settles only on completed responses.
- 401auth_error
- Missing or invalid API key, or an IP outside the key's allowlist.
- 402billing_error
- Balance too low, or a key/account spend limit was reached.
- 404not_found
- Unknown model id or route.
- 429rate_limit_error
- Key RPM or account tier exceeded. Honor Retry-After with jitter.
- 502upstream_error
- Every provider in the model's chain failed. Safe to retry.
{
"error": {
"message": "Insufficient credits",
"type": "billing_error",
"code": 402
}
}Overview
Anything that speaks the OpenAI or Anthropic APIs works unchanged, so every tool below connects with just a base URL and a key. Any model id from /v1/models works in any tool: run Claude in an OpenAI client or GPT in an Anthropic one, the router translates.
CORS is open on the /v1 surface, so browser-based tools can call the API directly with your key; no proxy needed. Create your key in the dashboard first, it is shown once.
SillyTavern
The most common RP frontend. Connects through its Chat Completion API.
- 1Open the plug icon (API Connections).
- 2Set API to
Chat Completionand the source toCustom (OpenAI-compatible). - 3Paste the endpoint
https://api.zenllm.org/v1and your key, then press Connect. - 4Pick any model from the list; it loads straight from the live catalog.
Presets work as-is, including prompt post-processing, system prompts and assistant prefill.
API: Chat Completion
Chat Completion Source: Custom (OpenAI-compatible)
Custom Endpoint (Base URL): https://api.zenllm.org/v1
API Key: sk-zenllm-...
Model: claude-fable-5 # list fills from /v1/modelsJanitorAI
JanitorAI calls the API from your browser, which works because CORS is open on /v1. Your key stays in your browser's local storage.
- 1Open a chat and go to API Settings.
- 2Choose
Proxy, then configurationCustom. - 3Set the proxy URL to
https://api.zenllm.org/v1/chat/completions(the full path, not just the base). - 4Enter your key and a model name, save, then use "Check proxy" to verify.
API: Proxy
Configuration: Custom
Model name: claude-fable-5
Proxy URL: https://api.zenllm.org/v1/chat/completions
API Key: sk-zenllm-...Marinara Engine
The local chat, roleplay and game engine. Its custom provider speaks the OpenAI format, and connections can be overridden per chat, so different characters can run on different models.
- 1Open Connections and add a new connection.
- 2Choose
Custom (OpenAI-compatible)as the provider. - 3Set the base URL to
https://api.zenllm.org/v1and paste your key. - 4The model picker fills itself from the catalog; pick one and save.
Connections -> Add Connection
Provider: Custom (OpenAI-compatible)
Base URL: https://api.zenllm.org/v1
API Key: sk-zenllm-...
# the model picker fills itself from /v1/modelsAgnai and Risu
Both connect through their OpenAI-compatible option. Agnai takes the base URL; Risu wants the full chat completions path.
- 1Agnai: in your preset, pick the OpenAI-compatible (third party) service and set the API URL to
https://api.zenllm.org/v1. - 2Risu: under Settings, choose the custom OpenAI-compatible model and set the request URL to
https://api.zenllm.org/v1/chat/completions. - 3Paste your key and type any model id from the catalog.
Preset -> AI Service: OpenAI-compatible / third party
API URL: https://api.zenllm.org/v1
API Key: sk-zenllm-...
Model: claude-fable-5Claude Code
Claude Code speaks the Anthropic Messages API, which ZenLLM serves natively at /v1/messages, streaming, tool use and token counting included.
- 1Export
ANTHROPIC_BASE_URLandANTHROPIC_AUTH_TOKENin your shell, or put them in~/.claude/settings.jsonto make it permanent. - 2Optionally pin
ANTHROPIC_MODELto any catalog id. - 3Run
claude. No login needed; the key is the auth.
export ANTHROPIC_BASE_URL="https://api.zenllm.org"
export ANTHROPIC_AUTH_TOKEN="sk-zenllm-..."
export ANTHROPIC_MODEL="claude-fable-5"
claudeCodex CLI
Codex talks the Responses API, served at /v1/responses. Point it at ZenLLM with a custom model provider.
- 1Add the provider block to
~/.codex/config.toml. - 2Export
ZENLLM_API_KEYin your shell. - 3Run
codex. Switch models any time with/modelor themodelline in the config.
# ~/.codex/config.toml
model = "gpt-5.6"
model_provider = "zenllm"
[model_providers.zenllm]
name = "ZenLLM"
base_url = "https://api.zenllm.org/v1"
env_key = "ZENLLM_API_KEY"
wire_api = "responses"opencode
Register ZenLLM as a provider through the OpenAI-compatible SDK adapter.
- 1Add the provider block to
~/.config/opencode/opencode.json(or a project-localopencode.json). - 2Export
ZENLLM_API_KEY, or paste the key inline if you prefer. - 3Run
opencodeand pick a model with/models.
// ~/.config/opencode/opencode.json
{
"provider": {
"zenllm": {
"npm": "@ai-sdk/openai-compatible",
"name": "ZenLLM",
"options": {
"baseURL": "https://api.zenllm.org/v1",
"apiKey": "{env:ZENLLM_API_KEY}"
},
"models": {
"claude-fable-5": { "name": "Claude Fable 5" },
"gpt-5.6": { "name": "GPT-5.6" }
}
}
}
}Zed
Zed's agent panel supports OpenAI-compatible providers natively.
- 1Add the provider under
language_models.openai_compatiblein yoursettings.json, listing the models you want. - 2Open the agent panel's settings, find ZenLLM and paste your key when prompted.
- 3Select the model from the panel's model picker.
// Zed settings.json
{
"language_models": {
"openai_compatible": {
"ZenLLM": {
"api_url": "https://api.zenllm.org/v1",
"available_models": [{
"name": "claude-fable-5",
"display_name": "Claude Fable 5",
"max_tokens": 1000000
}]
}
}
}
}Cursor
Cursor can route its chat models through any OpenAI-compatible endpoint via the base URL override.
- 1Open Cursor Settings, then Models.
- 2Paste your ZenLLM key into the OpenAI API key field and enable the base URL override with
https://api.zenllm.org/v1. - 3Add the catalog ids you want as custom model names, then hit Verify.
Note: the override applies to chat. Cursor-native features like Tab completions still run on Cursor's own service.
Cursor Settings -> Models
OpenAI API Key: sk-zenllm-...
Override OpenAI Base URL: https://api.zenllm.org/v1
Model names: claude-fable-5, gpt-5.6, ...Cline and Continue
The two big VS Code agents, both with first-class OpenAI-compatible support.
- 1Cline: in provider settings choose
OpenAI Compatible, set the base URL, key and a model id. - 2Continue: add a model entry with
provider: openaiandapiBaseto~/.continue/config.yaml.
API Provider: OpenAI Compatible
Base URL: https://api.zenllm.org/v1
API Key: sk-zenllm-...
Model ID: claude-fable-5LibreChat and Open WebUI
Self-hosted chat UIs. Both can fetch the model list from the catalog, so new models appear without config changes.
- 1LibreChat: add a custom endpoint to
librechat.yamlwithfetch: trueand restart. - 2Open WebUI: in Admin Panel connections, enable the OpenAI API and set the base URL and key.
# librechat.yaml
endpoints:
custom:
- name: ZenLLM
baseURL: https://api.zenllm.org/v1
apiKey: "${ZENLLM_API_KEY}"
models:
default: ["claude-fable-5", "gpt-5.6"]
fetch: trueChat completions
The OpenAI-compatible endpoint and the one most SDKs use. On failure the router retries the model's next provider inside the same request, so a single call survives a provider outage.
Billing settles on completion: with stream: true the final SSE chunk before [DONE] carries the usage object, and that is what your balance is charged. If you cancel mid-stream you pay only for the tokens generated up to the cancel; requests that fail outright cost nothing. Every response carries an x-zenllm-request-id header you can quote to support and match against your ledger.
- modelstringrequired
- Any id from /v1/models, e.g. claude-fable-5.
- messagesarrayrequired
- Chat history: {role, content}. Content can be text or multimodal parts (vision models accept image parts).
- streamboolean
- true streams SSE chunks; the final chunk carries usage.
- max_tokensinteger
- Output cap. Defaults to the model's maximum.
- temperaturenumber
- 0 to 2. Passed through to the model untouched.
- tools / tool_choicearray / string
- Standard OpenAI tool calling, passed through natively. No translation shims.
- response_formatobject
- e.g. {"type": "json_object"} on models that support JSON mode.
curl https://api.zenllm.org/v1/chat/completions \
-H "Authorization: Bearer $ZENLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-fable-5",
"messages": [{"role": "user", "content": "Hello"}],
"stream": true
}'Messages
Native Anthropic Messages format, including system prompts, thinking and tool use. Works unchanged with the official Anthropic SDKs. POST /v1/messages/count_tokens counts without running.
- modelstringrequired
- Any chat model id from the catalog.
- max_tokensintegerrequired
- Required by the Messages format.
- messagesarrayrequired
- User and assistant turns, Anthropic content blocks supported.
- systemstring
- System prompt, kept out of the messages array.
- thinkingobject
- Extended thinking config for models that support it.
- streamboolean
- Server-sent events in Anthropic's event framing.
curl https://api.zenllm.org/v1/messages \
-H "x-api-key: $ZENLLM_API_KEY" \
-H "anthropic-version: 2023-06-01" \
-H "Content-Type: application/json" \
-d '{
"model": "claude-fable-5",
"max_tokens": 1024,
"messages": [{"role": "user", "content": "Hello"}]
}'Responses
The OpenAI Responses format. The router converts between chat and responses dialects when a provider only supports one, so any model works from any format.
- modelstringrequired
- Model id. The router converts dialects when the upstream only speaks chat.
- inputstring | arrayrequired
- Prompt text or structured input items.
- streamboolean
- Streams response events as SSE.
- reasoningobject
- Effort hints for reasoning models that accept them.
curl https://api.zenllm.org/v1/responses \
-H "Authorization: Bearer $ZENLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-5.6",
"input": "Summarize the attached notes.",
"stream": true
}'Embeddings and rerank
OpenAI-compatible embeddings plus POST /v1/rerank for scoring a document list against a query in retrieval pipelines.
- modelstringrequired
- text-embedding-3-large.
- inputstring | arrayrequired
- One string or a batch. Billed on total input tokens.
- top_ninteger
- Rerank only: how many documents to return, best first.
curl https://api.zenllm.org/v1/embeddings \
-H "Authorization: Bearer $ZENLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "text-embedding-3-large",
"input": "The quick brown fox"
}'Images
Image generation and edits. Generations take JSON; POST /v1/images/edits takes multipart form data with an input image.
- modelstringrequired
- gpt-image-2.
- promptstringrequired
- What to draw. For edits, how to change the input image.
- sizestring
- e.g. 1024x1024. Model default when omitted.
- imagefile
- Edits only: multipart input image.
curl https://api.zenllm.org/v1/images/generations \
-H "Authorization: Bearer $ZENLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"model": "gpt-image-2",
"prompt": "isometric server rack, warm charcoal, orange accents",
"size": "1024x1024"
}'Audio
Text to speech returns raw audio bytes; POST /v1/audio/transcriptions takes multipart audio and returns text.
- inputstringrequired
- Speech: the text to speak.
- voicestring
- Speech: voice preset, e.g. alloy.
- filefilerequired
- Transcriptions: multipart audio (mp3, m4a, wav, webm).
- languagestring
- Transcriptions: ISO hint, auto-detected when omitted.
curl https://api.zenllm.org/v1/audio/speech \
-H "Authorization: Bearer $ZENLLM_API_KEY" \
-H "Content-Type: application/json" \
-d '{"model": "tts", "input": "Deploy is live.", "voice": "alloy"}' \
--output speech.mp3Models and health
The catalog with per-model pricing and context windows, no auth required. The detail route also lists the model's provider chain. GET /health reports service status.
curl https://api.zenllm.org/v1/models
# per-model detail incl. provider chain
curl https://api.zenllm.org/v1/models/claude-fable-5
# service health
curl https://api.zenllm.org/health