# ElevenRouter documentation Generated 2026-09-20T14:20:31.506Z from https://elevenrouter.com/docs. # ElevenRouter documentation ElevenRouter gives you one OpenAI-compatible API in front of many model providers, with routing, fallbacks and exact billing at official prices. [View as Markdown](https://elevenrouter.com/docs/md/index) ## How it works You send an OpenAI-style chat completion request to `https://elevenrouter.com/api/v1/chat/completions` with your ElevenRouter key. The gateway resolves the model, picks the healthiest provider endpoint that can serve it, translates the request to the provider's wire protocol when needed, streams the answer back and bills your organization the model's official per-token price. ```bash curl https://elevenrouter.com/api/v1/chat/completions \ -H "Authorization: Bearer $ELEVENROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "openai/gpt-5.6-luna", "messages": [{"role": "user", "content": "Hello!"}]}' ``` ## Base URL All endpoints live under `https://elevenrouter.com/api/v1`. Authenticate with `Authorization: Bearer sk-er-v1-...`. Keys are created in the [dashboard](https://app.elevenrouter.com/keys). ## Supported protocols One key, one bill, several dialects — every route shares the same routing, fallbacks and metering: - `POST /chat/completions` — OpenAI Chat Completions (native). - `POST /messages` — Anthropic Messages, usable with the Anthropic SDKs for any model. - `POST /responses` — OpenAI Responses API. - `POST /completions` — legacy text completions. - `POST /embeddings` — OpenAI embeddings, billed on input tokens. ## Next steps - [Quickstart](https://elevenrouter.com/docs/quickstart) — first request in two minutes with curl, Python or TypeScript. - [API reference](https://elevenrouter.com/docs/api-reference) — every endpoint, parameter and response field. - [Routing & fallbacks](https://elevenrouter.com/docs/routing) — control which providers serve you and what happens on failure. - [Keys, limits & billing](https://elevenrouter.com/docs/limits) — spend limits, rate limits, credits and the ledger. --- Source: https://elevenrouter.com/docs # Quickstart Create a key, send a request, read the usage and cost back. [View as Markdown](https://elevenrouter.com/docs/md/quickstart) ## 1. Create an API key Sign in to the [dashboard](https://app.elevenrouter.com/keys), open **API keys** and create a key. Keys look like `sk-er-v1-…` and are shown once. Optionally set a USD spend limit and a per-minute rate limit. ## 2. Send a request Any OpenAI SDK works by changing the base URL, and the official [ElevenRouter SDKs](https://elevenrouter.com/docs/sdks) add typed access to everything else. Build your first request here — pick a model, toggle streaming or a route receipt, and copy the snippet in the language you use: Model Fallback models (comma-separated) System prompt (optional) User message Temperature Max tokens Routing Stream JSON output Route receipt (X-ER-Metadata) ```bash curl https://elevenrouter.com/api/v1/chat/completions \ -H "Authorization: Bearer $ELEVENROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "anthropic/claude-sonnet-5", "messages": [ { "role": "user", "content": "Explain what an AI gateway does in two sentences." } ] }' ``` Replace $ELEVENROUTER_API_KEY with a key from the dashboard. Nothing you type here is sent anywhere. Or the shortest possible version with curl: ```bash curl https://elevenrouter.com/api/v1/chat/completions \ -H "Authorization: Bearer $ELEVENROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{"model": "openai/gpt-5.6-luna", "messages": [{"role": "user", "content": "Hello!"}]}' ``` ## 3. Read usage and cost Pass `"usage": {"include": true}` to receive the exact cost of the request inside the `usage` object (also on the final streaming chunk), or call `GET /generation?id=…` with the response `id` afterwards. ```json { "id": "gen-Qm3bHk9ZP2xT7Y1L", "model": "anthropic/claude-sonnet-5", "provider": "Anthropic", "choices": [{ "index": 0, "message": { "role": "assistant", "content": "..." }, "finish_reason": "stop" }], "usage": { "prompt_tokens": 21, "completion_tokens": 38, "total_tokens": 59, "cost": 0.000422 } } ``` ## 4. Pick models Model identifiers are canonical slugs like `anthropic/claude-opus-4.6` or `deepseek/deepseek-v4-flash`. Upstream-style aliases (`claude-opus-4-6`, `gpt-5.6-sol`) are accepted too, as are `~vendor/family-latest` aliases and `@preset/slug` references. List everything with `GET https://elevenrouter.com/api/v1/models`. ## 5. Go to production Give every environment its own workspace and keys, set a budget with alerts, add a fallback model, and enable a route receipt while you integrate — the [best practices](https://elevenrouter.com/docs/best-practices) page is a ten-minute checklist. Coding agents can read the docs as Markdown from [llms.txt](https://elevenrouter.com/docs/llms.txt) or operate the account through the [MCP server](https://elevenrouter.com/docs/integrations#mcp). --- Source: https://elevenrouter.com/docs/quickstart # Changelog & versioning The API is v1. Additive changes ship continuously; anything breaking is announced here 90 days ahead with a migration guide. [View as Markdown](https://elevenrouter.com/docs/md/changelog) ## Versioning policy - `Path version` *(v1)*: Only changes for incompatible wire-format breaks. None are planned; the OpenAI and Anthropic dialects are stable targets. - `Additive changes` *(no notice)*: New endpoints, optional request fields, response fields, headers and error codes can appear at any time. Clients must ignore unknown fields. - `Breaking changes` *(90 days notice)*: A deprecated entry here, an email to organization owners and a Deprecation response header precede any removal. - `Model lifecycle` *(per model)*: deprecated_at → retired_at → successor forwarding (opt-out per organization). Vendors retire models on their own schedule; ElevenRouter mirrors it with deprecated_at, retired_at and successor on each model, and forwards retired models to the successor unless your organization opts out. - `Machine-readable` *(GET /changelog)*: https://elevenrouter.com/api/v1/changelog returns these entries as JSON; the OpenAPI document is versioned with the API. ## Entries ### 2026-09-20 API 1.10.1 - addedmodelsClaude Fable 5.1 and DeepSeek V4.1 Flashanthropic/claude-fable-5.1 (1M context, 128K output, adaptive thinking, $10/$50 per 1M tokens with cache reads at $0.25) and deepseek/deepseek-v4.1-flash (1M context, 384K output, native vision, $0.30/$1.20 per 1M tokens at peak list price) are available on the API, in the Playground, in Cursor plans and as ~anthropic/claude-fable-latest. deepseek/deepseek-v4-flash is deprecated with V4.1 Flash as its successor; it keeps serving.[Learn more](https://elevenrouter.com/docs/models) - fixedapiLeaked upstream template markup is stripped from answersSome relays serve a model through a mismatched prompt template and let control markup escape into the visible answer (for example DSML tool-call closers such as after the text when reasoning is on, or ChatML end tokens). These are now removed from every answer, streamed or not, on every dialect and in Cursor, before anything is billed or rendered; the receipt records how many were removed as pipeline.artifacts_removed.[Learn more](https://elevenrouter.com/docs/routing) - addedservicesServices: a dedicated Cursor endpoint, key and plansBuy a Cursor plan from Services in the dashboard and get a base URL and key made for Cursor. The endpoint accepts every request shape Cursor sends through its base-URL override (Responses-style bodies, flat and grammar tools, thinking), renders replies the way Cursor parses them, answers the Verify button locally, and exposes models under neutral aliases so agent mode, tools and images work. Plans are data-driven (recurring, fixed-term or credit packs; USD allowance or unlimited with fair-use limits; per-plan model sets) and paid from the credit balance with automatic renewal, grace and expiry. Cursor keys (sk-er-cursor-v1-…) are refused by the regular API and regular keys by the Cursor endpoint.[Learn more](https://elevenrouter.com/docs/tools/cursor) ### 2026-09-16 API 1.9.1 - changedroutingPrecise errors when your provider preferences rule out every endpointRequests that max_price, require_parameters or only/ignore/order leave without an endpoint now fail with a 404 naming the preference to relax (no_endpoints_within_max_price, no_endpoints_supporting_parameters, no_endpoints_matching_provider_preferences) instead of a generic 503 model_unavailable. Prompts far beyond the model context are refused up front with context_length_exceeded instead of after an upstream round trip. Models no key can serve are no longer published in GET /models, and ~latest aliases only ever resolve to servable members.[Learn more](https://elevenrouter.com/docs/routing) - fixedapiRequest extensions never reach upstreams; response envelopes are strictly OpenAI-shapedplugins, session_id and metadata are stripped before a request is forwarded (strict OpenAI-compatible gateways rejected them), and upstream-specific top-level fields are dropped from chat completion responses and chunks. Streaming responses now carry x-er-model and x-er-provider like non-streaming ones; raw text/plain file uploads work as documented.[Learn more](https://elevenrouter.com/docs/reference) - addedobservabilityBroadcast: signed webhooks, OTLP collectors and S3 bucketsForward every finished generation to your own stack. Destinations are per organization or workspace (up to five), batched, retried with backoff and paused after repeated failures; delivery health is visible in the dashboard. Optional bodies when I/O logging is on.[Learn more](https://elevenrouter.com/docs/enterprise#broadcast) - addedprivacyI/O logging with encryption, retention and deletionOpt-in storage of prompts and completions (AES-256-GCM at rest), per workspace or organization, with a 1–365 day retention window, a “Prompt & response” tab in Logs and deletion APIs for single generations or bulk.[Learn more](https://elevenrouter.com/docs/enterprise#io-logging) - addedroutingPrivate modelsRegister your own OpenAI-compatible endpoints; their models appear as private/… ids visible only to your organization and route with the normal failover, receipts, budgets and logs. Private network ranges are refused.[Learn more](https://elevenrouter.com/docs/enterprise#private-models) - addedapiOAuth PKCE key exchange and credit linesPOST /auth/keys exchanges a user-approved code (PKCE, S256) for an API key scoped to the organization the user picked. Organizations billed in arrears get credit lines with 50/80/100 % alerts and monthly invoices that credit the balance when paid.[Learn more](https://elevenrouter.com/docs/enterprise#oauth) - addedapiPlugins: web search grounding, PDF parsing and server toolsRequest `plugins`: `web` adds cited search results (fee per result, itemised on the receipt and included in cost.total; `:online` is shorthand), `file-parser` extracts text from PDFs for models without native file input, `server-tools` lets the model call safe built-ins (datetime, search_models) in gateway-side rounds. Guardrail policies gain a `plugins` rule to block plugins or cap their spend.[Learn more](https://elevenrouter.com/docs/plugins) - addedapiFiles and Batch APIsPOST /files (JSON base64 or raw body) stores documents and JSONL inputs; messages may reference them as { type: "file", file: { file_id } }. POST /batches runs JSONL requests through the gateway asynchronously with output and error files, cancellation and expiry.[Learn more](https://elevenrouter.com/docs/plugins#batches) - addedapiImages, rerank, speech and transcription endpointsPOST /images/generations (per image), POST /rerank (per token), POST /audio/speech (per character, cost in x-er-cost) and POST /audio/transcriptions (per minute, JSON base64 body) route non-text models with the same failover and receipt. GET /models/modalities lists models per modality.[Learn more](https://elevenrouter.com/docs/plugins#media) - fixedbillingConcurrent settlements on one key no longer deadlockTwo simultaneous requests on the same API key could deadlock at settlement (FOR UPDATE against the key row while a foreign-key share lock was held). Settlement now takes a NO KEY UPDATE lock; no customer-visible change beyond fewer 500s under high concurrency. ### 2026-09-15 API 1.5.0 - addedsdkOfficial TypeScript and Python SDKs, MCP server`@elevenrouter/sdk` and the `elevenrouter` Python package are thin clients generated from the OpenAPI document: chat (with streaming), responses, messages, embeddings, models, generation lookup, credits, analytics and the management API. The `@elevenrouter/mcp` server lets coding agents search models, look up prices and generations, and summarise usage.[Learn more](https://elevenrouter.com/docs/sdks) - addeddocsDocs restructure, generated API reference, llms.txt per page, docs assistantDocumentation is organised into Overview, Models & routing, Features, Privacy & data handling, Best practices, Cookbook and Integrations. The API reference is generated from the OpenAPI document. Every page is available as Markdown at /docs/md/ (and via llms-full.txt) and can be copied with one click. A docs assistant answers questions using ElevenRouter itself.[Learn more](https://elevenrouter.com/docs) - addedplatformPublic status page with 90-day model uptimeGET /status (and the /status page) reports per-model and per-vendor availability from the routing engine with 90 days of history, plus operator-authored incidents and scheduled maintenance.[Learn more](https://elevenrouter.com/status) - addedapiManagement API: workspaces, budgets, policies, presets, notification rules, BYOK, membersEverything the dashboard can do is available to management keys under /management, audit-logged and rate-limited (120 requests/minute per key). Inference keys accept `preset_id` and honour the account key-lifetime policy.[Learn more](https://elevenrouter.com/docs/organization#management-api) - addedroutingPresets: `@preset/slug` in `model`Saved request configurations with versions. `@preset/slug` serves the current version, `@preset/slug@3` pins one; presets can also be pinned to a key. The route receipt reports `pipeline.preset`.[Learn more](https://elevenrouter.com/docs/organization#presets) - addedapiGuardrail policies and `403 policy_blocked`Model/vendor access, request limits, prompt-injection detection and sensitive-information redaction run before credits are reserved. Blocked requests return `403 policy_blocked` with the policy name and rule in `error.metadata`; redactions are reported in `pipeline.policies`.[Learn more](https://elevenrouter.com/docs/organization#guardrails) - addedapi`403 vendor_not_allowed` for account-level vendor controlsOrganizations can allow- or block-list vendors account-wide. Refusals name the vendor (never an upstream provider).[Learn more](https://elevenrouter.com/docs/organization#privacy-controls) ### 2026-09-14 API 1.3.0 - addedroutingProvider preferences: `max_price`, `require_parameters`, latency and throughput thresholdsCap what an endpoint may charge, route away from endpoints that would drop parameters, and demote endpoints whose observed p50 latency or throughput miss your thresholds.[Learn more](https://elevenrouter.com/docs/routing) - addedrouting`:thinking` variant, `~vendor/family-latest` aliases and the model lifecycleModels carry `family`, `deprecated_at`, `retired_at` and `successor`. Deprecation is announced with response headers; retired models are forwarded to their successor unless the organization opts out.[Learn more](https://elevenrouter.com/docs/routing#lifecycle) - addedapiResponse cache (`X-ER-Cache`), `middle-out` transform and response healingExact repeats can be served free from a per-key cache. `transforms: ["middle-out"]` trims oversized prompts from the middle. The `response-healing` plugin repairs malformed JSON output and validates it against your schema.[Learn more](https://elevenrouter.com/docs/routing#cache) - changedapiUpstream rate limits surface as `429 upstream_rate_limited`When every eligible endpoint is throttled the gateway now returns 429 with the vendor `Retry-After` instead of 503. Platform limits keep `X-RateLimit-*` headers.[Learn more](https://elevenrouter.com/docs/limits#rate-limits) ### 2026-09-13 API 1.2.0 - addedapiAnalytics API for management keys`GET /analytics/metrics` lists metrics, dimensions and filters; `POST /analytics/query` runs the same engine that powers Activity.[Learn more](https://elevenrouter.com/docs/observability#analytics-api) ### 2026-09-12 API 1.1.0 - addedapiRoute receipt (`X-ER-Metadata: enabled`), session and user attributionOpt into an `elevenrouter_metadata` object on every response with routing, cost breakdown and timing. `X-ER-Session-Id` / `session_id` and `X-ER-User-Id` / `user` group requests in Logs.[Learn more](https://elevenrouter.com/docs/api-reference#receipt) - changedbillingZero-completion insurance and credit orderingResponses with zero completion tokens and a blank or error finish reason are not charged. Promotional credits are spent before grants, then purchased credits.[Learn more](https://elevenrouter.com/docs/limits#insurance) ### 2026-09-10 API 1.0.0 - addedapiGeneral availability of /api/v1Chat completions, responses, messages, legacy completions and embeddings with automatic failover across credentials and vendors, billed at official vendor pricing.[Learn more](https://elevenrouter.com/docs/quickstart) Subscribe in code: poll `GET /changelog` and diff on `date` + `title`, or watch the `Deprecation` headers on responses for model retirements that affect you. --- Source: https://elevenrouter.com/docs/changelog # Models and pricing Canonical model identifiers, aliases and how prices are applied. [View as Markdown](https://elevenrouter.com/docs/md/models) ## Identifiers Models are addressed by canonical slug: `vendor/model`, for example `anthropic/claude-opus-4.6`, `openai/gpt-5.6-sol`, `deepseek/deepseek-v4-pro`, `moonshotai/kimi-k3`. Provider-native ids such as `claude-opus-4-6` or `claude-haiku-4-5-20251001` resolve to the same model. The full list with live availability is on the [models page](https://elevenrouter.com/models) and at `GET https://elevenrouter.com/api/v1/models`. ## Price components ```text cost = uncached_prompt_tokens x prompt_price + cached_prompt_tokens x cache_read_price + cache_write_tokens x cache_write_price + completion_tokens x completion_price (reasoning tokens are completion tokens) + request_fee ``` Prices are stored per million tokens with an effective date; the price in force at request time is snapshotted on the generation, so historical activity always shows what you were actually charged. --- Source: https://elevenrouter.com/docs/models # Routing and fallbacks How ElevenRouter chooses an endpoint for each request and what you can control. [View as Markdown](https://elevenrouter.com/docs/md/routing) ## Default routing Each canonical model is backed by one or more provider endpoints and credentials. ElevenRouter continuously learns which credential can reach which model (listing sync every few minutes plus live feedback), tracks health with an exponentially weighted error rate and latency per endpoint, and applies circuit breakers and cooldowns. Requests go to the healthiest eligible endpoint; if it fails before any output was sent, the next one is tried automatically. Credentials are also checked against what their provider reports about them: expired, exhausted or revoked credentials are skipped before a request is sent, and a credential whose remaining balance cannot cover the request's worst-case cost is skipped too. Among credentials that can all serve a model, the one expiring soonest is used first. The public `/models` list exposes the outcome as `endpoints_available` and `availability` (`available`, `degraded`, `unavailable`). When nothing can serve a model you receive a `model_unavailable` error; supply `models` fallbacks to keep serving. ## Provider preferences ```json { "model": "anthropic/claude-opus-4.6", "messages": [...], "provider": { "order": ["anthropic"], "allow_fallbacks": true, "ignore": [], "only": [], "sort": "latency" } } ``` Providers are identified by the model vendor's slug (`anthropic`, `openai`, `google`, …) — the same prefix as the model id — or, for your own attached keys, the provider slug shown on the BYOK page. This matters mostly with `models` fallbacks across vendors and with your own keys. - `order`: providers to try first, in this order. - `allow_fallbacks` (default true): when false, only providers in `order` are used. - `only` / `ignore`: restrict or exclude providers. - `sort`: `price`, `latency` or `throughput` to override the default health-weighted ordering. Platform endpoints all charge the official model price, so `price` only changes the order once cheaper endpoints (for example your own provider keys) are attached to a model. - `max_price`: `{ "prompt": 3, "completion": 15, "request": 0 }` in USD per million tokens / per request. Endpoints whose official price is above a cap are skipped (your own keys are compared at their BYOK fee price), so combined with `models` fallbacks you can say "never pay more than this". When the cap rules out every endpoint the request fails with a 404 `no_endpoints_within_max_price` that quotes the cap and the official price. - `require_parameters` (default false): by default, parameters a model or wire protocol cannot honour (for example `logprobs` on Claude) are dropped and listed under `pipeline.dropped_parameters` in the route receipt. Set it to `true` to route only to endpoints that support every parameter you sent; with no such endpoint the request moves to the next `models` fallback or fails with a 404 `no_endpoints_supporting_parameters` naming the parameters. Likewise `only` / `ignore` / `order` that leave no endpoint fail with `no_endpoints_matching_provider_preferences`. These are distinct from `model_unavailable` (503), which means the platform itself cannot serve the model right now. - `preferred_max_latency` / `preferred_min_throughput`: a number (applies to the p50) or `{ "p90": 800 }`-style object against the endpoint's measured time-to-first-token (ms) and output tokens/s over its last 200 successful requests. Endpoints that miss the bar are *demoted*, never dropped, so the request still succeeds when nothing meets it. - `quantizations`: accepted for compatibility and ignored — the vendors we route to do not expose quantization. ## Model variants Shorthands appended to any model id: - `model:nitro` — prioritise throughput (tokens per second), e.g. `openai/gpt-5.6-luna:nitro`. - `model:floor` — prioritise the lowest price. - `model:thinking` — turn reasoning on at medium effort unless the request sets `reasoning` itself. Fails with `variant_unsupported` on models that cannot reason. - `:online` and `:extended` are reserved and currently return `variant_unavailable`. An explicit `provider.sort` always wins over the suffix. Responses and the activity log report the canonical model id; the suffixed id you sent is kept as the requested model. Variants also work on `/messages`, `/responses`, `/completions`, `/embeddings` and `GET /models/:id`. ## Latest aliases `~vendor/family-latest` always resolves to the newest live model of a family, so you can track a vendor's current generation without changing code: `~anthropic/claude-sonnet-latest`, `~openai/gpt-terra-latest`. The response's `model` is the concrete model that answered and is billed at that model's official price. `GET /models` exposes each model's `family` and, on the newest member, its `latest_alias`. Retired models never resolve; the alias moves to the next member automatically. ## Deprecation and retirement Models carry `deprecated_at`, `retired_at` and `successor` in the catalog. While deprecated, responses include `x-er-model-deprecated` (the retirement date) and `x-er-model-successor`; a *Deprecations* alert rule notifies you when a model you use is scheduled for retirement. After retirement, requests are forwarded to the successor — the response says so with `x-er-model-forwarded-from` and `pipeline.forwarded_from` — unless your organization turns forwarding off, in which case you receive `404 model_retired` naming the replacement. ## Response cache Send `X-ER-Cache: true` to serve exact repeats of a request from a cache scoped to your API key. Hits are free, skip the vendor entirely and are recorded in Logs with a cache badge. The key covers the model and every parameter that changes the answer; it ignores `stream`, `usage`, `metadata`, `session_id`, `user` and routing preferences, so a streaming request can be served from a cached JSON answer (replayed as one chunk). ```text X-ER-Cache: true # opt in for this request X-ER-Cache-TTL: 3600 # seconds, 60 … 604800 (default 3600) X-ER-Cache-Clear: true # ignore what is stored and overwrite it # response X-ER-Cache: HIT | MISS | BYPASS X-ER-Cache-Age: 42 # seconds since the answer was stored (HIT) X-ER-Cache-TTL: 3600 X-ER-Cache-Source-Id: gen-… # the generation that produced the cached answer (HIT) ``` Only complete, non-streamed answers are stored; insured (empty) answers never are. An organization can switch the cache off under Settings, after which requests get `BYPASS`. Deleting a key deletes its cache. ## Message transforms `"transforms": ["middle-out"]` makes an oversized conversation fit the model's context window: messages are removed from the middle (system messages, the opening turn and the two latest turns are always kept; tool calls and their results go together), then the longest remaining message is trimmed in the middle. The receipt's `pipeline.transforms` reports what was removed and the prompt size before and after. ## Structured outputs and response healing `response_format` with `json_schema` is forwarded to models that support structured outputs; on models that only support JSON mode it is downgraded to `json_object` (reported as a dropped `structured_outputs` parameter) unless you set `require_parameters`. Add `"plugins": [{ "id": "response-healing" }]` to repair almost-JSON (code fences, prose around the object, trailing commas, single quotes, unterminated strings) and validate the result against your schema; the outcome is in `pipeline.healing` with `repaired`, `valid` and the validation errors. Healing applies to non-streamed responses. ## Rate limits Every response carries `x-ratelimit-limit` and `x-ratelimit-remaining` for your key; exceeding the limit returns `429 rate_limit_exceeded` with `retry-after` in seconds. Vendor-side throttling is absorbed by failover; when every endpoint for a model is throttled you receive `429 upstream_rate_limited` with the vendor's `retry-after` hint when it sent one. Mid-stream failures arrive as an error event inside the SSE stream (see [Streaming](https://elevenrouter.com/docs/streaming)). ## Prompt caching Place cache breakpoints with `cache_control` on text content parts, on a whole message, or on Anthropic-style `system` blocks. Breakpoints are forwarded to providers that support them (Anthropic-native endpoints receive them as native `cache_control` blocks; OpenAI-compatible aggregators receive them unchanged). Cached reads and writes are billed at the model's official cache rates and show up as `prompt_tokens_details.cached_tokens` / `cache_write_tokens`. ```json { "model": "anthropic/claude-sonnet-4.5", "messages": [ { "role": "system", "content": [ { "type": "text", "text": "", "cache_control": { "type": "ephemeral", "ttl": "1h" } } ] }, { "role": "user", "content": "Summarise section 3." } ] } ``` ## Model fallbacks Supply `models` with alternatives. If the primary model has no available endpoint, the next model is used and the response's `model` field tells you which one answered. ```json { "model": "anthropic/claude-sonnet-5", "models": ["openai/gpt-5.6-terra", "deepseek/deepseek-v4-pro"], "messages": [...] } ``` ## Retries and idempotency ElevenRouter retries transient upstream failures (rate limits, 5xx, timeouts, access denials) on other endpoints as long as nothing has been streamed to you yet. Client-side errors (invalid parameters, context length) are returned immediately without retry. Every attempt is recorded and visible in the dashboard's activity view. --- Source: https://elevenrouter.com/docs/routing # Model migrations Vendors retire model generations on their own schedule. ElevenRouter announces every deprecation in advance, keeps a successor for each retired model and can forward traffic automatically, so an upgrade is a one-line change you make on your own timetable. [View as Markdown](https://elevenrouter.com/docs/md/migrations) ## How the lifecycle works Every model carries `deprecated_at`, `retired_at` and `successor` in the catalog. While a model is deprecated it keeps serving; responses carry `Deprecation`, `Sunset` and `Link: <…>; rel="successor-version"` headers and a `model.deprecated` alert is sent to your organization. After `retired_at`, requests are forwarded to the successor (the route receipt records `pipeline.forwarded_from`) unless you turn forwarding off under Settings → Privacy & controls, in which case they fail with `404 model_retired`. ## Stay current with ~latest aliases The least-effort migration is to not pin a version at all: `~vendor/family-latest` always resolves to the newest active member of a family, and the catalog tells you which model it currently points to. Pin exact ids for reproducibility; use aliases for evaluation environments and internal tools. | Alias | Currently resolves to | Vendor | | --- | --- | --- | | ~anthropic/claude-fable-latest | anthropic/claude-fable-5.1 | Anthropic | | ~anthropic/claude-haiku-latest | anthropic/claude-haiku-4.5 | Anthropic | | ~anthropic/claude-opus-latest | anthropic/claude-opus-5 | Anthropic | | ~anthropic/claude-sonnet-latest | anthropic/claude-sonnet-5 | Anthropic | | ~deepseek/deepseek-flash-latest | deepseek/deepseek-v4.1-flash | DeepSeek | | ~deepseek/deepseek-pro-latest | deepseek/deepseek-v4-pro | DeepSeek | | ~moonshotai/kimi-k-latest | moonshotai/kimi-k3 | Moonshot AI | | ~openai/gpt-astra-latest | openai/gpt-6-astra | OpenAI | | ~openai/gpt-luna-latest | openai/gpt-5.6-luna | OpenAI | | ~openai/gpt-sol-latest | openai/gpt-5.6-sol | OpenAI | | ~openai/gpt-terra-latest | openai/gpt-5.6-terra | OpenAI | | ~qwen/qwen-max-latest | qwen/qwen3.8-max | Qwen | | ~tencent/hy-latest | tencent/hy3 | Tencent | | ~z-ai/glm-flash-latest | z-ai/glm-5.3-flash | Z.AI | ## Announced deprecations and retirements No model is currently deprecated or retired. This page updates automatically the moment a vendor announces one. ## Migration checklist 1. Find affected traffic: filter Logs by the deprecated model, or run `POST /analytics/query` grouped by `model` for the last 30 days. 2. Compare behaviour in staging with a [preset](https://elevenrouter.com/docs/organization#presets): create a new version pointing at the successor, run your evaluation set, roll back with one click if needed. 3. Watch parameter differences above; `provider.require_parameters: true` makes the gateway refuse rather than silently drop a parameter the successor lacks. 4. Set the successor as the primary model and keep the old id as a fallback until the retirement date — or switch to the `~latest` alias. 5. Subscribe to `model_deprecation` alerts (Settings → Notifications) so the next announcement reaches the right channel. ```bash # Which deprecated models did we call in the last 30 days? curl -X POST https://elevenrouter.com/api/v1/analytics/query \ -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" -H "content-type: application/json" \ -d '{ "range": { "from": "2026-08-15T00:00:00Z", "to": "2026-09-15T00:00:00Z" }, "metrics": ["requests", "cost"], "dimensions": ["model"] }' # Lifecycle fields for one model curl https://elevenrouter.com/api/v1/models/anthropic/claude-haiku-4.5 | jq '.data | {deprecated_at, retired_at, successor, latest_alias}' ``` --- Source: https://elevenrouter.com/docs/migrations # Streaming Server-Sent Events in the OpenAI chunk format, for every provider. [View as Markdown](https://elevenrouter.com/docs/md/streaming) ## Format Set `"stream": true`. Each event is `data: {...}` with an `object: "chat.completion.chunk"` payload. Deltas carry`content`, `tool_calls` or `reasoning`. The final content chunk sets `finish_reason`; a trailing chunk with an empty`choices` array carries `usage`; the stream ends with `data: [DONE]`. ```text data: {"id":"gen-...","object":"chat.completion.chunk","model":"anthropic/claude-haiku-4.5","provider":"Anthropic","choices":[{"index":0,"delta":{"role":"assistant","content":""},"finish_reason":null}]} data: {"id":"gen-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{"content":"1 2 3"},"finish_reason":null}]} data: {"id":"gen-...","object":"chat.completion.chunk","choices":[{"index":0,"delta":{},"finish_reason":"stop"}]} data: {"id":"gen-...","object":"chat.completion.chunk","choices":[],"usage":{"prompt_tokens":18,"completion_tokens":9,"total_tokens":27,"cost":0.000063}} data: [DONE] ``` ## Keepalive comments While an upstream is thinking, ElevenRouter may send SSE comment lines (`: ELEVENROUTER PROCESSING`) so proxies keep the connection open. SSE parsers ignore comments; make sure yours does too. ## Errors mid-stream If an upstream fails before any output was sent, another endpoint is tried transparently. If it fails after output started, the stream ends with an error event `data: {"error": {...}}` and no `[DONE]`. Only the tokens actually produced are billed. ## Cancelling Closing the connection cancels the upstream request. Tokens generated up to that point are billed and the generation is marked `cancelled`. --- Source: https://elevenrouter.com/docs/streaming # Plugins, files, batches & media Everything beyond a plain chat completion: grounding with web search, documents as input, safe built-in tools, asynchronous batches, and image, rerank, speech and transcription endpoints — all billed on the same receipt with every fee itemised. [View as Markdown](https://elevenrouter.com/docs/md/plugins) ## Plugins Plugins run inside the gateway before (or around) the model call. Ask for them with `plugins: [{ id }]`. Each plugin that charges anything appears as its own line in `elevenrouter_metadata.pipeline.plugins` and is included in `cost.total`; guardrail policies can block plugins or cap what they may cost per request. - `web` *(grounding · fee per result)*: Searches the web for the last user message (or `search_prompt`) and inserts up to `max_results` (default 5) cited sources as a system message. Billed per result returned (see the pricing page); the sources are listed on the receipt. The `:online` model variant is shorthand for this plugin. Customers never see which search vendor is used. - `file-parser` *(documents · free)*: Turns PDF attachments (`{ type: "file", file: { file_data | file_id } }`) into text for models without native file input. Models that accept files natively receive the PDF unchanged. Scanned PDFs without a text layer fail with `pdf_unreadable` rather than silently sending nothing. - `server-tools` *(built-in tools · rounds billed as generations)*: Exposes safe built-ins the model can call — `datetime` (current time in any timezone) and `search_models` (the catalog with prices and capabilities). Tool rounds run inside the gateway (up to `max_rounds`, default 3); each round is a normal, billed generation and the final answer is returned to you once, streamed if you asked for streaming. - `response-healing` *(output · free)*: Repairs malformed JSON (fences, trailing commas, truncation) when you asked for a JSON response. ```bash # Grounded answer with two cited sources, receipt enabled curl https://elevenrouter.com/api/v1/chat/completions -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" \ -H "X-ER-Metadata: enabled" -d '{ "model": "anthropic/claude-sonnet-5", "plugins": [{ "id": "web", "max_results": 2 }], "messages": [{ "role": "user", "content": "What changed in the latest ElevenRouter release?" }] }' # …or simply: "model": "anthropic/claude-sonnet-5:online" # A PDF for a model without native file input curl https://elevenrouter.com/api/v1/chat/completions -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" -d '{ "model": "deepseek/deepseek-v4-flash", "plugins": [{ "id": "file-parser" }], "messages": [{ "role": "user", "content": [ { "type": "text", "text": "Summarise this report." }, { "type": "file", "file": { "file_id": "file_abc123" } } ]}] }' # Let the model check the time before answering curl https://elevenrouter.com/api/v1/chat/completions -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" -d '{ "model": "openai/gpt-5.6-luna", "plugins": [{ "id": "server-tools", "tools": ["datetime"] }], "messages": [{ "role": "user", "content": "Is it still business hours in Tokyo?" }] }' ``` Policy controls: `rules.plugins.blocked` (e.g. `["web"]`), `rules.plugins.maxPluginCostUsdPerRequest` and `rules.plugins.maxWebResults` — see [guardrails](https://elevenrouter.com/docs/organization#guardrails). ## Files API Upload documents once and reference them from messages, or upload JSONL for batches. Two upload styles work from any HTTP client: JSON with base64 content, or a raw body with `x-er-purpose` and `x-er-filename` headers. Files are limited to 50 MB and 2 GB per organization; set `expires_after_seconds` to have them deleted automatically. ```bash # Raw upload curl https://elevenrouter.com/api/v1/files -H "Authorization: Bearer $ELEVENROUTER_API_KEY" \ -H "Content-Type: application/pdf" -H "x-er-purpose: user_data" -H "x-er-filename: report.pdf" \ --data-binary @report.pdf # JSON upload curl https://elevenrouter.com/api/v1/files -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" \ -d "{\"purpose\":\"batch\",\"filename\":\"requests.jsonl\",\"content_base64\":\"$(base64 -w0 requests.jsonl)\"}" curl https://elevenrouter.com/api/v1/files -H "Authorization: Bearer $ELEVENROUTER_API_KEY" # list curl https://elevenrouter.com/api/v1/files/file_abc123/content -H "Authorization: Bearer $ELEVENROUTER_API_KEY" # download curl -X DELETE https://elevenrouter.com/api/v1/files/file_abc123 -H "Authorization: Bearer $ELEVENROUTER_API_KEY" ``` ## Batch API Run thousands of requests asynchronously. Each JSONL line is `{ "custom_id", "method": "POST", "url": "/v1/chat/completions", "body" }`; the file is validated line by line at upload, then `POST /batches` starts it. Requests run through the normal gateway — same policies, budgets, fallbacks, billing and logs — at bounded concurrency. Results land in an output file (one JSON object per line with `custom_id` and the full response), failures in an error file. Batches expire after their completion window; cancellation stops after the in-flight requests. ```typescript import { ElevenRouter } from '@elevenrouter/sdk'; const client = new ElevenRouter(); const lines = docs.map((d, i) => JSON.stringify({ custom_id: `doc-${i}`, method: 'POST', url: '/v1/chat/completions', body: { model: 'openai/gpt-5.6-luna', messages: [{ role: 'user', content: `Classify: ${d}` }] }, })); const file = await client.files.upload({ purpose: 'batch', filename: 'classify.jsonl', content: lines.join('\n') }); const batch = await client.batches.create({ input_file_id: file.id, endpoint: '/v1/chat/completions' }); const done = await client.batches.wait(batch.id); const output = new TextDecoder().decode(await client.files.content(done.output_file_id!)); for (const line of output.trim().split('\n')) { const { custom_id, response } = JSON.parse(line); console.log(custom_id, response.body.choices[0].message.content); } ``` ## Images, rerank, speech and transcription Models whose modality is not text-to-text are served by dedicated endpoints with the same routing, failover and receipt. `GET /models/modalities` lists what is available. Billing units are per modality and shown as `usage.units`: - `POST /images/generations` *(per image)*: OpenAI-compatible image generation. `n` images at the official per-image price; `response_format` `b64_json` or `url`. - `POST /rerank` *(per token)*: Relevance scores for `documents` against a `query`, Cohere/Jina-compatible, optionally `top_n`. - `POST /audio/speech` *(per character)*: Text to speech; returns audio bytes (`audio/mpeg` by default) with the cost in the `x-er-cost` header. - `POST /audio/transcriptions` *(per minute)*: Speech to text from base64 audio in a JSON body (`file`, `filename`) — no multipart needed. Billed on the duration the model reports. ```bash curl https://elevenrouter.com/api/v1/images/generations -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" \ -d '{ "model": "openai/gpt-image-2", "prompt": "a lighthouse at dawn, watercolor", "n": 1, "size": "1024x1024", "usage": { "include": true } }' curl https://elevenrouter.com/api/v1/audio/transcriptions -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" \ -d "{\"model\":\"openai/whisper-2\",\"filename\":\"call.mp3\",\"file\":\"$(base64 -w0 call.mp3)\"}" ``` Video generation and containers are not offered yet; they will appear here the moment an upstream credential supports them, with the same receipt and privacy guarantees. --- Source: https://elevenrouter.com/docs/plugins # Workspaces, guardrails and presets Organise keys into environments, enforce policies before a request costs anything, and ship saved request configurations as @preset/slug. [View as Markdown](https://elevenrouter.com/docs/md/organization) ## Workspaces A workspace is an environment inside your organization — production, staging, a team's project. Keys are created in a workspace and never move; budgets, guardrail assignments and notification routing can be scoped to it. Credits and members stay shared at the organization. Every organization has a `default` workspace; team organizations can add more from environment templates and copy budgets and policy assignments between them. Organization owners and admins can act in every workspace. Other members can use the default workspace and any workspace they were explicitly added to, as `admin` (manage keys, budgets and members there) or `member`. Archiving a workspace requires its keys to be deleted first, so nothing is ever silently cut off. ## Guardrails (policies) A policy is a rule set that runs on every request *before* credits are reserved or an upstream is contacted. Policies apply wherever they are assigned: the whole organization, a workspace, a key, or a member (their keys). Several policies can apply to one request; a block from any of them wins. - `models` *(allow_all_except | allow_only)*: Model access by pattern: exact ids, vendor/* or *. Blocks with 403 policy_blocked. - `vendors` *(allow_all_except | allow_only)*: Access by the model's official vendor slug (anthropic, openai, google…). - `limits` *(object)*: maxOutputTokens, maxPromptTokens (estimated) and maxCostUsdPerRequest (upper-bound estimate). Exceeding any of them blocks. - `promptInjection` *(block | flag | redact)*: Built-in heuristics for instruction-override attempts over user and tool content, plus your own regex patterns and an allow-list of legitimate phrases. - `sensitiveInfo` *(block | flag | redact)*: Detectors for emails, phones, payment cards (Luhn), IPs, API keys/tokens, IBANs and US SSNs, plus custom regexes. Direction: prompts, non-streamed answers, or both. Redaction rewrites matched spans to `[REDACTED EMAIL]`-style markers before the request leaves ElevenRouter; the original text is never stored. Policy events (blocked, flagged, redacted) record only which rule fired and detector counts. The route receipt carries a `pipeline.policies` summary and blocked requests return: ```json HTTP/1.1 403 Forbidden { "error": { "type": "permission_error", "code": "policy_blocked", "message": "Request blocked by policy \"Production guardrails\" (vendors).", "metadata": { "policy": "Production guardrails", "rule": "vendors", "vendor": "anthropic", "mode": "allow_only" } } } ``` Before enabling a policy, **dry-run** it against the last 1–30 days of real traffic to see how many requests (and how much spend) its model, vendor and limit rules would have blocked. Text rules cannot be replayed because prompts are not stored; use the live tester instead. ## Presets A preset is a saved request configuration: a system prompt, a primary model with up to three fallbacks, a routing block, default parameters, caching and transforms. Address it in `model`: ```bash curl https://elevenrouter.com/api/v1/chat/completions \ -H "Authorization: Bearer $ELEVENROUTER_API_KEY" \ -H "Content-Type: application/json" \ -d '{ "model": "@preset/support-bot", "messages": [{ "role": "user", "content": "My invoice is wrong." }] }' ``` Fields you send always win over the preset's defaults; the preset only fills gaps. When the request has no system or developer message the preset's system prompt is prepended. Every save creates a new version; `@preset/support-bot` serves the current version and `@preset/support-bot@3` pins one. Presets can also be **pinned to a key**, in which case every request through that key receives the preset's prompt, parameters and routing while keeping the model it asked for. The route receipt records `pipeline.preset` with the slug, version and whether it was referenced or pinned. ## Account privacy controls - `maxKeyLifetimeDays` *(integer)*: Every key must expire within this many days of creation; keys created without an expiry get the maximum. - `allowedVendors / blockedVendors` *(string[])*: Account-wide vendor allow- or block-list applied before key allow-lists and policies. Refusals return 403 vendor_not_allowed. - `logPrompts` *(boolean)*: Whether prompts and completions are stored with logs (off by default). - `responseCache` *(boolean)*: Whether keys may opt into the per-key response cache. - `forwardRetiredModels` *(boolean)*: Whether requests to retired models are served by their announced successor. The **eligibility preview** under Settings → Privacy & controls shows, for the account or for one key, which models can be called right now and exactly which control or policy excludes the rest. ## Management API Everything above has a programmatic equivalent for **management keys** under `/management`: workspaces, budgets, policies (with assignments and dry-run), presets (with versions), notification rules, BYOK credentials (add, restrict to key hashes, rotate) and members. Responses use the `{ "data": … }` envelope with snake_case fields, every call is audit-logged with the management key as actor, and the surface is rate-limited per key (default 120 requests per minute). The full schema is in the [OpenAPI document](https://elevenrouter.com/api/v1/openapi.json). ```bash M="Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" B=https://elevenrouter.com/api/v1/management # A production workspace with a hard daily budget curl -X POST $B/workspaces -H "$M" -d '{ "name": "Production", "environment": "production" }' curl -X POST $B/budgets -H "$M" -d '{ "scope_type": "workspace", "scope_id": "production", "interval": "daily", "limit": 250 }' # Dry-run a vendor policy, then create it assigned to the workspace curl -X POST $B/policies/dry-run -H "$M" -d '{ "rules": { "vendors": { "mode": "allow_only", "slugs": ["anthropic", "openai"] } }, "days": 7 }' curl -X POST $B/policies -H "$M" -d '{ "name": "Approved vendors", "rules": { "vendors": { "mode": "allow_only", "slugs": ["anthropic", "openai"] } }, "assignments": [{ "target_type": "workspace", "target_id": "production" }] }' # A preset and a key in the workspace that pins it curl -X POST $B/presets -H "$M" -d '{ "slug": "support-bot", "name": "Support bot", "config": { "models": ["anthropic/claude-sonnet-5", "openai/gpt-5.6-terra"], "systemPrompt": "You are a support agent." } }' curl -X POST https://elevenrouter.com/api/v1/keys -H "$M" -d '{ "name": "support-backend", "workspace_id": "production", "preset_id": "support-bot" }' ``` --- Source: https://elevenrouter.com/docs/organization # Activity, logs and analytics Everything the gateway records about your requests, how to read it in the dashboard, and how to pull it into your own tools. [View as Markdown](https://elevenrouter.com/docs/md/observability) ## What is recorded Every request becomes a *generation*: model and vendor, key, workspace, status and finish reason, prompt / completion / cached / reasoning tokens, exact cost at the official rate, time to first token, total time, time spent routing, time lost to failed attempts, the list of attempts (vendor, outcome, classified reason), and your own labels — app (`X-Title`), session (`X-ER-Session-Id` / `session_id`) and end user (`X-ER-User-Id` / `user`). Prompts and completions are never stored. ## Activity The Activity page compares the selected range with the previous one: spend, requests, tokens, cache hit rate, blended $/1M tokens, error rate, p50 time to first token and output throughput, each with a sparkline. Below it: spend by model over time, requests by outcome, the token split, top keys and vendors. Anomaly banners appear when the last 24 hours deviate strongly from the 7-day baseline (spend, error rate, latency or volume). Turn on **Live** to refresh every 15 seconds. **Explore** pivots any metric by any dimension — model, vendor, key, workspace, status, finish reason, user, session, app, API, streamed, BYOK or error code — with an optional second dimension and a top-N cut-off. Rates and percentiles are computed on the grouped rows, never averaged. ## Logs Logs lists every request with a histogram, a search box (id, session, user, app or model), filters, a column chooser and saved views. **Live** tails new requests in place. Click a row to open the drawer: a waterfall (routing → failed attempts → time to first token → generation), each attempt with its vendor and classified reason, a cost explainer that multiplies your token counts by the captured official rates, and the raw record. Use ← → to move between rows and "Report a problem" to send us the request id. The **Sessions** tab groups requests by session or user with per-group cost. ## Exporting logs Export the current filters as CSV or JSON. Exports run in the background and produce a signed download link that stays valid for seven days. Columns match the Logs table; vendor names are the model's official vendor. ## Analytics API The same engine is available to **management keys**, so anything you can see in the dashboard you can pull into a spreadsheet, a BI tool or your own alerting. ```bash # Metrics and dimensions the engine understands curl https://elevenrouter.com/api/v1/analytics/metrics -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" # Daily spend and requests per model for the last 30 days, Berlin time curl https://elevenrouter.com/api/v1/analytics/query \ -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" \ -H "content-type: application/json" \ -d '{ "from": "2026-08-16T00:00:00Z", "to": "2026-09-15T00:00:00Z", "timezone": "Europe/Berlin", "granularity": "day", "metrics": ["cost", "requests", "cache_hit_rate", "p95_ttft_ms"], "dimensions": ["model"], "limit": 10, "filters": { "status": ["succeeded"] } }' ``` ```json { "data": { "query": { "from": "…", "to": "…", "timezone": "Europe/Berlin", "granularity": "day", "metrics": ["cost", …], "dimensions": ["model"] }, "rows": [ { "bucket": "2026-09-14T00:00:00", "dimensions": { "model": "anthropic/claude-sonnet-5" }, "metrics": { "cost": 12.4031, "requests": 1840, "cache_hit_rate": 0.41, "p95_ttft_ms": 910 } }, { "bucket": "2026-09-14T00:00:00", "dimensions": { "model": "__other__" }, "metrics": { … } } ], "labels": { "api_key": { "…": "prod" } }, "truncated": false } } ``` - `metrics` *(string[])*: requests, succeeded, failed, error_rate, cost, prompt_tokens, completion_tokens, cached_tokens, reasoning_tokens, total_tokens, cache_hit_rate, blended_per_million, p50_ttft_ms, p95_ttft_ms, p50_total_ms, p95_total_ms, tokens_per_second, fallback_rate, insured, users, sessions. - `dimensions` *(string[] (max 2))*: model, vendor, api_key, workspace, status, finish_reason, end_user, session, app, api_type, streamed, byok, error_code. The first dimension is cut to the top `limit` values by the first metric; the rest is reported as `__other__`. - `granularity` *(hour | day | week | month | total | auto)*: Bucket size. `total` returns one row per dimension combination; `auto` picks a readable size for the range. - `timezone` *(IANA zone)*: Bucket boundaries are computed in this zone; `bucket` strings are local times. - `filters` *(object)*: model, vendor, api_key_id, workspace_id, status, finish_reason, user, session, app, api_type, streamed, byok, error_code — arrays match any value. Ranges are limited to 400 days and results to 5,000 rows; narrow the range or use a coarser granularity when `truncated` is true. Inference keys cannot call the analytics API. --- Source: https://elevenrouter.com/docs/observability # Keys, limits and billing Prepaid credits, exact per-token billing and guardrails per key. [View as Markdown](https://elevenrouter.com/docs/md/limits) ## Credits Usage is paid from a prepaid balance that belongs to your organization. Before a request is dispatched ElevenRouter reserves an upper-bound estimate; after the response it settles the exact cost from the provider's token counts and releases the reservation. Every movement is an entry in the ledger you can inspect in the dashboard. ## Pricing Models are billed at the vendor's official list price: base input tokens, cached input tokens, cache writes and output tokens each at their published rate. Where a provider's accounting is known to be unreliable, ElevenRouter bills the smaller of the reported and estimated prompt tokens so you never pay for a provider's hidden system prompt. The per-request breakdown is available under Activity and, on request, in the [route receipt](https://elevenrouter.com/docs/api-reference#receipt). The full fee schedule is on the [pricing page](https://elevenrouter.com/pricing). ## Which credits are spent first Your balance is made of promotional credits, granted credits and purchased credits. Usage is always taken from promo credits first, then grants, then the credits you paid for, and only purchased credits are refundable. Each ledger entry shows the split. ## Zero-completion insurance A response with zero completion tokens whose finish reason is blank or `error` is not charged, even when the vendor bills us for processing the prompt. Failed requests are never charged. Partial streamed output that reached your client is billed for the tokens you received. Insured requests show a cost of $0 in Activity with an "insured" marker, and the route receipt reports `cost.insured: true`. ## Key spend limits Each key can carry a USD limit that is lifetime or resets daily, weekly or monthly (UTC). When the limit is reached requests fail with `402 key_limit_exceeded`. Alerts fire at 50, 80, 90 and 100% of the limit (owners and admins are emailed at 80% and above by default). Organization-level allow-lists restrict which models keys may use. ## Budgets Budgets cap spend for the whole organization, a workspace or a single key over a daily, weekly, monthly or lifetime window. A **hard** budget rejects requests once the limit is reached; a **soft** budget only alerts. Limits must shrink as the window narrows (lifetime > monthly > weekly > daily) so the tightest cap is always the binding one. Every budget card shows the spend so far and a forecast of when the limit will be reached at the current pace. ```json HTTP/1.1 402 Payment Required { "error": { "type": "insufficient_credits_error", "code": "budget_exceeded", "message": "The daily budget of $50.00 for this workspace has been reached. It resets 2026-09-16T00:00:00.000Z.", "metadata": { "budget_scope": "workspace", "budget_interval": "daily", "budget_limit": 50, "budget_resets_at": "2026-09-16T00:00:00.000Z" } } } ``` Budgets are reached-based: the request that reaches the limit completes and the next one is rejected. Estimates are upper bounds, so estimate-based rejection would refuse legitimate requests near the cap. A budget created part-way through a period counts the spend already made in that period. ## When a request is refused (402) - `insufficient_credits` *(balance)*: The prepaid balance cannot cover the upper-bound estimate for the request. Add credits or enable auto top-up. - `key_limit_exceeded` *(key limit)*: The key reached its lifetime or recurring spend limit. Raise it, or wait for the period to reset. - `budget_exceeded` *(budget)*: A hard budget on the organization, workspace or key was reached. metadata carries scope, interval, limit and reset time. Every refusal, and every charge decision, is recorded so you can always see why a request cost what it did (or was declined) in Activity. ## Rate limits (429) Keys default to 600 requests per minute; set a lower value per key when you hand keys to untrusted clients. Responses include `x-ratelimit-limit` and `x-ratelimit-remaining`; when exceeded you receive `429` with `retry-after` in seconds. Vendor-side rate limits are absorbed by failover: when one credential is throttled the request moves to the next eligible endpoint, and only when every endpoint is throttled do you see a `429` from ElevenRouter. ## Rotating keys From a key's page choose **Rotate**: a new key is created with the same name, limits and allowed models, and the old key keeps working for an overlap window (1 hour, 24 hours or 7 days) so you can roll deployments without downtime. The old key then expires by itself. ## Alerts Low balance, budget thresholds, key spend limits, failed auto top-ups, model availability and official price changes can be delivered by email, signed webhook or Slack incoming webhook (Settings → Notifications). Webhook deliveries are JSON and signed with HMAC-SHA256: ```text POST /your/endpoint X-ER-Event: alert.budget_threshold X-ER-Delivery-Id: 5d0c… X-ER-Timestamp: 1789999999 X-ER-Signature: v1=.")> { "id": "…", "type": "alert.budget_threshold", "severity": "warning", "title": "80% of the monthly workspace budget used in Acme", "message": "...", "url": "https://app.elevenrouter.com/settings/budgets", "data": { ... } } ``` Verify by recomputing the HMAC over `${X-ER-Timestamp}.${body}` with the signing secret shown once when the destination was created, and reject timestamps older than five minutes. Failed deliveries are retried with backoff; a destination that fails five times in a row is disabled and the owners are emailed. ## Attribution Send `HTTP-Referer` and `X-Title` headers to tag requests with your application; they appear in the activity view for filtering and analysis. ## Provisioning API (management keys) Create a **management key** in the dashboard to manage inference keys programmatically, for example one key per customer of your own product. Management keys cannot run model requests; inference keys cannot call the management API. ```bash # Create a key with a $10 monthly limit restricted to one model curl -X POST https://elevenrouter.com/api/v1/keys \ -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" \ -H "content-type: application/json" \ -d '{ "name": "customer-42", "limit": 10, "limit_reset": "monthly", "allowed_models": ["openai/gpt-5.6-luna"] }' # List, inspect (by id or hash), update, delete curl https://elevenrouter.com/api/v1/keys -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" curl https://elevenrouter.com/api/v1/keys/ -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" curl -X PATCH https://elevenrouter.com/api/v1/keys/ -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" -d '{ "disabled": true }' curl -X DELETE https://elevenrouter.com/api/v1/keys/ -H "Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY" ``` `POST` returns the plaintext key once under `key`; every response carries the key record under `data` with `limit`, `limit_remaining`, `usage`, `rate_limit_per_minute`, `allowed_models`, `disabled` and `expires_at`. ## Bring your own keys (BYOK) Under Settings you can attach your own provider API keys to your organization. ElevenRouter discovers which models each key can reach and prefers your keys whenever they can serve a request; if they are denied or fail, traffic falls back to platform keys at the official price. Requests served through your keys are billed a small fee (a percentage of the official price, shown in the dashboard) instead of the token cost, because the provider bills you directly. Secrets are encrypted at rest and only decrypted in memory to sign upstream calls. The activity view marks BYOK requests, and `provider.sort: "price"` (or `:floor`) treats them as the cheapest option. ## Teams Create a team organization to share credits, keys and provider keys with colleagues. Invite people by email; they join with the role you choose — `member` (use and create keys), `billing` (manage credits), `admin` (manage members, keys and settings) or `owner`. Invitations expire after seven days and can be revoked. --- Source: https://elevenrouter.com/docs/limits # Enterprise features Ship request data to your own stack, keep prompts under your control, bring your own endpoints, let third-party apps obtain keys your users approve, and pay by invoice. Everything below is configured per organization from Settings → Integrations & data. [View as Markdown](https://elevenrouter.com/docs/md/enterprise) ## Broadcast Every finished generation (success or failure) is forwarded to up to five destinations per organization or workspace. Delivery is asynchronous and batched (up to 100 events per request), retried with exponential backoff for up to eight attempts, and a destination that fails twenty times in a row is paused until you resume it. Payloads name models by their official vendor only. - `webhook` *(HTTPS · signed)*: JSON `{ object: "list", data: [event…] }`. Header `x-er-signature: t=,v1=` where `v1 = HMAC_SHA256(secret, `${t}.{raw body}`)`; reject when `t` is older than five minutes. - `otlp` *(OpenTelemetry collector)*: OTLP/HTTP JSON logs posted to `/v1/logs`: one record per generation with `gen_ai.*` and `elevenrouter.*` attributes (model, tokens, cost, latency, session, key). Works with any collector, Datadog, Grafana, Honeycomb, Langfuse via OTLP. - `s3` *(S3-compatible)*: NDJSON objects under `prefix/YYYY/MM/DD/`, signed with SigV4. Custom endpoints (MinIO, Cloudflare R2, Backblaze) with path-style addressing. ```typescript // Verify a broadcast webhook (Node) import { createHmac, timingSafeEqual } from 'node:crypto'; export function verify(secret: string, header: string, rawBody: string): boolean { const { t, v1 } = Object.fromEntries(header.split(',').map((p) => p.split('='))); if (Math.abs(Date.now() / 1000 - Number(t)) > 300) return false; const expected = createHmac('sha256', secret).update(`${t}.${rawBody}`).digest('hex'); return v1?.length === expected.length && timingSafeEqual(Buffer.from(v1), Buffer.from(expected)); } ``` Event shape: `generation.completed` with `generation.id`, `model`, `vendor`, `usage`, `cost_usd`, `latency_ms`, `fallback_count`, `session_id`, `end_user_id`, `error`. Enable “include bodies” on a destination to add the stored prompt and response when I/O logging is on. ## I/O logging Off by default. When enabled (organization-wide under Privacy & controls, or per workspace), request and response bodies are stored encrypted with AES-256-GCM, shown in Logs → “Prompt & response”, exported to broadcast destinations that opt in, and deleted after the retention window (1–365 days, default 30). Bodies over 1 MB are truncated. You can delete a single generation's bodies, everything before a date, or everything, from the dashboard or the console API. ```bash # Console API (session cookie or dashboard) GET /api/console/orgs/{orgId}/io-logging GET /api/console/orgs/{orgId}/generations/{generationId}/bodies DELETE /api/console/orgs/{orgId}/generations/{generationId}/bodies DELETE /api/console/orgs/{orgId}/io-logging/bodies { "before": "2026-09-01T00:00:00Z" } PATCH /api/console/orgs/{orgId}/workspaces/{workspaceId}/io-logging { "logIo": true | false | null } ``` ## Private models Register your own OpenAI-compatible endpoint (vLLM, Ollama, TGI, an internal gateway). Its models appear as `private/…` ids in your organization's catalog only, route through the same pipeline (fallbacks, receipts, budgets, guardrails, logs), and cost nothing beyond the BYOK fee on any price you attribute for internal cost accounting. The endpoint must be publicly routable; private network ranges are refused to prevent SSRF. Credentials are stored encrypted and never returned. ```bash # After registering "Team vLLM" with model llama-3.3-70b: curl https://elevenrouter.com/api/v1/chat/completions -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" -d '{ "model": "private/1a2b3c4d-llama-3.3-70b", "models": ["openai/gpt-5.6-luna"], "messages": [{ "role": "user", "content": "Hello" }] }' # falls back to a public model if your endpoint is down ``` ## OAuth PKCE for user-controlled keys Let your application obtain an ElevenRouter key that the user approves and pays for — no key copy-pasting. Public clients only need PKCE: generate a verifier, send the user to the consent screen, exchange the returned code for a key. The key is named after your app, lives under the organization the user picked and can carry a spend limit the user sets. ```typescript // 1. Generate PKCE pair const verifier = base64url(crypto.getRandomValues(new Uint8Array(48))); const challenge = base64url(await crypto.subtle.digest('SHA-256', new TextEncoder().encode(verifier))); // 2. Send the user to the consent screen location.href = `https://app.elevenrouter.com/oauth/authorize?callback_url=${encodeURIComponent('https://myapp.example/callback')}` + `&code_challenge=${challenge}&code_challenge_method=S256&name=My%20App&state=${state}`; // 3. On your callback: exchange the code (server or browser — no secret involved) const res = await fetch('https://elevenrouter.com/api/v1/auth/keys', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ code, code_verifier: verifier, code_challenge_method: 'S256' }), }); const { key } = await res.json(); // sk-er-v1-… scoped to the user's organization ``` Codes expire after ten minutes and are single-use; a wrong verifier consumes the code. Denied requests redirect with `error=access_denied`. ## Credit lines and invoiced billing Organizations billed in arrears get a credit line: the balance may run negative down to the line, with alerts at 50 / 80 / 100 % of the line used (email, Slack, webhook — the `credit_line_threshold` notification kind). Requests are refused with `402` once the line is exhausted. Invoices summarise usage per model for a period; paying one credits the balance and frees the line. Contact sales to enable a line; it appears under Credits together with the invoice history. Not offered yet: SAML SSO and SCIM provisioning, and classifier-based tagging of prompts. Teams that need them today can use OIDC through their identity provider's email domain with two-factor enforcement, and the analytics API for tagging via `X-ER-Metadata`. See the [changelog](https://elevenrouter.com/docs/changelog) for what ships next. --- Source: https://elevenrouter.com/docs/enterprise # Privacy & data handling What ElevenRouter stores about your requests, for how long, who can see it, and the controls you have. Defaults favour privacy: prompts are not stored unless you turn logging on. [View as Markdown](https://elevenrouter.com/docs/md/privacy) ## What is recorded per request - `Always` *(metadata)*: Generation id, timestamps, model and vendor, token counts, exact cost, latency and time-to-first-token, finish reason, status and error code, the key and workspace, optional session/user ids and app attribution, the routing decision and the pipeline summary (variant, preset, transforms, cache, guardrail counts). This is what powers Activity, Logs, billing and the route receipt. - `Only when enabled` *(prompts & completions)*: Request and response bodies are stored only when the organization turns on “Store prompts and completions” (Settings → Privacy & controls). Off by default. When off, nothing you send or receive is persisted after the response is delivered. - `Never` *(—)*: Matched text from guardrail policies (only detector names and counts), your BYOK secrets in plaintext (encrypted at rest, decrypted in memory to sign upstream calls), or card details (handled by the payment processor). ## Who sees what Customers see a model's **official vendor** (Anthropic, OpenAI, Google…) in the catalog, logs, receipts and headers — never an internal route, credential or infrastructure detail. Error messages, ledger descriptions and generation records are sanitised the same way. Inside an organization, members see logs for the workspaces they belong to; owners and admins see everything; the platform operator sees metadata for support and abuse prevention and, when you enabled prompt logging, the stored bodies. ## Retention - `Generation metadata` *(13 months)*: Kept for billing reconciliation, analytics and exports. Aggregated daily rollups are kept indefinitely without identifiers. - `Stored prompts/completions` *(30 days)*: When logging is on. Turning logging off stops new storage immediately; existing bodies age out or can be purged on request. - `Response cache` *(≤ 7 days)*: Cached answers are scoped to one API key, live in memory for the TTL you set (max 7 days) and are dropped when the key is deleted or the organization disables the cache. - `Audit log` *(24 months)*: Who changed what (keys, budgets, policies, members) with IP and request id. - `Policy events` *(90 days)*: Which rule fired on which request; never the matched text. ## Controls you have - `Prompt logging` *(organization)*: Off by default; toggle in Settings → Privacy & controls. - `Vendor allow/block lists` *(organization)*: Keep traffic away from vendors you have not approved; the eligibility preview shows the effect per key. - `Sensitive-information redaction` *(policy)*: Strip emails, phone numbers, cards, IPs, secrets, IBANs, SSNs and custom patterns from prompts before they leave ElevenRouter, and from non-streamed answers. - `Key lifetime` *(organization)*: Force keys to expire within N days. - `Response cache` *(organization / request)*: Opt in per request with X-ER-Cache; disable account-wide. - `Data export` *(organization)*: Export generation metadata as CSV or JSON from Logs, or through the analytics API. - `Deletion` *(request)*: Deleting a key removes its cached responses immediately. Deleting an organization removes keys, budgets, policies, presets and stored bodies; billing records are retained as required by law. Contact support for account-wide erasure requests. ## Vendor data handling Prompts are sent to the model's vendor to produce the answer; each vendor's own retention and training policies apply to that processing. Use the vendor controls above to restrict which vendors may receive your traffic, and `provider.require_parameters` or model allow-lists to pin specific models. ElevenRouter does not use your prompts or completions to train models. ## Security API keys are stored as SHA-256 hashes and shown once. BYOK secrets are encrypted with AES-256-GCM using a key held outside the database. All traffic is TLS. Management keys are rate-limited and every control-plane action is audit-logged. Report vulnerabilities to [security@elevenrouter.com](https://elevenrouter.com/mailto:security@elevenrouter.com). --- Source: https://elevenrouter.com/docs/privacy # Best practices A production checklist for teams running real traffic through ElevenRouter: how to structure keys, cap spend, survive vendor incidents, keep costs predictable and stay observable. [View as Markdown](https://elevenrouter.com/docs/md/best-practices) ## Keys and environments - One [workspace](https://elevenrouter.com/docs/organization#workspaces) per environment (production, staging, development) and one key per service or deployment inside it. Keys are cheap; shared keys make spend and incidents impossible to attribute. - Give every key a spend limit and, for user-facing services, a rate limit. Set an expiry on keys handed to contractors or CI; set an account-wide maximum key lifetime under Settings → Privacy & controls to enforce it. - Use `allowed_models` or a guardrail policy on keys that only ever need one or two models — it turns a leaked key into a bounded problem. - Rotate with overlap (Key → Rotate → 24 hours) instead of deleting; deployments switch over without a hard cut. - Never use a management key for inference and never ship it to a client; it can create keys. ## Budgets and alerts Put a hard monthly budget on the organization and soft budgets on workspaces and keys. Hard budgets reject with `402 budget_exceeded` once reached; soft budgets only alert, which is what you want for the paths where an outage costs more than an overrun. Wire budget thresholds, low balance and failed auto top-ups to Slack or a webhook, and enable auto top-up for production organizations so a spike never becomes a 402. ## Reliability - `models` *(fallback list)*: Always pass one or two fallbacks from another vendor. ElevenRouter already fails over across credentials for the same model; cross-vendor fallbacks cover the vendor being down. - `timeouts` *(client)*: Set a client timeout above the model’s realistic completion time (reasoning models can take minutes) and stream so you see progress. The gateway keeps the connection alive with SSE comments while upstreams think. - `retries` *(client)*: Retry only 429 and 5xx, honour Retry-After, and never retry 400/402/403. The SDKs do this; with raw HTTP add jittered backoff. Do not retry a streamed request that already produced tokens unless your app can deduplicate. - `idempotency` *(design)*: Requests are not idempotent at the API level. Attach your own request id via session_id / metadata so retries can be reconciled in Logs, and make downstream side effects idempotent. - `provider preferences` *(routing)*: Use sort: "latency" for interactive paths, sort: "price" (or :floor) for batch, and require_parameters: true when a dropped parameter would silently change behaviour. - `health` *(monitoring)*: Poll GET /status or subscribe to model_availability alerts; the status page shows per-model availability from the routing engine, not a synthetic probe. ## Cost control - Cap output with `max_tokens`; the credit reservation is an upper bound and a missing cap reserves the model's maximum. - Use prompt caching for long, stable prefixes (`cache_control` on system prompts and documents) — cached input is billed at the vendor's cache-read rate, visible per request in Activity. - Turn on the `X-ER-Cache` response cache for deterministic, repeated calls (classification, extraction with temperature 0). Hits are free. - Route batch and background work to `:floor` or a cheaper family; keep the expensive model for the interactive path. A preset per use case makes this a config change, not a deploy. - Add a `maxCostUsdPerRequest` guardrail on user-facing keys to stop pathological prompts before they run. - Use `usage.include: true` or the route receipt to see the exact cost per response and reconcile against your own metering. ## Output quality For JSON, prefer `response_format: json_schema` on models that advertise `structured_outputs`, add the `response-healing` plugin for models that do not, and validate on your side anyway. Send stable system prompts first (they are the cacheable prefix) and keep per-request material last. When context can overflow, opt into `transforms: ["middle-out"]` so long conversations degrade gracefully instead of failing. ## Observability Send `X-ER-Session-Id` and `X-ER-User-Id` (or the `user` field) on every request so Logs can group a conversation and Activity can show cost per user. Tag applications with `HTTP-Referer` and `X-Title`. Store the `x-er-generation-id` next to your own request logs — support and `GET /generation` both key off it. Export logs on a schedule if you need them in your warehouse. ## Security and privacy - Keep prompt logging off unless you need it for debugging; turn it on per organization, not globally, and remember redaction policies run before anything is stored. - Put a sensitive-information guardrail (redact) on keys that receive end-user input, and a prompt-injection guardrail (flag, then block once tuned) on agents that call tools. - Restrict BYOK credentials to the keys that need them and rotate them from the dashboard or the management API. - Review the audit log after changes to keys, budgets and policies; every management-API call is attributed to its key. ## A production-ready request ```bash curl https://elevenrouter.com/api/v1/chat/completions \ -H "Authorization: Bearer $ELEVENROUTER_API_KEY" \ -H "Content-Type: application/json" \ -H "X-ER-Session-Id: conv_8f2a" -H "X-ER-User-Id: user_1834" \ -H "HTTP-Referer: https://app.example.com" -H "X-Title: Example Support" \ -d '{ "model": "anthropic/claude-sonnet-5", "models": ["openai/gpt-5.6-terra"], "provider": { "sort": "latency", "require_parameters": true }, "max_tokens": 800, "stream": true, "messages": [ { "role": "system", "content": [{ "type": "text", "text": "You are the support assistant for Example.", "cache_control": { "type": "ephemeral" } }] }, { "role": "user", "content": "My invoice is wrong." } ] }' ``` --- Source: https://elevenrouter.com/docs/best-practices # Cookbook Copy-paste recipes for the things teams build most often. Each one is complete: paste, set your key, run. [View as Markdown](https://elevenrouter.com/docs/md/cookbook) ## The cheapest model that supports tools Filter the catalog by capability and price instead of hard-coding a model. The same query powers the MCP `search_models` tool. ```typescript import { ElevenRouter } from '@elevenrouter/sdk'; const client = new ElevenRouter(); const { data } = await client.models.list(); const perMillion = (v?: string) => Number(v ?? 0) * 1_000_000; const candidates = data .filter((m) => m.supported_parameters.includes('tools') && m.availability !== 'unavailable' && (m.context_length ?? 0) >= 128_000) .sort((a, b) => perMillion(a.pricing.prompt) + perMillion(a.pricing.completion) - (perMillion(b.pricing.prompt) + perMillion(b.pricing.completion))); const [primary, fallback] = candidates; const res = await client.chat.completions.create({ model: primary!.id, models: fallback ? [fallback.id] : undefined, tools: [{ type: 'function', function: { name: 'lookup_order', parameters: { type: 'object', properties: { id: { type: 'string' } }, required: ['id'] } } }], messages: [{ role: 'user', content: 'Where is order 4821?' }], }); ``` ## Reliable JSON extraction Ask for a schema, let the gateway repair malformed output, and validate. Works on models without native structured outputs because `response-healing` fixes trailing commas, fences and truncated objects before you see them. ```python from elevenrouter import ElevenRouter client = ElevenRouter() schema = {"type": "object", "properties": {"name": {"type": "string"}, "total": {"type": "number"}, "currency": {"type": "string"}}, "required": ["name", "total"]} res = client.chat.completions.create( model="openai/gpt-5.6-luna", temperature=0, response_format={"type": "json_schema", "json_schema": {"name": "invoice", "schema": schema}}, plugins=[{"id": "response-healing"}], messages=[{"role": "user", "content": f"Extract the invoice fields as JSON:\n{invoice_text}"}], ) data = json.loads(res["choices"][0]["message"]["content"]) ``` ## Long documents without overflow `middle-out` trims the least important middle of a conversation when it exceeds the model's context, keeping the system prompt and the latest turns. Combined with a cheap fallback that has a bigger window, long inputs never fail. ```bash curl https://elevenrouter.com/api/v1/chat/completions -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" -d '{ "model": "anthropic/claude-sonnet-5", "models": ["openai/gpt-5.6-terra"], "transforms": ["middle-out"], "messages": [{ "role": "system", "content": "Summarise the document." }, { "role": "user", "content": "" }] }' ``` ## One key per customer (SaaS metering) Create an inference key per tenant with its own monthly limit through the management API, then bill from Activity or the analytics API grouped by key. Delete the key to cut a tenant off instantly. ```typescript const admin = new ElevenRouter({ apiKey: process.env.ELEVENROUTER_MANAGEMENT_KEY }); // On tenant signup const { data: key, key: plaintext } = await admin.keys.create({ name: `tenant-${tenant.id}`, workspace_id: 'production', limit: tenant.plan.monthlyUsd, limit_reset: 'monthly', allowed_models: ['openai/gpt-5.6-luna', 'anthropic/claude-haiku-4.5'], }); await vault.store(tenant.id, plaintext); // Month-end: spend per tenant const usage = await admin.analytics.query({ range: { from, to }, metrics: ['cost', 'requests'], dimensions: ['api_key'] }); ``` ## Cost per conversation Send the same `X-ER-Session-Id` on every turn of a conversation. Logs → Sessions groups the turns and sums their cost; the analytics API can do the same with the `session` dimension. ```typescript const res = await client.chat.completions.create( { model: 'anthropic/claude-sonnet-5', messages }, { headers: { 'X-ER-Session-Id': conversationId, 'X-ER-User-Id': userId } }, ); ``` ## Cache-aware chat Put the stable prefix (system prompt, documents) first with a `cache_control` breakpoint so the vendor bills cache reads, and turn on the response cache for repeated identical prompts. ```bash curl https://elevenrouter.com/api/v1/chat/completions \ -H "Authorization: Bearer $ELEVENROUTER_API_KEY" -H "Content-Type: application/json" \ -H "X-ER-Cache: true" -H "X-ER-Cache-TTL: 3600" \ -d '{ "model": "anthropic/claude-sonnet-5", "messages": [ { "role": "system", "content": [{ "type": "text", "text": "", "cache_control": { "type": "ephemeral", "ttl": "1h" } }] }, { "role": "user", "content": "What is the refund window?" } ] }' # Second identical call: X-ER-Cache: HIT, cost $0 ``` ## Guardrails for a user-facing bot Redact personal data before it leaves your account, flag injection attempts while you tune, cap cost per request, and pin the whole configuration to the bot's key as a preset. ```bash M="Authorization: Bearer $ELEVENROUTER_MANAGEMENT_KEY"; B=https://elevenrouter.com/api/v1/management curl -X POST $B/policies -H "$M" -d '{ "name": "Support bot guardrails", "rules": { "sensitiveInfo": { "action": "redact", "detectors": ["email", "phone", "card", "secret"], "direction": "input" }, "promptInjection": { "action": "flag" }, "limits": { "maxCostUsdPerRequest": 0.25, "maxOutputTokens": 1200 } }, "assignments": [{ "target_type": "api_key", "target_id": "" }] }' curl -X POST $B/presets -H "$M" -d '{ "slug": "support-bot", "name": "Support bot", "config": { "models": ["anthropic/claude-sonnet-5", "openai/gpt-5.6-terra"], "systemPrompt": "You are the support assistant…", "parameters": { "temperature": 0.3, "max_tokens": 800 } } }' curl -X PATCH https://elevenrouter.com/api/v1/keys/ -H "$M" -d '{ "preset_id": "support-bot" }' ``` ## Claude models through the Anthropic SDK — and GPT too Point the Anthropic SDK at `https://elevenrouter.com/api/v1`; the Messages endpoint accepts any model in the catalog, so the same client can call GPT or Gemini with Anthropic-style requests. ```python import anthropic client = anthropic.Anthropic(base_url="https://elevenrouter.com/api/v1", api_key=os.environ["ELEVENROUTER_API_KEY"]) msg = client.messages.create(model="openai/gpt-5.6-luna", max_tokens=300, messages=[{"role": "user", "content": "Hello from the Anthropic SDK"}]) ``` More recipes live in the [integrations guide](https://elevenrouter.com/docs/integrations) (Vercel AI SDK, LangChain, LiteLLM, PydanticAI, coding agents) and the [SDK reference](https://elevenrouter.com/docs/sdks). --- Source: https://elevenrouter.com/docs/cookbook # SDKs Official TypeScript and Python clients, generated from the OpenAPI document so they never drift from the gateway. Thin by design: one method per operation, typed request and response shapes, streaming, retries and the management API. [View as Markdown](https://elevenrouter.com/docs/md/sdks) ## TypeScript — @elevenrouter/sdk ```bash npm install @elevenrouter/sdk ``` ```ts import { ElevenRouter } from '@elevenrouter/sdk'; const client = new ElevenRouter({ apiKey: process.env.ELEVENROUTER_API_KEY, metadata: true }); const res = await client.chat.completions.create({ model: 'anthropic/claude-sonnet-5', models: ['openai/gpt-5.6-terra'], messages: [{ role: 'user', content: 'Summarise this in one line.' }], }); console.log(res.choices[0]?.message.content, res.elevenrouter_metadata?.cost); // Streaming const stream = await client.chat.completions.create({ model: 'openai/gpt-5.6-luna', messages, stream: true }); for await (const chunk of stream) process.stdout.write(chunk.choices[0]?.delta.content ?? ''); console.log(stream.meta.generationId); ``` Works in Node 20+, Bun, Deno, edge runtimes and browsers (bring a key from your backend). No dependencies. Every other endpoint is one call away: `client.models.list()`, `client.embeddings.create()`, `client.messages.create()` (Anthropic format), `client.generation(id)`, `client.credits()`, `client.status()`, `client.analytics.query()`, and the management resources `keys`, `workspaces`, `budgets`, `policies`, `presets`, `notificationRules`, `byok` and `members`. Anything else: `client.call('operationId', …)`. - `apiKey / baseUrl` *(options)*: Default to ELEVENROUTER_API_KEY and ELEVENROUTER_BASE_URL. Point baseUrl at a self-hosted gateway. - `metadata` *(boolean)*: Adds X-ER-Metadata: enabled so inference responses carry the elevenrouter_metadata route receipt. - `maxRetries / timeoutMs` *(number)*: Idempotent calls, 429s and 5xx responses are retried with exponential backoff honouring Retry-After (default 2). Streams are never timed out once started. - `defaultHeaders` *(object)*: Sent on every request — use it for HTTP-Referer / X-Title app attribution or X-ER-Session-Id. - `errors` *(classes)*: ElevenRouterError with subclasses BadRequestError, AuthenticationError, PermissionError, NotFoundError, InsufficientCreditsError, RateLimitError, ServerError, ConnectionError, AbortError; each carries status, type, code, param, metadata, requestId and retryAfterMs. ## Python — elevenrouter ```bash pip install elevenrouter ``` ```python from elevenrouter import ElevenRouter client = ElevenRouter() # reads ELEVENROUTER_API_KEY res = client.chat.completions.create( model="anthropic/claude-sonnet-5", models=["openai/gpt-5.6-terra"], messages=[{"role": "user", "content": "Summarise this in one line."}], ) print(res["choices"][0]["message"]["content"], res["_meta"]["generation_id"]) # Streaming for chunk in client.chat.completions.create(model="openai/gpt-5.6-luna", messages=messages, stream=True): print(chunk["choices"][0]["delta"].get("content", ""), end="", flush=True) # Async from elevenrouter import AsyncElevenRouter async with AsyncElevenRouter() as aclient: res = await aclient.chat.completions.create(model="openai/gpt-5.6-luna", messages=messages) ``` Python 3.9+, one dependency (`httpx`), sync and async clients with the same surface. Responses are plain dicts in the wire format plus a `_meta` entry with the generation id, vendor, request id and rate-limit headers. Errors mirror the TypeScript classes (`RateLimitError`, `InsufficientCreditsError`, …). ## Management API from the SDKs ```ts const admin = new ElevenRouter({ apiKey: process.env.ELEVENROUTER_MANAGEMENT_KEY }); const { data: ws } = await admin.workspaces.create({ name: 'Production', environment: 'production' }); await admin.budgets.create({ scope_type: 'workspace', scope_id: ws.id, interval: 'daily', limit: 250 }); const dry = await admin.policies.dryRun({ rules: { vendors: { mode: 'allow_only', slugs: ['anthropic', 'openai'] } } }); console.log(`would block ${dry.data?.blocked} of ${dry.data?.requests} requests`); const { key } = await admin.keys.create({ name: 'support-backend', workspace_id: ws.id, preset_id: 'support-bot' }); ``` ## Generate your own client Both SDKs are produced by a small generator over [openapi.json](https://elevenrouter.com/api/v1/openapi.json); any OpenAPI 3.0 toolchain (openapi-typescript, openapi-generator, Kiota, …) works against the same document for other languages. The document is versioned with the API and listed in the [changelog](https://elevenrouter.com/docs/changelog). --- Source: https://elevenrouter.com/docs/sdks # Frameworks & coding agents ElevenRouter speaks the OpenAI and Anthropic wire formats, so almost every framework works by changing a base URL. Recipes below, plus environment-variable setups for coding agents and the MCP server. [View as Markdown](https://elevenrouter.com/docs/md/integrations) ## OpenAI SDKs (any language) ```ts import OpenAI from 'openai'; const client = new OpenAI({ baseURL: 'https://elevenrouter.com/api/v1', apiKey: process.env.ELEVENROUTER_API_KEY }); // Use any catalog model id. ElevenRouter extensions (models, provider, transforms) pass through as extra body fields. ``` ## Anthropic SDKs ```python import anthropic client = anthropic.Anthropic(base_url="https://elevenrouter.com/api/v1", api_key=os.environ["ELEVENROUTER_API_KEY"]) msg = client.messages.create(model="openai/gpt-5.6-terra", max_tokens=300, messages=[{"role": "user", "content": "Hi"}]) ``` `POST /messages` accepts the Anthropic format for every model in the catalog — including non-Anthropic ones — and translates tools, system prompts and streaming events. ## Vercel AI SDK ```ts import { createOpenAI } from '@ai-sdk/openai'; import { streamText } from 'ai'; const elevenrouter = createOpenAI({ baseURL: 'https://elevenrouter.com/api/v1', apiKey: process.env.ELEVENROUTER_API_KEY, name: 'elevenrouter' }); const result = streamText({ model: elevenrouter.chat('anthropic/claude-sonnet-5'), prompt: 'Write a product description for a mechanical keyboard.', providerOptions: { openai: { models: ['openai/gpt-5.6-terra'] } }, // fallback, forwarded as an extra field }); ``` ## LangChain / LangGraph ```python from langchain_openai import ChatOpenAI llm = ChatOpenAI( model="anthropic/claude-sonnet-5", base_url="https://elevenrouter.com/api/v1", api_key=os.environ["ELEVENROUTER_API_KEY"], default_headers={"X-Title": "my-agent", "X-ER-Metadata": "enabled"}, model_kwargs={"models": ["openai/gpt-5.6-terra"]}, ) ``` ## LiteLLM ```python import litellm response = litellm.completion( model="openai/anthropic/claude-sonnet-5", # "openai/" selects the OpenAI-compatible provider api_base="https://elevenrouter.com/api/v1", api_key=os.environ["ELEVENROUTER_API_KEY"], messages=[{"role": "user", "content": "Hello"}], ) ``` ## PydanticAI ```python from pydantic_ai import Agent from pydantic_ai.models.openai import OpenAIChatModel from pydantic_ai.providers.openai import OpenAIProvider model = OpenAIChatModel("openai/gpt-5.6-terra", provider=OpenAIProvider(base_url="https://elevenrouter.com/api/v1", api_key=os.environ["ELEVENROUTER_API_KEY"])) agent = Agent(model, instructions="Be concise.") ``` ## Coding agents Most agents read the OpenAI or Anthropic environment variables. Point them at ElevenRouter and pick any catalog model; budgets, guardrails and logs apply exactly as for your own apps. Create a dedicated key per agent so spend is attributable. ```bash # Claude Code (Anthropic format) export ANTHROPIC_BASE_URL=https://elevenrouter.com/api/v1 export ANTHROPIC_AUTH_TOKEN=$ELEVENROUTER_API_KEY export ANTHROPIC_MODEL=anthropic/claude-sonnet-5 # Codex CLI (OpenAI format) export OPENAI_BASE_URL=https://elevenrouter.com/api/v1 export OPENAI_API_KEY=$ELEVENROUTER_API_KEY codex --model openai/gpt-5.6-terra # Cline / Roo Code: choose "OpenAI Compatible", base URL https://elevenrouter.com/api/v1, model id from the catalog. # Cursor: use the dedicated Cursor service (Services → Cursor in the dashboard), not this base URL. # See /docs/tools/cursor. ``` Cursor is special: its base-URL override sends a dialect of its own (Responses-style fields, flat and grammar tools) and needs neutral model names. ElevenRouter ships a [dedicated Cursor service](https://elevenrouter.com/docs/tools/cursor) with its own endpoint, key and plans built for it. ## MCP server `@elevenrouter/mcp` gives agents tools to search the catalog by capability and price, look up official prices with cost estimates, check platform status, debug a request by generation id and summarise spend (management key). It speaks stdio JSON-RPC and needs nothing but Node. ```bash # Claude Code claude mcp add elevenrouter -e ELEVENROUTER_API_KEY=sk-er-v1-… -- npx -y @elevenrouter/mcp # Cursor / Cline / Windsurf (mcpServers) { "mcpServers": { "elevenrouter": { "command": "npx", "args": ["-y", "@elevenrouter/mcp"], "env": { "ELEVENROUTER_API_KEY": "sk-er-v1-…" } } } } ``` Agents can also read this documentation directly: every page is available as Markdown (see [llms.txt](https://elevenrouter.com/docs/llms.txt)), and the OpenAPI document describes every endpoint. --- Source: https://elevenrouter.com/docs/integrations # Cursor A dedicated service for the Cursor editor: its own endpoint, its own key, ready-made model names and plans paid from your credit balance. [View as Markdown](https://elevenrouter.com/docs/md/tools--cursor) Cursor lets you point its OpenAI integration at any compatible endpoint, but what it sends through that override is not plain Chat Completions: depending on the version and the model name it mixes in Responses-API fields, flat tool definitions and grammar tools, expects strictly shaped streaming chunks back, and treats names containing a vendor differently. The Cursor service absorbs all of that so Agent, Ask, Edit, tool calls, images and reasoning models simply work. ## Set up in five steps 1. In the [dashboard](https://app.elevenrouter.com/services/cursor) open **Services → Cursor** and buy a plan. You get a Cursor key (shown once) and the model names to add. One plan is one key for one developer; teams buy one per person. 2. In Cursor press `Ctrl/Cmd + Shift + J`, open **Models → API Keys**. You need an active Cursor Pro (or higher) subscription — Cursor only allows custom models on paid plans. 3. Turn on **Override OpenAI Base URL** and paste the Cursor base URL. Turn on **OpenAI API Key** and paste your Cursor key. Leave the Anthropic and Google key toggles off. ```text Override OpenAI Base URL: https://cursor.elevenrouter.com/v1 OpenAI API Key: sk-er-cursor-v1-… (from Services → Cursor) ``` 4. Under **Model Names** add the names listed on your Services page (for example `er-sonnet-5`, `er-sol-5.6`, `er-deepseek-v4-flash`) and enable them. Disable Cursor's built-in GPT names if you do not want them routed here too. 5. Click **Verify**. ElevenRouter answers the test request instantly and free, and your Services page shows the plan as connected. Pick a model in the chat or agent panel and start. ## Why the model names look the way they do Cursor decides how to build a request from the model name. Names containing `anthropic`, `claude`, `openai`, `gpt`, `gemini` or `vertex` switch it to vendor-specific payloads or make it reject the model outright, and tool calls stop working. ElevenRouter therefore exposes every model under a neutral alias such as `er-opus-5`. The dashboard lists the official model each alias stands for, and responses echo the alias you asked for. ## Plans, allowances and limits Plans are defined by the platform and paid from your credit balance, so every top-up method, promo code and invoice works for them. A plan is a combination of: - `term` *(recurring · fixed · open-ended)*: Recurring plans renew automatically from your balance; fixed plans (e.g. 24 hours) simply end; open-ended packs last until the allowance is used up. - `allowance` *(USD or unlimited)*: Usage is valued at official model rates (times the plan’s rate multiplier) and consumed from the allowance. Nothing is charged to your balance per request. - `limits` *(fair use)*: Requests per minute, concurrent requests, tokens per day and a maximum output length, per plan. - `models` *(all or selected)*: Which aliases the plan may use. Asking for anything else returns a clear error listing the names to add. When the allowance is used up requests are refused with `402 service_allowance_exhausted` until the plan renews (or you renew early from the dashboard). If a renewal cannot be paid the plan keeps working for a grace period while you top up; after that it ends and its key stops working. ## What works inside Cursor - `Ask, Agent, Edit` *(yes)*: Streaming, tool calls (nested, flat and grammar-style custom tools such as ApplyPatch), multi-turn tool results. - `Images` *(vision models)*: Pasted or attached images reach vision models. For text-only models the image is replaced by a short note instead of failing the request. - `Reasoning models` *(yes)*: Thinking is streamed as reasoning_content. Cursor decides whether to show a thinking panel based on the model name; for custom names it often does not, which is a Cursor limitation. - `Long sessions` *(compacted)*: Cursor assumes custom models have a 1M-token window. When a chat outgrows the real model context, the oldest middle turns are compacted (middle-out) so the session continues. - `Tab, Composer, cloud agents, Bugbot, CLI` *(Cursor’s own servers)*: These never use custom keys; Cursor routes them itself. ## The endpoint The Cursor base URL serves exactly what Cursor needs and nothing else. It accepts only Cursor keys (`sk-er-cursor-v1-…`); regular API keys are refused with `cursor_key_required`, and Cursor keys are refused by the regular API with `service_key_not_accepted`. Common base-URL mistakes get a 404 that says how to fix them. ```bash # Model names your plan grants (what to add in Cursor) curl https://cursor.elevenrouter.com/v1/models -H "Authorization: Bearer $CURSOR_KEY" # What Cursor calls (any of Cursor's request shapes is accepted) curl https://cursor.elevenrouter.com/v1/chat/completions \ -H "Authorization: Bearer $CURSOR_KEY" -H "Content-Type: application/json" \ -d '{"model":"er-sonnet-5","messages":[{"role":"user","content":"hi"}],"stream":true}' ``` ## Troubleshooting - `Verify keeps spinning`: Make sure the OpenAI API Key toggle is on (not just filled in) and the base URL ends in /v1 with nothing after it. In Cursor Settings → Network try HTTP Compatibility Mode = HTTP/1.1. - `"Model name is not valid"`: Use the alias exactly as listed on your Services page; do not add vendor names of your own. - `404 cursor_base_url_misconfigured`: The URL you pasted has /chat/completions or a second /v1 at the end. Paste the base URL exactly as shown. - `Requests for gpt-… go to ElevenRouter`: While the override is on, Cursor sends every OpenAI-style model there, including built-in names you left enabled. Disable them, or ask us to map them to your plan. - `402 service_allowance_exhausted`: The plan’s allowance for this period is used up. Renew early or pick a bigger plan on the Services page. - `Key lost`: Keys are shown once. Regenerate from the Services page; the old key stops working immediately. --- Source: https://elevenrouter.com/docs/tools/cursor # API reference Base URL: https://elevenrouter.com/api/v1. All responses are JSON; streaming responses are Server-Sent Events. [View as Markdown](https://elevenrouter.com/docs/md/api-reference) ## POST /chat/completions OpenAI-compatible chat completion. Requires `Authorization: Bearer sk-er-v1-…`. - `model` *(string, required)*: Canonical slug (anthropic/claude-sonnet-5) or accepted alias. Append :nitro to prefer throughput or :floor to prefer price (see Routing). - `messages` *(array, required)*: system, developer, user, assistant and tool messages. Content may be a string or an array of text / image_url / file parts. Text parts and messages accept cache_control: { type: "ephemeral", ttl?: "5m" | "1h" } to place prompt-cache breakpoints (Anthropic semantics; passed through where supported). - `stream` *(boolean)*: Stream Server-Sent Events. The final chunk carries `usage` (and `cost` when requested) before data: [DONE]. - `max_tokens / max_completion_tokens` *(integer)*: Cap on output tokens. Defaults to a model-specific value when the provider requires one. - `temperature, top_p, top_k, stop, seed, frequency_penalty, presence_penalty, repetition_penalty, min_p` *(sampling)*: Forwarded when the model supports the parameter; silently dropped otherwise. - `tools, tool_choice, parallel_tool_calls` *(tools)*: OpenAI function-calling schema. Translated for Anthropic-native providers. - `response_format` *(object)*: text, json_object or json_schema (models advertising structured_outputs). - `reasoning` *(object)*: { effort: minimal|low|medium|high|xhigh, max_tokens, exclude }. Mapped to reasoning_effort or extended thinking per vendor. - `models` *(string[])*: ElevenRouter extension: ordered fallback models tried when the primary has no available endpoint. - `provider` *(object)*: ElevenRouter extension: { order, only, ignore, allow_fallbacks, sort }. See Routing. - `usage.include` *(boolean)*: ElevenRouter extension: adds `cost` (USD) to the usage object. Response headers: `x-er-generation-id`, `x-er-provider` (the model's vendor, e.g. `Anthropic`), `x-er-model`, `x-ratelimit-limit`, `x-ratelimit-remaining`, `x-request-id`. Request headers understood on every inference endpoint: `X-ER-Session-Id` (or body `session_id`) groups requests into a conversation for per-session cost; `X-ER-User-Id` (or the OpenAI `user` field) tags your end user; `X-ER-Metadata: enabled` adds the route receipt below. ## Route receipt (X-ER-Metadata) Send `X-ER-Metadata: enabled` and every response carries an `elevenrouter_metadata` object: how the request was routed and what it cost, to the cent. On streams it rides on the final usage chunk (Responses: on the `response.completed` object; Messages: on `message_delta`). On errors where routing already happened (502, 503) it is placed under `error.metadata.elevenrouter_metadata`. Attempts name the model's vendor and a classified reason; there is nothing to parse and nothing vendor-specific. ```json "elevenrouter_metadata": { "generation_id": "gen-Qm3bHk9ZP2xT7Y1L", "requested_model": "anthropic/claude-sonnet-5:nitro", "model": "anthropic/claude-sonnet-5", "vendor": "Anthropic", "routing": { "strategy": "expiry_first", "sort": "throughput", "eligible_endpoints": 3, "attempt": 2, "attempts": 2, "fallback_model": false, "fallbacks": [{ "vendor": "Anthropic", "outcome": "retryable_error", "reason": "rate_limited", "duration_ms": 118 }] }, "timing_ms": { "routing": 9, "fallback": 118, "ttft": 640, "generation": 1210, "total": 1977 }, "cost": { "currency": "USD", "prompt": 0.000063, "cache_read": 0.0000036, "cache_write": 0, "completion": 0.00057, "reasoning": 0, "request_fee": 0, "platform_fee": 0, "total": 0.0006366, "insured": false, "byok": false }, "pricing": { "prompt_per_million": 3, "completion_per_million": 15, "cache_read_per_million": 0.3, "cache_write_per_million": 3.75, "reasoning_per_million": null, "request_fee": 0 } } ``` - `routing.eligible_endpoints` *(integer)*: Endpoints that could serve the model for your request after credential, health and preference filtering. - `routing.attempt / attempts` *(integer)*: Which attempt produced the response (1-based) and how many were made. attempt is null when every attempt failed. - `routing.fallbacks[].reason` *(string)*: Classified failure of an earlier attempt: rate_limited, overloaded, upstream_error, timeout, network, model_access_denied, quota_exhausted, auth_invalid. - `routing.fallback_model` *(boolean)*: True when a model from your models array served the request instead of the primary one. - `cost.*` *(number (USD))*: Split by token class at the official rates in pricing; total is what your balance was charged (0 when insured). - `timing_ms.*` *(integer)*: routing = before the first upstream call; fallback = time lost to failed attempts; ttft = time to first token; generation = ttft → last token. ## POST /messages Anthropic Messages-compatible endpoint. Point the Anthropic SDK at `https://elevenrouter.com/api/v1` with your ElevenRouter key as `x-api-key` (or `Authorization: Bearer`) and use any model in the catalog, not only Claude. Requests are normalised internally and routed exactly like chat completions; responses, streaming events (`message_start` … `message_stop`) and errors use Anthropic's shapes. Supports `system` (string or blocks with `cache_control`), text / image / document blocks, `tools`, `tool_choice`, `thinking`, `stop_sequences`, `metadata.user_id` and the ElevenRouter `models` / `provider` extensions. ```bash curl https://elevenrouter.com/api/v1/messages \ -H "x-api-key: $ELEVENROUTER_API_KEY" \ -H "anthropic-version: 2023-06-01" \ -H "content-type: application/json" \ -d '{ "model": "openai/gpt-5.6-luna", "max_tokens": 256, "messages": [{ "role": "user", "content": "Hello" }] }' ``` Usage is reported as `input_tokens`, `output_tokens`, `cache_read_input_tokens` and `cache_creation_input_tokens`; `cost` is added when the request includes `usage.include`. Errors come back as `{ "type": "error", "error": { "type", "message" } }`. ## POST /responses OpenAI Responses API dialect. Accepts `input` as a string or an item list (messages, `function_call`, `function_call_output`), `instructions`, `max_output_tokens`, function `tools`, `tool_choice`, `reasoning.effort`, `text.format` (JSON schema) and `text.verbosity`. Streaming emits `response.created`, `response.output_text.delta`, `response.function_call_arguments.delta` and finishes with `response.completed` (or `response.incomplete` when truncated). Server-side conversation state (`previous_response_id`) and hosted tools are not supported; send the full conversation each time. ```json { "id": "resp_Qm3bHk9ZP2xT7Y1L", "object": "response", "status": "completed", "model": "openai/gpt-5.6-luna", "provider": "OpenAI", "output": [{ "id": "msg_…", "type": "message", "role": "assistant", "status": "completed", "content": [{ "type": "output_text", "text": "Hello!", "annotations": [] }] }], "output_text": "Hello!", "usage": { "input_tokens": 8, "output_tokens": 2, "total_tokens": 10, "input_tokens_details": { "cached_tokens": 0 }, "output_tokens_details": { "reasoning_tokens": 0 } } } ``` ## POST /completions Legacy text completions. `prompt` (string or string[]) becomes a single user message; the reply is returned as `choices[].text` with `object: "text_completion"`. Streams end with `data: [DONE]`. ## POST /embeddings OpenAI-compatible embeddings. `input` is a string, an array of strings, or token arrays; `dimensions` and `encoding_format` are forwarded. Embedding models appear in `GET /models` with modality `text->embedding` and are billed on input tokens only at the official rate. Fallback `models`, `provider` preferences and `usage.include` work as for chat. ```bash curl https://elevenrouter.com/api/v1/embeddings \ -H "Authorization: Bearer $ELEVENROUTER_API_KEY" \ -H "content-type: application/json" \ -d '{ "model": "openai/text-embedding-3-small", "input": ["hello", "world"], "usage": { "include": true } }' ``` ## GET /models Public. Lists active models with official per-token pricing (decimal strings, USD per token), context length, supported parameters and the number of live endpoints. ```json { "object": "list", "data": [{ "id": "anthropic/claude-haiku-4.5", "name": "Anthropic: Claude Haiku 4.5", "context_length": 200000, "pricing": { "prompt": "0.000001", "completion": "0.000005", "input_cache_read": "0.0000001", "input_cache_write": "0.00000125", "request": "0", "image": "0" }, "top_provider": { "context_length": 200000, "max_completion_tokens": 64000, "is_moderated": false }, "supported_parameters": ["max_tokens", "temperature", "tools", "reasoning", "..."], "endpoints_available": 1 }] } ``` ## GET /auth/key Information about the calling key: label, spend limit, usage, remaining limit and rate limit. ## GET /credits Total credits purchased or granted and total usage for the organization that owns the key. ## GET /generation?id=gen-… Metadata for one request: model, provider, status, finish reason, prompt / completion / cached / reasoning tokens, total cost, latency and generation time. ```json { "data": { "id": "gen-Qm3bHk9ZP2xT7Y1L", "model": "anthropic/claude-sonnet-5", "provider_name": "Anthropic", "status": "succeeded", "streamed": true, "finish_reason": "stop", "tokens_prompt": 21, "tokens_completion": 38, "native_tokens_cached": 0, "native_tokens_reasoning": 0, "total_cost": 0.000422, "latency": 812, "generation_time": 1460, "created_at": "2026-09-14T18:42:11.204Z" } } ``` --- Source: https://elevenrouter.com/docs/api-reference # API reference Generated from the same OpenAPI document the gateway validates against, so it cannot drift. Every operation, parameter and schema below is what the SDKs are built from. [View as Markdown](https://elevenrouter.com/docs/md/reference) Base URL `https://elevenrouter.com/api/v1`. Authenticate with `Authorization: Bearer sk-er-v1-…`. Download the document at [elevenrouter.com/api/v1/openapi.json](https://elevenrouter.com/api/v1/openapi.json) to generate your own client, or use the [official SDKs](https://elevenrouter.com/docs/sdks). ## Inference Chat, responses, messages, completions and embeddings. post`/chat/completions`Create a chat completionbearer OpenAI Chat Completions format. Supports streaming (`stream: true`, SSE), tools, structured outputs, reasoning, fallback `models`, `provider` routing preferences and `usage.include` for cost in the response. Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · ChatCompletionRequest - `model`stringrequired - `messages`object[]requiredpropertiesarray of object`role`"system" | "developer" | "user" | "assistant" | "tool" | "function"required`content`string | object | object | object | object[] | nullpropertiesstring | object | object | object | object[] | null`name`string`tool_calls`object[]propertiesarray of object3 properties`tool_call_id`string`refusal`string | null`reasoning`string | null`cache_control`objectproperties`type`"ephemeral"required`ttl`"5m" | "1h" - `stream`boolean - `stream_options`objectproperties`include_usage`boolean - `max_tokens`integer | null - `max_completion_tokens`integer | null - `temperature`number | null - `top_p`number | null - `top_k`integer - `frequency_penalty`number | null - `presence_penalty`number | null - `repetition_penalty`number - `min_p`number - `top_a`number - `seed`integer | null - `stop`string | string[] | nullpropertiesOption 1stringOption 2array of stringstring - `n`integer | null - `logit_bias`object | null - `logprobs`boolean | null - `top_logprobs`integer | null - `response_format`object | object | objectpropertiesOption 1`type`"text"requiredOption 2`type`"json_object"requiredOption 3`type`"json_schema"required`json_schema`objectrequiredproperties`name`stringrequired`description`string`schema`object`strict`boolean | null - `tools`object[]propertiesarray of object`type`"function"required`function`objectrequiredproperties`name`stringrequired`description`string`parameters`object`strict`boolean | null - `tool_choice`"none" | "auto" | "required" | objectpropertiesOption 1"none" | "auto" | "required"Option 2`type`"function"required`function`objectrequiredproperties`name`stringrequired - `parallel_tool_calls`boolean - `user`string - `metadata`object - `reasoning`objectproperties`effort`"none" | "minimal" | "low" | "medium" | "high" | "xhigh"`max_tokens`integer`exclude`boolean`enabled`boolean - `reasoning_effort`"none" | "minimal" | "low" | "medium" | "high" | "xhigh" - `verbosity`"low" | "medium" | "high" - `models`string[] - `provider`objectproperties`order`string[]`allow_fallbacks`boolean`ignore`string[]`only`string[]`sort`"price" | "throughput" | "latency"`require_parameters`boolean`max_price`objectproperties`prompt`number`completion`number`request`number`preferred_min_throughput`number | objectpropertiesOption 1numberOption 2`p50`number`p75`number`p90`number`p99`number`preferred_max_latency`number | objectpropertiesOption 1numberOption 2`p50`number`p75`number`p90`number`p99`number`quantizations`string[]`data_collection`"allow" | "deny" - `route`"fallback" - `usage`objectproperties`include`boolean - `transforms`"middle-out"[] - `plugins`object[]propertiesarray of object`id`"response-healing" | "web" | "file-parser" | "server-tools"required`max_results`integer`search_prompt`string`tools`"datetime" | "search_models"[]`max_rounds`integer - `session_id`string Responses - `200`Completion, or an SSE stream of `ChatCompletionChunk` events ending with `data: [DONE]`.ChatCompletionResponseschema`id`stringrequired`object`"chat.completion"required`created`integerrequired`model`stringrequired`provider`string`choices`object[]requiredpropertiesarray of object`index`integerrequired`message`objectrequiredproperties`role`"assistant"required`content`string | nullrequired`refusal`string | null`reasoning`string | null`tool_calls`object[]propertiesarray of object3 properties`finish_reason`"stop" | "length" | "tool_calls" | "content_filter" | "function_call" | "error" | nullrequired`native_finish_reason`string | null`logprobs`any | null`usage`objectproperties`prompt_tokens`integerrequired`completion_tokens`integerrequired`total_tokens`integerrequired`prompt_tokens_details`objectproperties`cached_tokens`integer`cache_write_tokens`integer`audio_tokens`integer`completion_tokens_details`objectproperties`reasoning_tokens`integer`audio_tokens`integer`accepted_prediction_tokens`integer`rejected_prediction_tokens`integer`cost`number`cost_details`objectproperties`upstream_inference_cost`number | null`system_fingerprint`string | null - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/completions`Create a text completion (legacy)bearer OpenAI legacy completions format (`prompt` string). Translated to chat internally. Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · object - `model`stringrequired - `prompt`stringrequired - `stream`boolean - `max_tokens`integer - `temperature`number Responses - `200`Completion. - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/embeddings`Create embeddingsbearer Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · EmbeddingsRequest - `model`stringrequired - `input`string | string[] | integer[] | integer[][]requiredpropertiesOption 1stringOption 2array of stringstringOption 3array of integerintegerOption 4array of integer[]array of integerinteger - `encoding_format`"float" | "base64" - `dimensions`integer - `user`string - `models`string[] - `provider`objectproperties`order`string[]`allow_fallbacks`boolean`ignore`string[]`only`string[]`sort`"price" | "throughput" | "latency"`require_parameters`boolean`max_price`objectproperties`prompt`number`completion`number`request`number`preferred_min_throughput`number | objectpropertiesOption 1numberOption 2`p50`number`p75`number`p90`number`p99`number`preferred_max_latency`number | objectpropertiesOption 1numberOption 2`p50`number`p75`number`p90`number`p99`number`quantizations`string[]`data_collection`"allow" | "deny" - `usage`objectproperties`include`boolean Responses - `200`Embedding vectors.EmbeddingsResponseschema`object`"list"required`data`object[]requiredpropertiesarray of object`object`"embedding"required`index`integerrequired`embedding`number[] | stringrequiredpropertiesnumber[] | string`model`stringrequired`provider`string`usage`objectrequiredproperties`prompt_tokens`integerrequired`total_tokens`integerrequired`cost`number - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/messages`Create a message (Anthropic Messages API)bearer Anthropic Messages format for any model in the catalog. Accepts `x-api-key` or a bearer token. Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · object - `model`stringrequired - `max_tokens`integerrequired - `messages`object[]required - `system`any - `stream`boolean Responses - `200`Message or SSE stream. - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/responses`Create a response (OpenAI Responses API)bearer OpenAI Responses format (`input`, `instructions`, streaming events). Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · object - `model`stringrequired - `input`anyrequired - `instructions`string - `stream`boolean Responses - `200`Response object or SSE stream. - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope ## Models The public catalog with official pricing and live availability. get`/collections`Curated and automatic model collectionspublic Responses - `200`Collections.objectschema`data`Collection[] get`/collections/{slug}`A collection with its modelspublic Parameters - `slug`path · stringrequired Responses - `200`Collection with full model records under `items`.objectschema`data`Collection & object - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/models`List modelsbearer Every model with official pricing, context length, modalities, supported parameters and live `availability`. Anonymous. With an API key of yours (either kind) the list also includes your organization’s private models. Responses - `200`Model list.ModelsListResponseschema`object`"list"required`data`object[]requiredpropertiesarray of object`id`stringrequired`canonical_slug`stringrequired`name`stringrequired`created`integerrequired`description`stringrequired`context_length`integer | nullrequired`architecture`objectrequiredproperties`modality`stringrequired`input_modalities`string[]required`output_modalities`string[]required`tokenizer`stringrequired`instruct_type`string | nullrequired`pricing`objectrequiredproperties`prompt`stringrequired`completion`stringrequired`request`stringrequired`image`stringrequired`input_cache_read`string`input_cache_write`string`internal_reasoning`string`top_provider`objectrequiredproperties`context_length`integer | nullrequired`max_completion_tokens`integer | nullrequired`is_moderated`booleanrequired`per_request_limits`null | nullrequired`supported_parameters`string[]required`endpoints_available`integerrequired`availability`"available" | "degraded" | "unavailable" | "no_keys" | "unknown"`family`string | null`latest_alias`string | null`deprecated_at`string | null`retired_at`string | null`successor`string | null get`/models/{vendor}/{model}`Get a modelpublic Also accepts `~vendor/family-latest` aliases and `:variant` suffixes, e.g. `/models/~anthropic/claude-sonnet-latest`. Parameters - `vendor`path · stringrequiredVendor slug, e.g. `anthropic` (or `~anthropic` for a latest alias). - `model`path · stringrequiredModel name, e.g. `claude-sonnet-5`, optionally with a variant suffix (`:nitro`). Responses - `200`Model.objectschema`data`Modelproperties`id`stringrequired`canonical_slug`stringrequired`name`stringrequired`created`integerrequired`description`stringrequired`context_length`integer | nullrequired`architecture`objectrequiredproperties`modality`stringrequired`input_modalities`string[]required`output_modalities`string[]required`tokenizer`stringrequired`instruct_type`string | nullrequired`pricing`objectrequiredproperties`prompt`stringrequired`completion`stringrequired`request`stringrequired`image`stringrequired`input_cache_read`string`input_cache_write`string`internal_reasoning`string`top_provider`objectrequiredproperties`context_length`integer | nullrequired`max_completion_tokens`integer | nullrequired`is_moderated`booleanrequired`per_request_limits`null | nullrequired`supported_parameters`string[]required`endpoints_available`integerrequired`availability`"available" | "degraded" | "unavailable" | "no_keys" | "unknown"`family`string | null`latest_alias`string | null`deprecated_at`string | null`retired_at`string | null`successor`string | null - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/models/{vendor}/{model}/stats`Pricing history, uptime, performance, usage trend and related modelspublic Parameters - `vendor`path · stringrequired - `model`path · stringrequired Responses - `200`Stats.objectschema`data`ModelStatsproperties`id`string`metrics`ModelMetricsproperties`id`string`requests_7d`integer`tokens_7d`integer`tokens_30d`integer`latency_p50_ms`integer | nullMedian time to first token over the last 7 days.`latency_p95_ms`integer | null`throughput_p50_tps`number | nullMedian output tokens per second.`throughput_p95_tps`number | null`samples`integer`pricing_history`object[]propertiesarray of object`effective_from`string (date-time)`effective_to`string (date-time) | null`prompt`numberUSD per million tokens.`completion`number`cache_read`number | null`cache_write_5m`number | null`cache_write_1h`number | null`reasoning`number | null`request_fee`number`source_url`string | null`uptime`objectproperties`status`"operational" | "degraded" | "outage" | "unknown"`uptime_3d`number | null`uptime_30d`number | null`days`object[]propertiesarray of object4 properties`usage_trend`object[]propertiesarray of object`day`string (date)`requests`integer`tokens`integer`related`objectproperties`family`string[]`vendor`string[]`similar_price`string[] - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/models/metrics`Observed performance and usage per modelpublic Aggregate, anonymous platform metrics for every listed model: requests and tokens (7d/30d) and p50/p95 time-to-first-token and throughput over the last 7 days (null under 5 samples). No authentication. Responses - `200`Metrics.objectschema`data`ModelMetrics[] get`/models/modalities`Models grouped by modalitypublic Parameters - `output`query · stringFilter by output modality (`image`, `audio`, `embedding`, `rerank`, `text`). - `input`query · stringFilter by input modality (`text`, `image`, `audio`, `file`). Responses - `200`Filtered models and per-modality id lists.objectschema`data`Model[]`modalities`object get`/rankings`Top models and vendors by tokenspublic Aggregate token volume routed through ElevenRouter over the window, with growth versus the previous window, vendor shares and apps that opted into public attribution. Parameters - `window`query · "7d" | "30d" Responses - `200`Rankings.objectschema`data`Rankingsproperties`window`"7d" | "30d"`from`string (date-time)`to`string (date-time)`total_tokens`integer`models`object[]propertiesarray of object`id`string`name`string`vendor`string`tokens`integer`previous_tokens`integer`growth`number | nullPercent change versus the previous window.`requests`integer`share`number`vendors`object[]propertiesarray of object`slug`string`name`string`tokens`integer`share`number`models`integer`apps`object[]Only organizations that opted into public attribution.propertiesarray of object`title`string`url`string | null`tokens`integer`requests`integer`top_model`string | null`generated_at`string (date-time) get`/vendors`Model vendors with counts, price floors, uptime and recent price changespublic Responses - `200`Vendors.objectschema`data`Vendor[] get`/vendors/{vendor}`A vendor with its modelspublic Parameters - `vendor`path · stringrequired Responses - `200`Vendor with full model records under `items`.objectschema`data`Vendor & object - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope ## Account Key info, credits and generation lookups for the calling key. get`/auth/key`Current key infobearer Label, spend limit, remaining limit and usage for the calling API key. Responses - `200`Key info.KeyInfoResponseschema`data`objectrequiredproperties`label`stringrequired`limit`number | nullrequired`usage`numberrequired`limit_remaining`number | nullrequired`limit_reset`"daily" | "weekly" | "monthly" | nullrequired`is_free_tier`booleanrequired`rate_limit`objectrequiredproperties`requests`integerrequired`interval`stringrequired - `401`Missing or invalid API key.ErrorEnvelope post`/auth/keys`Exchange an OAuth PKCE code for an API keypublic Public clients: send the user to `/oauth/authorize` on the dashboard with `callback_url`, `code_challenge` (S256) and `state`; exchange the returned `code` with the original `code_verifier`. Codes expire after 10 minutes and are single-use. Request body · object - `code`stringrequired - `code_verifier`stringrequired - `code_challenge_method`"S256" Responses - `201`The new key (shown once).objectschema`key`string`key_id`string (uuid)`organization_id`string (uuid)`user_id`string`expires_at`string | null - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope get`/credits`Creditsbearer Responses - `200`Total credits purchased and used.CreditsResponseschema`data`objectrequiredproperties`total_credits`numberrequired`total_usage`numberrequired - `401`Missing or invalid API key.ErrorEnvelope get`/generation`Get a generationbearer Usage, cost and timing for one request by its `x-er-generation-id`. Parameters - `id`query · stringrequired Responses - `200`Generation.GenerationResponseschema`data`objectrequiredproperties`id`stringrequired`model`stringrequired`provider_name`string | nullrequired`created_at`stringrequired`streamed`booleanrequired`cancelled`booleanrequired`finish_reason`string | nullrequired`native_finish_reason`string | nullrequired`latency`number | nullrequired`generation_time`number | nullrequired`moderation_latency`number | nullrequired`tokens_prompt`integerrequired`tokens_completion`integerrequired`native_tokens_prompt`integerrequired`native_tokens_completion`integerrequired`native_tokens_reasoning`integerrequired`native_tokens_cached`integerrequired`native_tokens_cache_write`integerrequired`total_cost`numberrequired`upstream_inference_cost`number | nullrequired`usage`numberrequired`is_byok`booleanrequired`upstream_id`string | nullrequired`api_type`stringrequired`status`"pending" | "succeeded" | "failed" | "cancelled"required`error_code`string | nullrequired - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope ## Status Public platform status, uptime history, incidents and the API changelog. No authentication. get`/changelog`API changelog and versioning policypublic Responses - `200`Entries, newest first.objectschema`api_version`string`policy`object`entries`ChangelogEntry[] get`/status`Platform statuspublic Per-model and per-vendor availability from the routing engine with up to 90 days of daily uptime, plus active incidents, scheduled maintenance and recently resolved incidents. No authentication. Parameters - `days`query · integer Responses - `200`Status.PublicStatusschema`status`"operational" | "degraded" | "partial_outage" | "major_outage" | "maintenance"`summary`string`generatedAt`string (date-time)`days`integer`vendors`object[]propertiesarray of object`slug`string`name`string`status`string`uptime90`number | null`models`integer`models`object[]propertiesarray of object`id`string`name`string`vendor`string`status`"operational" | "degraded" | "outage" | "unknown"`uptime90`number | null`uptime30`number | null`days`object[]propertiesarray of object4 properties`activeIncidents`PublicIncident[]`scheduledMaintenance`PublicIncident[]`recentIncidents`PublicIncident[] get`/status/incidents/{id}`Get an incidentpublic Parameters - `id`path · stringrequired Responses - `200`Incident.objectschema`data`PublicIncidentproperties`id`string (uuid)`title`string`kind`"incident" | "maintenance"`status`"investigating" | "identified" | "monitoring" | "resolved" | "scheduled" | "in_progress" | "completed"`impact`"none" | "minor" | "major" | "critical" | "maintenance"`affectedModels`string[]`affectedVendors`string[]`components`string[]`scheduledStart`string (date-time) | null`scheduledEnd`string (date-time) | null`startedAt`string (date-time)`resolvedAt`string (date-time) | null`updates`object[]propertiesarray of object`id`string`status`string`body`string`createdAt`string (date-time) - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope ## Media Image generation, rerank, text-to-speech and speech-to-text, routed and billed like chat. post`/audio/speech`Text to speechbearer Returns audio bytes (`audio/mpeg` by default). Billed per input character at the model's prompt rate per million; the cost is in the `x-er-cost` header. Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · SpeechRequest - `model`stringrequired - `models`string[] - `input`stringrequired - `voice`stringrequired - `response_format`"mp3" | "opus" | "aac" | "flac" | "wav" | "pcm" - `speed`number - `instructions`string - `provider`objectRouting preferences (same shape as the chat request provider block). Responses - `200`Audio bytes. - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/audio/transcriptions`Speech to textbearer JSON body with base64 audio (no multipart needed). Billed per minute of audio (`audioPerMinute`) using the duration the model reports. Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · TranscriptionRequest - `model`stringrequired - `models`string[] - `file`stringrequiredBase64 audio, raw or as a data URL. - `filename`string - `language`string - `prompt`string - `response_format`"json" | "text" | "verbose_json" - `temperature`number - `provider`objectRouting preferences (same shape as the chat request provider block). - `usage`objectproperties`include`boolean Responses - `200`Transcript.TranscriptionResponseschema`text`string`duration`number`language`string`model`string`provider`string`usage`objectproperties`cost`number`units`objectproperties`minutes`number - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/images/generations`Generate imagesbearer OpenAI-compatible image generation for models whose output modality is `image`. Billed per image at the official price; `usage.units.images` reports what was produced. Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · ImagesRequest - `model`stringrequiredAn image model id (output modality `image`). - `models`string[]Fallback models. - `prompt`stringrequired - `n`integer - `size`string - `quality`string - `style`string - `response_format`"url" | "b64_json" - `background`string - `output_format`string - `provider`objectRouting preferences (same shape as the chat request provider block). - `usage`objectproperties`include`boolean Responses - `200`Generated images (`b64_json` or `url`).ImagesResponseschema`created`integer`data`object[]propertiesarray of object`url`string`b64_json`string`revised_prompt`string`model`string`provider`stringOfficial vendor of the model.`usage`objectproperties`cost`number`units`objectproperties`images`integer - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/rerank`Rerank documentsbearer Relevance scores for documents against a query (Cohere/Jina-compatible). Billed on tokens at the model's prompt rate. Parameters - `X-ER-Session-Id`header · stringGroups requests into a session (per-conversation cost in Logs). Also accepted as `session_id` in the body. - `X-ER-User-Id`header · stringYour end-user identifier for per-user analytics. The OpenAI `user` body field is equivalent. - `X-ER-Metadata`header · "enabled" | "disabled"Set to `enabled` to receive an `elevenrouter_metadata` route receipt on the response. - `X-ER-Cache`header · "true" | "false"Set to `true` to serve exact repeats from a per-key response cache (free hits). Responses carry `X-ER-Cache: HIT|MISS|BYPASS`, `X-ER-Cache-Age`, `X-ER-Cache-TTL` and `X-ER-Cache-Source-Id`. - `X-ER-Cache-TTL`header · integerCache lifetime in seconds (60–604800, default 3600). - `X-ER-Cache-Clear`header · "true" | "false"Set to `true` to ignore a stored answer and overwrite it. - `HTTP-Referer`header · stringOptional app attribution: your app URL. - `X-Title`header · stringOptional app attribution: your app name. Request body · RerankRequest - `model`stringrequired - `models`string[] - `query`stringrequired - `documents`string | object[]required - `top_n`integer - `return_documents`boolean - `provider`objectRouting preferences (same shape as the chat request provider block). - `usage`objectproperties`include`boolean Responses - `200`Ranked results.RerankResponseschema`model`string`provider`string`results`object[]propertiesarray of object`index`integer`relevance_score`number`document`objectproperties`text`string`usage`objectproperties`total_tokens`integer`cost`number - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope ## Files Customer files: batch inputs and documents referenced from messages as `{ type: "file", file: { file_id } }`. get`/files`List filesbearer Parameters - `purpose`query · "batch" | "batch_output" | "user_data" - `limit`query · integer Responses - `200`Files.objectschema`object`string`data`File[] - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/files`Upload a filebearer JSON with base64 content, or a raw body (`application/pdf`, `application/jsonl`, `text/plain`, …) with `x-er-purpose` and `x-er-filename` headers. Files are limited to 50 MB; batch inputs are validated line by line at upload. Request body · FileUploadRequest - `purpose`"batch" | "user_data"required - `filename`stringrequired - `content_base64`stringrequired - `mime_type`string - `expires_after_seconds`integer Responses - `201`File metadata.Fileschema`id`string`object`"file"`bytes`integer`created_at`integer`filename`string`purpose`"batch" | "batch_output" | "user_data"`mime_type`string`line_count`integer | null`expires_at`integer | null - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope delete`/files/{id}`Delete a filebearer Parameters - `id`path · stringrequired Responses - `200`Deleted.objectschema`id`string`object`string`deleted`boolean - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope get`/files/{id}`File metadatabearer Parameters - `id`path · stringrequired Responses - `200`File.Fileschema`id`string`object`"file"`bytes`integer`created_at`integer`filename`string`purpose`"batch" | "batch_output" | "user_data"`mime_type`string`line_count`integer | null`expires_at`integer | null - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope get`/files/{id}/content`Download file contentbearer Parameters - `id`path · stringrequired Responses - `200`Raw bytes with the stored content type. - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope ## Batches Asynchronous JSONL batches executed through the gateway at bounded concurrency. get`/batches`List batchesbearer Parameters - `limit`query · integer - `after`query · string Responses - `200`Batches.objectschema`object`string`data`Batch[]`has_more`boolean - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/batches`Create a batchbearer Runs every line of a JSONL input file (`{custom_id, method, url, body}`) through the gateway at bounded concurrency. Each line is billed and logged like a normal request; results land in an output file, failures in an error file. Request body · BatchCreateRequest - `input_file_id`stringrequired - `endpoint`"/v1/chat/completions" | "/v1/embeddings"required - `completion_window`"24h" - `metadata`object Responses - `201`Batch.Batchschema`id`string`object`"batch"`endpoint`string`input_file_id`string`output_file_id`string | null`error_file_id`string | null`status`"validating" | "failed" | "in_progress" | "finalizing" | "completed" | "expired" | "cancelling" | "cancelled"`completion_window`string`request_counts`objectproperties`total`integer`completed`integer`failed`integer`errors`object | null`metadata`object`created_at`integer`in_progress_at`integer | null`expires_at`integer | null`finalizing_at`integer | null`completed_at`integer | null`failed_at`integer | null`cancelled_at`integer | null - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope get`/batches/{id}`Get a batchbearer Parameters - `id`path · stringrequired Responses - `200`Batch.Batchschema`id`string`object`"batch"`endpoint`string`input_file_id`string`output_file_id`string | null`error_file_id`string | null`status`"validating" | "failed" | "in_progress" | "finalizing" | "completed" | "expired" | "cancelling" | "cancelled"`completion_window`string`request_counts`objectproperties`total`integer`completed`integer`failed`integer`errors`object | null`metadata`object`created_at`integer`in_progress_at`integer | null`expires_at`integer | null`finalizing_at`integer | null`completed_at`integer | null`failed_at`integer | null`cancelled_at`integer | null - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope post`/batches/{id}/cancel`Cancel a batchbearer Parameters - `id`path · stringrequired Responses - `200`Batch (cancelling or cancelled).Batchschema`id`string`object`"batch"`endpoint`string`input_file_id`string`output_file_id`string | null`error_file_id`string | null`status`"validating" | "failed" | "in_progress" | "finalizing" | "completed" | "expired" | "cancelling" | "cancelled"`completion_window`string`request_counts`objectproperties`total`integer`completed`integer`failed`integer`errors`object | null`metadata`object`created_at`integer`in_progress_at`integer | null`expires_at`integer | null`finalizing_at`integer | null`completed_at`integer | null`failed_at`integer | null`cancelled_at`integer | null - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope - `402`Insufficient credits, key spend limit or budget reached.ErrorEnvelope - `403`Model not allowed for this key, or policy block.ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope - `502`Every eligible endpoint failed upstream.ErrorEnvelope - `503`No endpoint can serve the model right now.ErrorEnvelope ## Management Control plane for management keys: inference keys, workspaces, budgets, policies, presets, notification rules, BYOK credentials and members. Rate-limited per management key (default 120 requests/minute) and audit-logged. get`/analytics/metrics`Analytics catalogbearer Metrics, dimensions, granularities and filters accepted by `POST /analytics/query`. Responses - `200`Catalog. post`/analytics/query`Query usage analyticsbearer The engine behind the dashboard: aggregate requests, spend, tokens, cache hit rate, latency percentiles and more over a range, bucketed by hour/day/week/month and broken down by up to two dimensions (model, vendor, api_key, workspace, status, finish_reason, end_user, session, app, api_type, streamed, byok, error_code). Request body · object - `from`string (date-time)required - `to`string (date-time)required - `timezone`stringIANA zone for bucket boundaries (default UTC). - `granularity`"hour" | "day" | "week" | "month" | "total" | "auto" - `metrics`string[]required - `dimensions`string[] - `filters`objectproperties`model`string[]`vendor`string[]`api_key_id`string[]`workspace_id`string[]`status`"succeeded" | "failed" | "cancelled"[]`finish_reason`string[]`user`string[]`session`string[]`app`string[]`streamed`boolean`byok`boolean`error_code`string[] - `limit`integerTop-N values of the first dimension; the rest fold into `__other__`. Responses - `200`Rows of `{ bucket, dimensions, metrics }` plus display labels for ids.objectschema`data`objectproperties`rows`object[]propertiesarray of object`bucket`string | nullBucket start in the query time zone, `YYYY-MM-DDTHH:mm:ss`.`dimensions`object`metrics`object`labels`object`truncated`boolean - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope get`/keys`List API keysbearer Parameters - `limit`query · integer - `offset`query · integer - `include_disabled`query · boolean Responses - `200`Keys.objectschema`data`ApiKey[] post`/keys`Create an API keybearer The plaintext `key` is returned once and never again. Request body · ApiKeyWrite - `name`string - `workspace_id`stringWorkspace id or slug (create only). - `limit`number | null - `limit_reset`"daily" | "weekly" | "monthly" | null - `rate_limit_per_minute`integer | null - `allowed_models`string[] | null - `preset_id`string | nullPreset id or slug applied to every request through the key. - `expires_at`string (date-time) | nullClamped to the account’s maximum key lifetime when one is set. - `disabled`booleanUpdate only. Responses - `201`Created.objectschema`data`ApiKeyproperties`id`string (uuid)required`hash`stringrequiredSHA-256 of the key; also accepted as the path id.`name`stringrequired`label`stringrequiredDisplay prefix, e.g. `sk-er-v1-3f9a…c21e`.`kind`"inference"required`workspace_id`string (uuid) | null`disabled`booleanrequired`limit`number | nullUSD spend limit (lifetime or per period).`limit_reset`"daily" | "weekly" | "monthly" | null`limit_remaining`number | null`usage`numberrequiredLifetime USD spend.`usage_period`numberUSD spend in the current reset period.`rate_limit_per_minute`integer | null`allowed_models`string[] | null`preset_id`string (uuid) | null`expires_at`string (date-time) | null`last_used_at`string (date-time) | null`created_at`string (date-time)required`updated_at`string (date-time)required`key`string delete`/keys/{id}`Delete an API keybearer Parameters - `id`path · stringrequired Responses - `200`Deleted. - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/keys/{id}`Get an API keybearer Parameters - `id`path · stringrequiredKey id or hash. Responses - `200`Key.objectschema`data`ApiKeyproperties`id`string (uuid)required`hash`stringrequiredSHA-256 of the key; also accepted as the path id.`name`stringrequired`label`stringrequiredDisplay prefix, e.g. `sk-er-v1-3f9a…c21e`.`kind`"inference"required`workspace_id`string (uuid) | null`disabled`booleanrequired`limit`number | nullUSD spend limit (lifetime or per period).`limit_reset`"daily" | "weekly" | "monthly" | null`limit_remaining`number | null`usage`numberrequiredLifetime USD spend.`usage_period`numberUSD spend in the current reset period.`rate_limit_per_minute`integer | null`allowed_models`string[] | null`preset_id`string (uuid) | null`expires_at`string (date-time) | null`last_used_at`string (date-time) | null`created_at`string (date-time)required`updated_at`string (date-time)required - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope patch`/keys/{id}`Update an API keybearer Parameters - `id`path · stringrequired Request body · ApiKeyWrite - `name`string - `workspace_id`stringWorkspace id or slug (create only). - `limit`number | null - `limit_reset`"daily" | "weekly" | "monthly" | null - `rate_limit_per_minute`integer | null - `allowed_models`string[] | null - `preset_id`string | nullPreset id or slug applied to every request through the key. - `expires_at`string (date-time) | nullClamped to the account’s maximum key lifetime when one is set. - `disabled`booleanUpdate only. Responses - `200`Updated.objectschema`data`ApiKeyproperties`id`string (uuid)required`hash`stringrequiredSHA-256 of the key; also accepted as the path id.`name`stringrequired`label`stringrequiredDisplay prefix, e.g. `sk-er-v1-3f9a…c21e`.`kind`"inference"required`workspace_id`string (uuid) | null`disabled`booleanrequired`limit`number | nullUSD spend limit (lifetime or per period).`limit_reset`"daily" | "weekly" | "monthly" | null`limit_remaining`number | null`usage`numberrequiredLifetime USD spend.`usage_period`numberUSD spend in the current reset period.`rate_limit_per_minute`integer | null`allowed_models`string[] | null`preset_id`string (uuid) | null`expires_at`string (date-time) | null`last_used_at`string (date-time) | null`created_at`string (date-time)required`updated_at`string (date-time)required - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/budgets`List budgetsbearer Responses - `200`Budgets.objectschema`data`Budget[] - `401`Missing or invalid API key.ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope post`/management/budgets`Create a budgetbearer Request body · BudgetWrite - `scope_type`"organization" | "workspace" | "api_key"Create only. - `scope_id`stringWorkspace id/slug or key id/hash (create only; omitted for organization scope). - `interval`"daily" | "weekly" | "monthly" | "lifetime"Create only. - `limit`number - `mode`"hard" | "soft" - `include_byok`boolean - `alert_thresholds`number[] Responses - `201`Created.objectschema`data`Budgetproperties`id`string (uuid)`scope_type`"organization" | "workspace" | "api_key"`scope_id`string`interval`"daily" | "weekly" | "monthly" | "lifetime"`limit`number`mode`"hard" | "soft"`include_byok`boolean`alert_thresholds`number[]`spent`number`remaining`number`used_percent`number`period_start`string (date-time)`period_end`string (date-time) | null`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope delete`/management/budgets/{id}`Delete a budgetbearer Parameters - `id`path · stringrequiredBudget id. Responses - `200`Deleted. - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/budgets/{id}`Get a budgetbearer Parameters - `id`path · stringrequiredBudget id. Responses - `200`Budget.objectschema`data`Budgetproperties`id`string (uuid)`scope_type`"organization" | "workspace" | "api_key"`scope_id`string`interval`"daily" | "weekly" | "monthly" | "lifetime"`limit`number`mode`"hard" | "soft"`include_byok`boolean`alert_thresholds`number[]`spent`number`remaining`number`used_percent`number`period_start`string (date-time)`period_end`string (date-time) | null`created_at`string (date-time) - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope patch`/management/budgets/{id}`Update a budgetbearer Parameters - `id`path · stringrequiredBudget id. Request body · BudgetWrite - `scope_type`"organization" | "workspace" | "api_key"Create only. - `scope_id`stringWorkspace id/slug or key id/hash (create only; omitted for organization scope). - `interval`"daily" | "weekly" | "monthly" | "lifetime"Create only. - `limit`number - `mode`"hard" | "soft" - `include_byok`boolean - `alert_thresholds`number[] Responses - `200`Updated.objectschema`data`Budgetproperties`id`string (uuid)`scope_type`"organization" | "workspace" | "api_key"`scope_id`string`interval`"daily" | "weekly" | "monthly" | "lifetime"`limit`number`mode`"hard" | "soft"`include_byok`boolean`alert_thresholds`number[]`spent`number`remaining`number`used_percent`number`period_start`string (date-time)`period_end`string (date-time) | null`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/byok`List byok credentialsbearer Responses - `200`ByokCredentials.objectschema`data`ByokCredential[] - `401`Missing or invalid API key.ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope post`/management/byok`Create a byok credentialbearer Request body · ByokCredentialWrite - `provider_id`string (uuid)Create only. - `label`string - `secret`stringCreate/rotate only; never returned. - `enabled`boolean - `allowed_key_hashes`string[] | nullRestrict to these inference key hashes (update only). Responses - `201`Created.objectschema`data`ByokCredentialproperties`id`string (uuid)`provider`objectproperties`id`string`slug`string`name`string`label`string`last4`string`enabled`boolean`status`string`allowed_key_ids`string (uuid)[] | nullInference keys allowed to use this credential; null = every key.`last_synced_at`string (date-time) | null`last_used_at`string (date-time) | null`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope delete`/management/byok/{id}`Delete a byok credentialbearer Parameters - `id`path · stringrequiredByokCredential id. Responses - `200`Deleted. - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/byok/{id}`Get a byok credentialbearer Parameters - `id`path · stringrequiredByokCredential id. Responses - `200`ByokCredential.objectschema`data`ByokCredentialproperties`id`string (uuid)`provider`objectproperties`id`string`slug`string`name`string`label`string`last4`string`enabled`boolean`status`string`allowed_key_ids`string (uuid)[] | nullInference keys allowed to use this credential; null = every key.`last_synced_at`string (date-time) | null`last_used_at`string (date-time) | null`created_at`string (date-time) - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope patch`/management/byok/{id}`Update a byok credentialbearer Parameters - `id`path · stringrequiredByokCredential id. Request body · ByokCredentialWrite - `provider_id`string (uuid)Create only. - `label`string - `secret`stringCreate/rotate only; never returned. - `enabled`boolean - `allowed_key_hashes`string[] | nullRestrict to these inference key hashes (update only). Responses - `200`Updated.objectschema`data`ByokCredentialproperties`id`string (uuid)`provider`objectproperties`id`string`slug`string`name`string`label`string`last4`string`enabled`boolean`status`string`allowed_key_ids`string (uuid)[] | nullInference keys allowed to use this credential; null = every key.`last_synced_at`string (date-time) | null`last_used_at`string (date-time) | null`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope post`/management/byok/{id}/rotate`Rotate a BYOK secretbearer Replaces the upstream secret in place; routing history, label and key restrictions are kept. Parameters - `id`path · stringrequired Request body · object - `secret`stringrequired Responses - `200`Rotated.objectschema`data`ByokCredentialproperties`id`string (uuid)`provider`objectproperties`id`string`slug`string`name`string`label`string`last4`string`enabled`boolean`status`string`allowed_key_ids`string (uuid)[] | nullInference keys allowed to use this credential; null = every key.`last_synced_at`string (date-time) | null`last_used_at`string (date-time) | null`created_at`string (date-time) get`/management/members`List organization members and pending invitationsbearer Responses - `200`Members.objectschema`data`Member[]`invitations`Invitation[] delete`/management/members/{userId}`Remove a memberbearer Parameters - `userId`path · stringrequired Responses - `200`Removed. patch`/management/members/{userId}`Change a member’s rolebearer Parameters - `userId`path · stringrequired Request body · object - `role`"owner" | "admin" | "member" | "billing"required Responses - `200`Updated. post`/management/members/invitations`Invite a member by emailbearer Request body · object - `email`string (email)required - `role`"admin" | "member" | "billing" Responses - `201`Invitation sent.objectschema`data`Invitationproperties`id`string (uuid)`email`string`role`string`expires_at`string (date-time) delete`/management/members/invitations/{id}`Revoke an invitationbearer Parameters - `id`path · stringrequired Responses - `200`Revoked. get`/management/notification-rules`List notification rulesbearer Responses - `200`NotificationRules.objectschema`data`NotificationRule[] - `401`Missing or invalid API key.ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope post`/management/notification-rules`Create a notification rulebearer Request body · NotificationRuleWrite - `kind`stringCreate only. - `workspace_id`string | nullCreate only. - `config`object - `channels`objectproperties`email`boolean`destination_ids`string (uuid)[] - `recipients`objectproperties`roles`string[]`user_ids`string[]`emails`string[] - `enabled`boolean Responses - `201`Created.objectschema`data`NotificationRuleproperties`id`string (uuid)`kind`"low_balance" | "budget_threshold" | "key_limit_threshold" | "model_availability" | "model_price_change" | "model_deprecation" | "auto_top_up_failed"`workspace_id`string (uuid) | null`config`object`channels`objectproperties`email`boolean`destination_ids`string (uuid)[]`recipients`objectproperties`roles`string[]`user_ids`string[]`emails`string (email)[]`enabled`boolean`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope delete`/management/notification-rules/{id}`Delete a notification rulebearer Parameters - `id`path · stringrequiredNotificationRule id. Responses - `200`Deleted. - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/notification-rules/{id}`Get a notification rulebearer Parameters - `id`path · stringrequiredNotificationRule id. Responses - `200`NotificationRule.objectschema`data`NotificationRuleproperties`id`string (uuid)`kind`"low_balance" | "budget_threshold" | "key_limit_threshold" | "model_availability" | "model_price_change" | "model_deprecation" | "auto_top_up_failed"`workspace_id`string (uuid) | null`config`object`channels`objectproperties`email`boolean`destination_ids`string (uuid)[]`recipients`objectproperties`roles`string[]`user_ids`string[]`emails`string (email)[]`enabled`boolean`created_at`string (date-time) - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope patch`/management/notification-rules/{id}`Update a notification rulebearer Parameters - `id`path · stringrequiredNotificationRule id. Request body · NotificationRuleWrite - `kind`stringCreate only. - `workspace_id`string | nullCreate only. - `config`object - `channels`objectproperties`email`boolean`destination_ids`string (uuid)[] - `recipients`objectproperties`roles`string[]`user_ids`string[]`emails`string[] - `enabled`boolean Responses - `200`Updated.objectschema`data`NotificationRuleproperties`id`string (uuid)`kind`"low_balance" | "budget_threshold" | "key_limit_threshold" | "model_availability" | "model_price_change" | "model_deprecation" | "auto_top_up_failed"`workspace_id`string (uuid) | null`config`object`channels`objectproperties`email`boolean`destination_ids`string (uuid)[]`recipients`objectproperties`roles`string[]`user_ids`string[]`emails`string (email)[]`enabled`boolean`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/policies`List policiesbearer Responses - `200`Policies.objectschema`data`Policy[] - `401`Missing or invalid API key.ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope post`/management/policies`Create a policybearer Request body · PolicyWrite - `name`stringrequired - `description`string | null - `workspace_id`string | nullCreate only. - `rules`PolicyRulesrequiredEvery section is optional; an empty rule set allows everything.properties`models`objectproperties`mode`"allow_all_except" | "allow_only"required`patterns`string[]requiredModel ids, `vendor/*` or `*`.`vendors`objectproperties`mode`"allow_all_except" | "allow_only"required`slugs`string[]required`limits`objectproperties`maxOutputTokens`integer`maxPromptTokens`integer`maxCostUsdPerRequest`number`promptInjection`objectproperties`action`"block" | "flag" | "redact"required`patterns`string[]`allowlist`string[]`sensitiveInfo`objectproperties`action`"block" | "flag" | "redact"required`detectors`"email" | "phone" | "card" | "ip" | "secret" | "iban" | "ssn"[]required`customPatterns`string[]`direction`"input" | "output" | "both" - `enabled`boolean - `assignments`object[]Create only.propertiesarray of object`target_type`"organization" | "workspace" | "api_key" | "member"required`target_id`stringrequiredWorkspace id/slug, key id/hash, member user id/email. Responses - `201`Created.objectschema`data`Policyproperties`id`string (uuid)`name`string`description`string | null`workspace_id`string (uuid) | null`rules`PolicyRulesEvery section is optional; an empty rule set allows everything.properties`models`objectproperties`mode`"allow_all_except" | "allow_only"required`patterns`string[]requiredModel ids, `vendor/*` or `*`.`vendors`objectproperties`mode`"allow_all_except" | "allow_only"required`slugs`string[]required`limits`objectproperties`maxOutputTokens`integer`maxPromptTokens`integer`maxCostUsdPerRequest`number`promptInjection`objectproperties`action`"block" | "flag" | "redact"required`patterns`string[]`allowlist`string[]`sensitiveInfo`objectproperties`action`"block" | "flag" | "redact"required`detectors`"email" | "phone" | "card" | "ip" | "secret" | "iban" | "ssn"[]required`customPatterns`string[]`direction`"input" | "output" | "both"`enabled`boolean`assignments`PolicyAssignment[]`created_at`string (date-time)`updated_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope delete`/management/policies/{id}`Delete a policybearer Parameters - `id`path · stringrequiredPolicy id. Responses - `200`Deleted. - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/policies/{id}`Get a policybearer Parameters - `id`path · stringrequiredPolicy id. Responses - `200`Policy.objectschema`data`Policyproperties`id`string (uuid)`name`string`description`string | null`workspace_id`string (uuid) | null`rules`PolicyRulesEvery section is optional; an empty rule set allows everything.properties`models`objectproperties`mode`"allow_all_except" | "allow_only"required`patterns`string[]requiredModel ids, `vendor/*` or `*`.`vendors`objectproperties`mode`"allow_all_except" | "allow_only"required`slugs`string[]required`limits`objectproperties`maxOutputTokens`integer`maxPromptTokens`integer`maxCostUsdPerRequest`number`promptInjection`objectproperties`action`"block" | "flag" | "redact"required`patterns`string[]`allowlist`string[]`sensitiveInfo`objectproperties`action`"block" | "flag" | "redact"required`detectors`"email" | "phone" | "card" | "ip" | "secret" | "iban" | "ssn"[]required`customPatterns`string[]`direction`"input" | "output" | "both"`enabled`boolean`assignments`PolicyAssignment[]`created_at`string (date-time)`updated_at`string (date-time) - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope patch`/management/policies/{id}`Update a policybearer Parameters - `id`path · stringrequiredPolicy id. Request body · PolicyWrite - `name`stringrequired - `description`string | null - `workspace_id`string | nullCreate only. - `rules`PolicyRulesrequiredEvery section is optional; an empty rule set allows everything.properties`models`objectproperties`mode`"allow_all_except" | "allow_only"required`patterns`string[]requiredModel ids, `vendor/*` or `*`.`vendors`objectproperties`mode`"allow_all_except" | "allow_only"required`slugs`string[]required`limits`objectproperties`maxOutputTokens`integer`maxPromptTokens`integer`maxCostUsdPerRequest`number`promptInjection`objectproperties`action`"block" | "flag" | "redact"required`patterns`string[]`allowlist`string[]`sensitiveInfo`objectproperties`action`"block" | "flag" | "redact"required`detectors`"email" | "phone" | "card" | "ip" | "secret" | "iban" | "ssn"[]required`customPatterns`string[]`direction`"input" | "output" | "both" - `enabled`boolean - `assignments`object[]Create only.propertiesarray of object`target_type`"organization" | "workspace" | "api_key" | "member"required`target_id`stringrequiredWorkspace id/slug, key id/hash, member user id/email. Responses - `200`Updated.objectschema`data`Policyproperties`id`string (uuid)`name`string`description`string | null`workspace_id`string (uuid) | null`rules`PolicyRulesEvery section is optional; an empty rule set allows everything.properties`models`objectproperties`mode`"allow_all_except" | "allow_only"required`patterns`string[]requiredModel ids, `vendor/*` or `*`.`vendors`objectproperties`mode`"allow_all_except" | "allow_only"required`slugs`string[]required`limits`objectproperties`maxOutputTokens`integer`maxPromptTokens`integer`maxCostUsdPerRequest`number`promptInjection`objectproperties`action`"block" | "flag" | "redact"required`patterns`string[]`allowlist`string[]`sensitiveInfo`objectproperties`action`"block" | "flag" | "redact"required`detectors`"email" | "phone" | "card" | "ip" | "secret" | "iban" | "ssn"[]required`customPatterns`string[]`direction`"input" | "output" | "both"`enabled`boolean`assignments`PolicyAssignment[]`created_at`string (date-time)`updated_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope post`/management/policies/{id}/assignments`Assign a policybearer Parameters - `id`path · stringrequired Request body · object - `target_type`"organization" | "workspace" | "api_key" | "member"required - `target_id`stringrequired Responses - `201`Assigned.objectschema`data`PolicyAssignmentproperties`id`string (uuid)`target_type`"organization" | "workspace" | "api_key" | "member"`target_id`string delete`/management/policies/{id}/assignments/{assignmentId}`Remove a policy assignmentbearer Parameters - `id`path · stringrequired - `assignmentId`path · stringrequired Responses - `200`Removed. post`/management/policies/dry-run`Dry-run a policy against recent trafficbearer Replays the model, vendor and limit rules over the last N days of real requests (no prompts are stored, so text rules are reported as not simulated). Request body · PolicyDryRun - `rules`PolicyRulesrequiredEvery section is optional; an empty rule set allows everything.properties`models`objectproperties`mode`"allow_all_except" | "allow_only"required`patterns`string[]requiredModel ids, `vendor/*` or `*`.`vendors`objectproperties`mode`"allow_all_except" | "allow_only"required`slugs`string[]required`limits`objectproperties`maxOutputTokens`integer`maxPromptTokens`integer`maxCostUsdPerRequest`number`promptInjection`objectproperties`action`"block" | "flag" | "redact"required`patterns`string[]`allowlist`string[]`sensitiveInfo`objectproperties`action`"block" | "flag" | "redact"required`detectors`"email" | "phone" | "card" | "ip" | "secret" | "iban" | "ssn"[]required`customPatterns`string[]`direction`"input" | "output" | "both" - `workspace_id`string | null - `api_key_ids`string (uuid)[] - `days`integer Responses - `200`What the policy would have blocked.objectschema`data`PolicyDryRunResultproperties`days`integer`requests`integer`blocked`integer`byRule`object`spendBlockedUsd`number`samples`object[]propertiesarray of object`id`string`model`string`rule`string`at`string (date-time)`notSimulated`string[]Text rules cannot be replayed because prompts are not stored. get`/management/policies/events`List policy eventsbearer Parameters - `days`query · integer - `kind`query · "blocked" | "flagged" | "redacted" - `limit`query · integer Responses - `200`Events, newest first.objectschema`data`PolicyEvent[] get`/management/presets`List presetsbearer Responses - `200`Presets.objectschema`data`Preset[] - `401`Missing or invalid API key.ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope post`/management/presets`Create a presetbearer Request body · PresetWrite - `slug`stringCreate only. - `name`string - `description`string | null - `workspace_id`string | null - `config`PresetConfigproperties`systemPrompt`string`models`string[]Primary model followed by up to three fallbacks.`provider`objectRouting preferences (same shape as the request `provider` block).`parameters`objectDefault sampling parameters; request fields win.`cache`objectproperties`enabled`booleanrequired`ttlSeconds`integer`transforms`"middle-out"[]`plugins`object[]Server-side plugins. `web`: search grounding with cited sources (fee per result, itemised on the receipt; also enabled by the `:online` variant). `file-parser`: PDF text extraction for models without native file input. `server-tools`: safe built-in tools the model can call (`datetime`, `search_models`) in extra rounds. `response-healing`: JSON repair.propertiesarray of object`id`"web" | "file-parser" | "server-tools" | "response-healing"required`max_results`integer`web`: results to retrieve (default 5).`search_prompt`string`web`: query override (defaults to the last user message).`tools`"datetime" | "search_models"[]`server-tools`: which built-ins to expose (default all).`max_rounds`integer`server-tools`: maximum tool rounds (default 3). - `note`string | null - `current_version`integerUpdate only: roll back or forward to an existing version. Responses - `201`Created.objectschema`data`Presetproperties`id`string (uuid)`slug`string`name`string`description`string | null`workspace_id`string (uuid) | null`current_version`integer`reference`stringUse as `model`, e.g. `@preset/support-bot`.`archived_at`string (date-time) | null`created_at`string (date-time)`updated_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope delete`/management/presets/{ref}`Delete a presetbearer Parameters - `ref`path · stringrequiredPreset id or slug. Responses - `200`Deleted. - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/presets/{ref}`Get a presetbearer Parameters - `ref`path · stringrequiredPreset id or slug. Responses - `200`Preset.objectschema`data`Presetproperties`id`string (uuid)`slug`string`name`string`description`string | null`workspace_id`string (uuid) | null`current_version`integer`reference`stringUse as `model`, e.g. `@preset/support-bot`.`archived_at`string (date-time) | null`created_at`string (date-time)`updated_at`string (date-time) - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope patch`/management/presets/{ref}`Update a presetbearer Parameters - `ref`path · stringrequiredPreset id or slug. Request body · PresetWrite - `slug`stringCreate only. - `name`string - `description`string | null - `workspace_id`string | null - `config`PresetConfigproperties`systemPrompt`string`models`string[]Primary model followed by up to three fallbacks.`provider`objectRouting preferences (same shape as the request `provider` block).`parameters`objectDefault sampling parameters; request fields win.`cache`objectproperties`enabled`booleanrequired`ttlSeconds`integer`transforms`"middle-out"[]`plugins`object[]Server-side plugins. `web`: search grounding with cited sources (fee per result, itemised on the receipt; also enabled by the `:online` variant). `file-parser`: PDF text extraction for models without native file input. `server-tools`: safe built-in tools the model can call (`datetime`, `search_models`) in extra rounds. `response-healing`: JSON repair.propertiesarray of object`id`"web" | "file-parser" | "server-tools" | "response-healing"required`max_results`integer`web`: results to retrieve (default 5).`search_prompt`string`web`: query override (defaults to the last user message).`tools`"datetime" | "search_models"[]`server-tools`: which built-ins to expose (default all).`max_rounds`integer`server-tools`: maximum tool rounds (default 3). - `note`string | null - `current_version`integerUpdate only: roll back or forward to an existing version. Responses - `200`Updated.objectschema`data`Presetproperties`id`string (uuid)`slug`string`name`string`description`string | null`workspace_id`string (uuid) | null`current_version`integer`reference`stringUse as `model`, e.g. `@preset/support-bot`.`archived_at`string (date-time) | null`created_at`string (date-time)`updated_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope post`/management/presets/{ref}/versions`Save a new preset versionbearer Published immediately unless `publish` is false; older versions stay addressable as `@preset/slug@N`. Parameters - `ref`path · stringrequiredPreset id or slug. Request body · object - `config`PresetConfigrequiredproperties`systemPrompt`string`models`string[]Primary model followed by up to three fallbacks.`provider`objectRouting preferences (same shape as the request `provider` block).`parameters`objectDefault sampling parameters; request fields win.`cache`objectproperties`enabled`booleanrequired`ttlSeconds`integer`transforms`"middle-out"[]`plugins`object[]Server-side plugins. `web`: search grounding with cited sources (fee per result, itemised on the receipt; also enabled by the `:online` variant). `file-parser`: PDF text extraction for models without native file input. `server-tools`: safe built-in tools the model can call (`datetime`, `search_models`) in extra rounds. `response-healing`: JSON repair.propertiesarray of object`id`"web" | "file-parser" | "server-tools" | "response-healing"required`max_results`integer`web`: results to retrieve (default 5).`search_prompt`string`web`: query override (defaults to the last user message).`tools`"datetime" | "search_models"[]`server-tools`: which built-ins to expose (default all).`max_rounds`integer`server-tools`: maximum tool rounds (default 3). - `note`string | null - `publish`boolean Responses - `201`Version saved.objectschema`data`Presetproperties`id`string (uuid)`slug`string`name`string`description`string | null`workspace_id`string (uuid) | null`current_version`integer`reference`stringUse as `model`, e.g. `@preset/support-bot`.`archived_at`string (date-time) | null`created_at`string (date-time)`updated_at`string (date-time)`version`PresetVersionproperties`version`integer`config`PresetConfigproperties`systemPrompt`string`models`string[]Primary model followed by up to three fallbacks.`provider`objectRouting preferences (same shape as the request `provider` block).`parameters`objectDefault sampling parameters; request fields win.`cache`objectproperties`enabled`booleanrequired`ttlSeconds`integer`transforms`"middle-out"[]`plugins`object[]Server-side plugins. `web`: search grounding with cited sources (fee per result, itemised on the receipt; also enabled by the `:online` variant). `file-parser`: PDF text extraction for models without native file input. `server-tools`: safe built-in tools the model can call (`datetime`, `search_models`) in extra rounds. `response-healing`: JSON repair.propertiesarray of object5 properties`note`string | null`created_at`string (date-time) post`/management/presets/from-request`Derive a preset config from a request bodybearer Request body · object - `request`objectrequired Responses - `200`Config (not persisted).objectschema`data`objectproperties`config`PresetConfigproperties`systemPrompt`string`models`string[]Primary model followed by up to three fallbacks.`provider`objectRouting preferences (same shape as the request `provider` block).`parameters`objectDefault sampling parameters; request fields win.`cache`objectproperties`enabled`booleanrequired`ttlSeconds`integer`transforms`"middle-out"[]`plugins`object[]Server-side plugins. `web`: search grounding with cited sources (fee per result, itemised on the receipt; also enabled by the `:online` variant). `file-parser`: PDF text extraction for models without native file input. `server-tools`: safe built-in tools the model can call (`datetime`, `search_models`) in extra rounds. `response-healing`: JSON repair.propertiesarray of object5 properties get`/management/workspaces`List workspacesbearer Responses - `200`Workspaces.objectschema`data`Workspace[] - `401`Missing or invalid API key.ErrorEnvelope - `429`Rate limited. Honour `Retry-After` and `X-RateLimit-*`.ErrorEnvelope post`/management/workspaces`Create a workspacebearer Request body · WorkspaceWrite - `name`stringrequired - `slug`stringCreate only. - `description`string | null - `environment`"production" | "staging" | "development" | "other" Responses - `201`Created.objectschema`data`Workspaceproperties`id`string (uuid)`slug`string`name`string`description`string | null`is_default`boolean`environment`"production" | "staging" | "development" | "other" | null`archived_at`string (date-time) | null`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `401`Missing or invalid API key.ErrorEnvelope delete`/management/workspaces/{id}`Delete a workspacebearer Parameters - `id`path · stringrequiredWorkspace id or slug. Responses - `200`Deleted. - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/workspaces/{id}`Get a workspacebearer Parameters - `id`path · stringrequiredWorkspace id or slug. Responses - `200`Workspace.objectschema`data`Workspaceproperties`id`string (uuid)`slug`string`name`string`description`string | null`is_default`boolean`environment`"production" | "staging" | "development" | "other" | null`archived_at`string (date-time) | null`created_at`string (date-time) - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope patch`/management/workspaces/{id}`Update a workspacebearer Parameters - `id`path · stringrequiredWorkspace id or slug. Request body · WorkspaceWrite - `name`stringrequired - `slug`stringCreate only. - `description`string | null - `environment`"production" | "staging" | "development" | "other" Responses - `200`Updated.objectschema`data`Workspaceproperties`id`string (uuid)`slug`string`name`string`description`string | null`is_default`boolean`environment`"production" | "staging" | "development" | "other" | null`archived_at`string (date-time) | null`created_at`string (date-time) - `400`Invalid request (including `context_length_exceeded` for prompts the model cannot fit).ErrorEnvelope - `404`Model or resource not found — or your provider preferences left no endpoint (`no_endpoints_within_max_price`, `no_endpoints_supporting_parameters`, `no_endpoints_matching_provider_preferences`).ErrorEnvelope get`/management/workspaces/{id}/members`List workspace membersbearer Parameters - `id`path · stringrequired Responses - `200`Members (implicit for the default workspace). post`/management/workspaces/{id}/members`Add a workspace memberbearer Parameters - `id`path · stringrequired Request body · object - `user_id`stringrequiredMember user id or email. - `role`"admin" | "member" Responses - `201`Added. delete`/management/workspaces/{id}/members/{userId}`Remove a workspace memberbearer Parameters - `id`path · stringrequired - `userId`path · stringrequired Responses - `200`Removed. --- Source: https://elevenrouter.com/docs/reference # Errors Errors use the OpenAI envelope so existing SDKs surface them correctly. [View as Markdown](https://elevenrouter.com/docs/md/errors) ```json { "error": { "message": "Insufficient credits. Your balance is empty; add credits to continue.", "type": "insufficient_credits_error", "code": "insufficient_credits", "param": null, "metadata": { "request_id": "req_..." } } } ``` ## Status codes and types - `400 invalid_request_error` *(client)*: Malformed body, unsupported parameter, context length exceeded (code context_length_exceeded) or an upstream validation error passed through. - `401 authentication_error` *(client)*: Missing, invalid, disabled or expired API key. - `402 insufficient_credits_error` *(client)*: Organization balance is empty, or the key reached its spend limit (code key_limit_exceeded). - `403 permission_error` *(client)*: Model not allowed for this key, or the account is suspended. - `404 not_found_error` *(client)*: Unknown model (code model_not_found), unknown generation id, or your own provider preferences left no endpoint: no_endpoints_within_max_price, no_endpoints_supporting_parameters, no_endpoints_matching_provider_preferences. Each message says which preference to relax. - `429 rate_limit_error` *(client)*: Per-key rate limit exceeded. Honour the retry-after header. - `502 provider_error` *(upstream)*: All eligible endpoints failed with an upstream error. metadata.provider_name names the model vendor of the last endpoint tried. - `503 model_unavailable_error / overloaded_error` *(upstream)*: No endpoint can serve the model right now, or providers are rate limited or overloaded. Retry with backoff. - `504 timeout_error` *(upstream)*: The upstream provider did not respond within the request timeout. - `500 server_error` *(server)*: Unexpected error. Include the request_id when contacting support. ## Request ids Every response carries `x-request-id`; completions also carry `x-er-generation-id`. Both appear in the dashboard and let support trace a request end to end. --- Source: https://elevenrouter.com/docs/errors