Build with router
Use OpenAI-compatible APIs, Anthropic-compatible Messages, or your favorite AI app with one model catalog.
Quick start#
Create an account, fund its wallet and create an API key. Use the deployment origin plus /v1 for OpenAI clients, and the origin without /v1 for Anthropic clients. Send Authorization: Bearer YOUR_API_KEY or X-Api-Key, and keep the secret on your server. New keys default to inference and usage:read; account management needs separate permissions.
- Create an account and open your workspace.
- Make sure your wallet has enough balance for the request.
- Create an API key. Copy the full secret once and store it securely.
- Set your SDK's base URL to router and use an exact model ID from the catalog.
- Send a request, then review its usage and settled cost in your workspace.
Base URLs
https://your-router-domain/v1https://your-router-domainAnthropic SDKs append /v1/messages themselves. Use the base URL without that path.
For the shell examples below, set ROUTER_BASE_URL to this site's origin without /v1. Use ROUTER_API_KEYfor inference and ROUTER_MANAGEMENT_KEY for a key with the required account permissions.
Authentication
Send Authorization: Bearer YOUR_API_KEY. The Messages endpoint also accepts X-Api-Key. Keep keys on your server or in local environment variables.
API key permissions
New keys default to inference and usage:read. Select additional permissions when creating a key in the workspace. A valid key without the permission required by an endpoint returns 403.
| Field | Description |
|---|---|
inference | Chat Completions, Responses, Messages, model/supply reads, and POST /v1/feedback. |
usage:read | GET /v1/usage, /v1/usage/requests, /v1/usage/daily, /v1/models/compare and /v1/pricing/changes. |
account:read | GET /v1/account, /v1/account/balance, /v1/account/usage, /v1/account/savings, /v1/keys, /v1/techniques and /v1/experiments, including experiment detail. |
account:write | Create/revoke keys through /v1/keys and PATCH /v1/techniques/{id}. Policy editing requires a browser session. |
Legacy text completions
POST /v1/completions accepts one string prompt or an array containing one string and returns choices[].text. Streaming and echo are supported. It uses the same routing and settlement as Chat Completions. Batched or token-ID prompts, nonempty suffix insertion, logprobs, best_of or n other than 1, and tools are unsupported.
Chat completion
One language setting updates the request examples on this page.
curl 'https://your-router-domain/v1/chat/completions' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{
"role": "user",
"content": "Hello!"
}
],
"max_tokens": 128
}'Give each key a clear boundary#
Create and edit API key policies in the signed-in workspace. Empty model and IP lists mean unrestricted; null numeric limits or expiry remove those limits. Model allowlists, client IP/CIDR, expiry, UTC-minute rate, UTC-day quota, concurrency and monthly spending limits are enforced by the gateway. List, update and revoke return only the key prefix; the full secret is shown once at creation. Account and balance reads require account:read. API keys default to prompt_cache_mode passthrough; on/off/passthrough are editable advanced settings. x-ci-prompt-cache overrides the key. For Claude models, on needs a compatible native Messages route (currently claude-opus-4.8 only), and off keeps client cache_control while disabling affinity. x-ci-prompt-cache-scope selects session/user/org; the session label is printable ASCII of 1–256 characters. The x-ci-prompt-cache-affinity new/hit/stale/miss header is a five-minute route preference, not proof of supplier cache reads or guaranteed savings.
Open API keys to create a key or edit its policy. Advanced limits are optional and enforced by the gateway. Empty model/IP lists allow every model/source. Blank numeric limits and expiry mean unlimited/no expiry.
| Field | Type | Description |
|---|---|---|
allowed_models | string[] | Up to 100 model IDs or aliases. [] means unrestricted; null is invalid. |
allowed_ip_cidrs | string[] | Up to 50 IPv4 or IPv6 addresses/CIDRs. [] allows any source IP. Restricted keys fail with 403 when a trusted Cloudflare client IP is unavailable. |
expires_at | ISO timestamp | null | Future expiry as an absolute timestamp. null removes expiry. The dashboard displays local time. |
rate_limit_per_minute | integer | null | 1–100,000 accepted logical inference requests per fixed UTC minute. |
daily_request_limit | integer | null | 1–1,000,000,000 accepted logical inference requests per UTC day. |
concurrency_limit | integer | null | 1–10,000 in-flight logical inference requests. |
monthly_spend_limit_usd | number | null | $0–$1,000,000, with up to 9 decimal places. null is unlimited; $0 blocks positive-cost inference. |
Every accepted logical inference counts once, including cache hits and failed requests. Both the requested model and the final experiment/technique model must satisfy the allowlist. Budget checks include in-flight reservations and can reject a request whose estimated maximum charge exceeds the remaining allowance. Monthly spending belongs to the UTC month when the request is accepted.
Rate, daily, concurrency and key monthly-budget limits return 429; insufficient wallet balance returns 402. Expired or revoked keys return 401. Scope, model, IP and management permission failures return 403.
Policy edits constrain new admissions. Already-reserved requests can complete under their original authorization. A policy change between authentication and reservation rejects the request with 403; retry under the updated policy.
Read account and balance
These endpoints require account:read and return current account data and wallet amounts in USD. Available balance excludes in-flight reservations. Active key count excludes revoked and expired keys. A workspace key uses its fixed organization_id; a signed-in session selects a workspace with the same query parameter. Omit it for personal account data. Workspace balances show the owner-funded shared wallet, while email and platform role identify the responsible member. Owner card and automatic-recharge settings stay private; workspace reads return false or null for those settings.
curl 'https://your-router-domain/v1/account' \
-H 'Authorization: Bearer YOUR_API_KEY'curl 'https://your-router-domain/v1/account/balance' \
-H 'Authorization: Bearer YOUR_API_KEY'List and create keys through the API
curl 'https://your-router-domain/v1/keys' \
-H 'Authorization: Bearer YOUR_API_KEY'curl "$ROUTER_BASE_URL/v1/keys" \
-H "Authorization: Bearer $ROUTER_MANAGEMENT_KEY" \
-H "Content-Type: application/json" \
-d '{"name":"Application inference","scopes":["inference","usage:read"],"allowed_models":["deepseek-v4-flash"],"rate_limit_per_minute":60,"monthly_spend_limit_usd":25}'Workspace requests spend the owner's shared wallet. Each member's UTC monthly allowance includes reservations across all their workspace keys, in addition to each key's own limits. New invitations default to $0; the owner must grant a spending allowance. Removal or a tighter limit blocks new admissions; requests already reserved can finish under their original authorization. Usage and account reads stay within the selected workspace; personal history, saved-card settings, experiments, uploads and techniques are not inherited.
The full secret appears only in the creation response. List, update, and revoke responses contain its prefix. Keep the secret on your server; neither the full key nor its hash can be read back.
API reference#
The request builder runs Chat Completions, Responses or Messages requests with your own API key. Its cURL, Python and JavaScript examples share the selected parameters. Running inference can spend wallet balance. GET /v1/docs lists these section overviews; add q to search their titles, keywords and text. A valid API key is required, with no additional scope.
The request builder uses the same public endpoints as your application. Your secret stays in this page's memory; running a request can spend wallet balance.
Search these documentation overviews
GET /v1/docs returns the section directory without bodies. Add q to return matching overview paragraphs, best match first. limit is 1–10, defaults to 4, and is ignored without a nonblank query. Supply q once, with at most 500 characters. The linked sections contain the detailed field tables and interactive examples. This endpoint needs a valid Bearer or X-Api-Key credential, with no additional scope, and does not call a model or spend wallet balance.
curl 'https://your-router-domain/v1/docs?q=api%20keys&limit=4' \
-H 'Authorization: Bearer YOUR_API_KEY'Live response
Kept in this page only. Never stored in your browser.curl 'https://your-router-domain/v1/chat/completions' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "claude-fable-5",
"messages": [
{
"role": "user",
"content": "A farmer has 17 sheep. All but 9 run away. How many are left? Show your reasoning."
}
],
"max_tokens": 128,
"temperature": 0.7,
"stream": false,
"ranking": "balance"
}'See the full endpoint reference for request fields, response formats and error codes.
Models and pricing#
GET /public/models and /public/models/{model_id} need no API key. The list returns a models array; detail accepts exact case-sensitive IDs and listed aliases, including slashes. These compatibility endpoints use 0.00 for an unknown discount, while null reference prices retain the unknown distinction; the UI /api/public/models endpoint keeps discount null. Use only visible, price-eligible models; current capacity is checked at admission. Token prices are USD per million input, output, cache-read or cache-write tokens. GET /v1/models/compare estimates a workload without inference. GET /v1/pricing/changes uses an inclusive since timestamp and a version-frozen next_cursor; both reads require usage:read. Catalog observations are not continuous supplier price checks.
Use the exact model ID in the model field. The live catalog lists currently configured models and their prices. A single model can have several underlying routes; router automatically chooses the serving route.
curl 'https://your-router-domain/v1/models' \
-H 'Authorization: Bearer YOUR_API_KEY'Use GET /v1/models/compare to estimate a token workload across one to ten models without calling an upstream. Pass comma-separated model IDs, prompt_tokens, completion_tokens and requests. The result includes customer cost estimates and anonymous supplier rates. Actual route and usage determine the bill; unknown list prices and savings remain null.
GET /v1/pricing/changes?since=2026-09-06T00%3A00%3A00Z returns the latest change per allowed model since an inclusive timestamp. Follow next_cursor with the same since and credential context to keep the first page’s catalog version. Both endpoints require usage:read. They describe the configured catalog: pricing_checked_at is null, and pricing_observed_at identifies the observation time. See the price change contract for fields and pagination.
Token rates are in US dollars per million tokens. Input, output, cache reads and cache writes have separate rates. Catalog prices describe current supply; the final charge follows the route that successfully serves your request. When a verified model-maker reference exists, the default ceiling is the list price. Without one, ordinary requests can use configured retail rates and discount/list-price savings remain unknown. Explicit min_discount_percent, including 0, still requires a verified reference and otherwise returns 400 list_price_unknown.
| Field | Description |
|---|---|
id | Exact public model identifier. |
aliases | Alternative vendor-qualified identifiers accepted for the same model. |
pricing.input_per_million / pricing.output_per_million | Current input and output catalog rates in USD. |
pricing.cache_read_input_per_million / pricing.cache_write_input_per_million | Separate input-cache rates. |
context_length / max_output_tokens | Context capacity and maximum generation length. |
capabilities.streaming / capabilities.reasoning | Capabilities of the published model. |
Response feedback#
POST /v1/feedback accepts your own successful request_id, an integer score from 1 to 5 and an optional comment. Find the ID in the x-ci-request-id response header. Resubmitting replaces the previous score and comment. Feedback does not require an experiment, and does not imply automatic quality judging or statistical confidence.
Attach a score to a completed request using its x-ci-request-id response header. Sign in with the account that made the request to save feedback.
curl 'https://your-router-domain/v1/feedback' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"request_id": "",
"score": 5,
"comment": "Accurate answer"
}'Scores are integers from 1 to 5 and accept only your own successful requests. Resubmitting replaces the previous score and comment. Review settled spend, request status, tokens, and feedback together. Average cost divides total spend by all recorded requests; no samples means no average. Savings and statistical confidence are not inferred.
Parameters#
POST /v1/completions accepts a single string prompt (or one-string array), with streaming and echo, and returns choices[].text. Chat Completions uses messages with roles and content. Set max_tokens or max_completion_tokens to bound output, and stream for server-sent events. Tools, tool_choice, response_format, sampling and reasoning options depend on the chosen model and route. Router normalizes supported protocol differences; it cannot add a capability the serving model does not have.
Chat requests use the OpenAI Chat Completions shape. Supported parameters depend on the exact model and serving route. Router handles known format differences before sending your request.
| Field | Type | Description |
|---|---|---|
messages | array | Conversation messages with role and content. |
max_tokens / max_completion_tokens | integer | An explicit output-token budget. Set one to bound generation. |
temperature / top_p | number | Sampling settings, when supported by the model. |
tools / tool_choice | array / object | Client-side tool definitions and tool selection. |
response_format | object | JSON object or schema request for models with matching support. |
reasoning / reasoning_effort | object / string | Reasoning configuration mapped to the serving model. |
stream | boolean | Receive protocol-specific server-sent events. |
A compatibility layer cannot add an ability the model does not have. Validate the request shape you use in production, especially tools combined with reasoning or structured output.
Direct image input
Models with capabilities.vision: true in GET /v1/models can accept images in ordinary user messages. The model detail page marks each anonymous route as Text + images or Text only. Image requests use compatible routes at their displayed prices; the gateway never falls back to a cheaper text-only route.
Chat uses image_url content parts; Responses uses input_image; Messages uses image with a URL or base64 source. Supply an HTTP(S) URL without credentials, or canonical base64 for PNG, JPEG, WebP or GIF. The complete JSON request, including base64, must fit within 2 MiB. File IDs and temporary uploads are not provided. See the image input shapes and limits.
Price ceiling#
min_discount_percent is a number from 0 through 99.99. It constrains input and output rates separately against the published model-maker reference price. A request with a minimum discount fails when no eligible route meets both ceilings. GET /v1/models/supply reports candidate counts at current prices; it does not guarantee capacity, health or a successful response.
Add min_discount_percent to set the minimum discount your request accepts. It is a number from 0 to 99.99, checked against router's published model-maker reference price.
curl 'https://your-router-domain/v1/chat/completions' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{
"role": "user",
"content": "Hello!"
}
],
"min_discount_percent": 40,
"max_tokens": 128
}'A route must meet the ceiling on both input and output prices. Router removes this field before forwarding the request. If no route qualifies, the request fails instead of silently selecting a more expensive route.
| Field | Description |
|---|---|
400 · invalid_min_discount | The value is not a number from 0 through 99.99. |
400 · list_price_unknown | No verified comparison price is available for this model. |
503 · min_discount_unavailable | No current route satisfies both price ceilings. Lower the required discount or try again later. |
Check available supply
curl 'https://your-router-domain/v1/models/supply?model=deepseek-v4-flash&min_discount_percent=40' \
-H 'Authorization: Bearer YOUR_API_KEY'The candidate count describes routes priced below the ceiling at that moment. It does not guarantee health, capacity or a successful response.
Zero data retention#
Enable account zero data retention in /dashboard/data-protection, or send zdr: true for one request. Request false does not lift the account restriction. No verified ZDR supply is configured, so effective ZDR returns 503 zdr_capacity_unavailable. Enabling clears response cache and blocks new uploads and image reads, scheduling existing uploads for deletion; Prompt Studio runs are cancelled and their saved prompts, answers and results are cleared. Billing records, separate experiment configurations and pre-existing browser drafts remain. With the restriction off, POST /v1/uploads stores one PNG/JPEG/WebP/GIF up to 10 MiB for one hour; earlier uploads retain their recorded expiry. Uploading requires inference scope or a same-origin session. Reference the returned id using Responses input_image.file_id, Messages image.source.file_id, or the Router-specific Chat image_url.url router-upload:// prefix. Quotas are 32 stored files/64 MiB per account, including pending cleanup, and rolling limits of 20 admitted uploads per minute/120 per day. See /api-reference#uploads for the exact fields and deletion limits. Normal availability does not prove supplier zero retention.
The zdr: true field restricts a request to verified zero-retention supply. Routes must have verified coverage before they can serve a request that requires ZDR.
503 zdr_capacity_unavailable. A model's normal availability is not a zero-retention promise.Speed, discount, balance#
ranking chooses the order of eligible routes for the same model. balance is the default and combines recent speed and discount; discount starts with the lowest estimated cost; speed prefers recent speed with cost as a tie-break. Routes with too little history receive a neutral score. Ranking does not override price ceilings, privacy requirements or model capabilities.
Use ranking to choose how eligible routes are ordered. The model stays the same; you do not need to select or configure an underlying provider.
| Field | Description |
|---|---|
balance | The default. Combines recent speed and discount information. |
discount | Start with the lowest estimated cost among eligible routes. |
speed | Prefer recent speed; cost breaks ties. Routes with too little history receive a neutral score. |
curl 'https://your-router-domain/v1/chat/completions' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-v4-flash",
"messages": [
{
"role": "user",
"content": "Hello!"
}
],
"ranking": "speed",
"max_tokens": 128
}'Ranking does not override a price ceiling, a privacy requirement, or a model's capabilities. The route that serves the request determines its settled rate.
Responses API#
POST /v1/responses supports Responses-compatible clients. Set store: false and include the required conversation input with each request. Streaming, function calls and supported local tools are available. Stored responses, previous_response_id, conversations, background mode and provider-hosted web or file search are not supported.
Use POST /v1/responses for Responses-compatible clients such as Codex. Set store: false and include the conversation input needed for each request.
curl 'https://your-router-domain/v1/responses' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-v4-flash",
"input": "Hello!",
"store": false,
"stream": true,
"max_output_tokens": 128
}'previous_response_id, conversations, background mode, and provider-hosted web or file search are not part of this endpoint.Anthropic Messages#
POST /v1/messages accepts Anthropic Messages and returns the corresponding response shape. Claude Code executes client-side tools locally and sends tool_result blocks back. Streams use message_start, content_block_delta, message_delta and message_stop. Anthropic-hosted tools, Files and Message Batches are not compatibility targets. Receiving opaque native output does not prove that signed or encrypted history can be replayed. POST /v1/messages/count_tokens returns a free, local approximate input_tokens count; x-ci-token-count-estimated is true and x-ci-token-count-method is unicode-heuristic-v1. It requires inference permission and respects the model allowlist; it is not a supplier tokenizer or a context-fit guarantee.
POST /v1/messages accepts the Anthropic Messages format and returns the corresponding response shape. Claude Code executes client-side tools locally and sends their results back to the endpoint.
curl 'https://your-router-domain/v1/messages' \
-H 'Authorization: Bearer YOUR_API_KEY' \
-H 'Content-Type: application/json' \
-d '{
"model": "deepseek-v4-flash",
"max_tokens": 1024,
"messages": [
{
"role": "user",
"content": "Hello!"
}
]
}'Streams use Anthropic event names including message_start, content_block_delta, message_delta and message_stop.
Anthropic-hosted tools, Files and Message Batches are not compatibility targets. Signed, encrypted, and opaque history replay is not supported in this version, including on native routes. The API may preserve these items in native output, but sending them back as history returns 400.
Estimate input tokens
POST /v1/messages/count_tokens accepts model, system, messages and function tools and returns input_tokens without calling a provider, reserving funds or charging the wallet. It requires inference permission and the model allowlist still applies. This local Unicode heuristic is approximate, not the supplier tokenizer or a guaranteed context-fit bound. The response marks x-ci-token-count-estimated: true and x-ci-token-count-method: unicode-heuristic-v1. Media, signed thinking and server tools are unsupported.
Errors and limits#
OpenAI-compatible endpoints return an error object; Messages uses the Anthropic error envelope. 400 indicates an invalid or unsupported request; 401 an invalid, expired or revoked key; 402 insufficient balance; 403 a permission or policy denial; 404 a missing resource; 429 a rate or budget limit. Supplier failure, unavailable eligible capacity and timeouts can return 502, 503 or 504. Use status and error code for program logic.
| Field | Description |
|---|---|
400 | Invalid request body or unsupported parameter combination. |
401 | Missing, invalid, expired or revoked API key. |
402 | Insufficient wallet balance. |
403 | The API key lacks a required permission, or the request origin or account access is not authorized. |
404 | The model or requested record was not found. |
429 | A request, concurrency, quota, or key monthly budget limit was reached. |
502 | Eligible upstream requests failed. |
503 | No route meets the required capacity, discount or privacy conditions. |
504 | The serving request timed out. |
OpenAI-compatible endpoints use an error object. Messages returns Anthropic's error envelope. Use the status and error code for program logic, and the message for diagnosis.
{
"error": {
"message": "Invalid API key.",
"type": "authentication_error",
"code": "invalid_api_key"
}
}Reliability#
Each eligible route gets at most two physical attempts: the initial attempt and one retry for qualifying transport failures before downstream output or HTTP 404/408/409/425/429/5xx. A rejected underlying JSON-body read or SSE prebuffer read, or supplier timeout during those reads, can retry after response headers arrive. Attempts share one reservation and the original 180-second deadline. A valid Retry-After is honored in full only if it fits that attempt’s remaining budget; otherwise that retry is skipped. Parsing, decoding, invalid stream frames, usage-validation and database failures are not same-route transport retries. No retry occurs after a streaming response is returned, settlement begins or the client cancels. Only a valid final success is charged once. A new generation cannot continue a partial response. If the client retries a failed stream, start a complete new request and use bounded backoff.
Automatic fallback
Router can retry eligible provider failures and move to another route before output begins. The public model identifier and protocol stay the same.
Streaming boundaries
Once output reaches your client, a partial response cannot be replaced transparently. If a stream fails, retry the complete request. Do not append output from a new generation to a failed one.
Client retry policy
Use bounded exponential backoff with jitter for transient errors. Respect Retry-After when it is present, and set a reasonable timeout and output budget.
Usage and billing#
Successful requests report token usage and the settled customer charge in cheaper_inference.billing and usage.cost. Failed or unsettled requests have no settled amount. Request and daily reports require usage:read and accept start_at inclusive, end_at exclusive and api_key_id. Preserve filters while paging with next_cursor. Daily reporting uses timezone_offset_minutes east of UTC, defaults to 30 days and accepts up to 366 days. Account usage and savings require account:read; old requests without a recorded list-price baseline remain unknown rather than being repriced today. For settled supplier requests, a positive cache-read count is hit, an explicitly reported zero is miss, and absent read reporting is unknown. Historical zero alone is not evidence of a miss. Cache-write counts are independent. Platform exact-cache hits are not_applicable to supplier cache reporting; unsettled requests have a null state. Daily cache percentages include only settled supplier requests with proven cache-read reporting, including explicit zero reads.
Successful requests report token usage and the exact settled customer charge. Internally attempted provider requests do not appear as additional customer bills.
{
"usage": {
"prompt_tokens": 1234,
"completion_tokens": 321,
"total_tokens": 1555,
"cost": 0.012345
},
"cheaper_inference": {
"request_id": "request-id",
"billing": {
"status": "settled",
"billed_cost_usd": "0.012345",
"currency": "USD"
}
}
}The cheaper_inference namespace is retained for response compatibility. Its billed amount is your charge, not the private cost paid to a supplier. Failed or unsettled requests do not include a settled amount.
Chat streams deliver settlement metadata in a final empty-choice event. Responses includes it in response.completed or a final response.incomplete; Messages includes it in the final message_delta. The x-ci-request-id header helps locate the request.
Usage reports
Both reports require usage:read. Filter by start_at (inclusive), end_at (exclusive) and api_key_id. Timestamps without an offset are interpreted as UTC. Request history uses next_cursor for pagination; keep the same filters while paging. Daily reports fill missing calendar days and count only settled ledger amounts as spending.
curl 'https://your-router-domain/v1/usage/requests?limit=25' \
-H 'Authorization: Bearer YOUR_API_KEY'curl 'https://your-router-domain/v1/usage/daily?timezone_offset_minutes=480' \
-H 'Authorization: Bearer YOUR_API_KEY'timezone_offset_minutes sets a fixed calendar offset in minutes east of UTC. The default is 0; 480 means UTC+8. Daily reports default to 30 calendar days and accept windows up to 366 days. Unknown cache reporting is not presented as a measured zero hit rate.
Report channels#
Choose Email, Slack, Discord or Telegram in Reports for personal usage digests, excluding Router workspace requests. Email uses the account’s verified address; Slack and Discord use explicit platform authorization, while Telegram requires starting the Bot and confirming the recipient in the same Router session. Connecting leaves the schedule Off and sends no report. Daily, weekly and monthly summaries cover previous complete UTC periods, with scheduled work checked every five minutes. Read /v1/channels with account:read; update report_frequency or explicitly send-report with account:write. Browser mutations require the same origin. Off disables scheduled digests but manual reports can summarize yesterday. Details lists nine optional product events from available_events. Explicitly save events independently of report_frequency; [] unsubscribes, and Off disables only scheduled digests. Existing and reconnected channels are not automatically opted in. Required account, security and billing messages are separate. Missing configuration is a 503 error; sent:false means a successful no-activity result, not failed delivery. Provider acceptance does not establish recipient reading. No automatic resend follows an unknown acknowledgement. Connection management requires the signed-in browser session. See /api-reference#channels.
Reports include personal usage and settled spending without prompt or response bodies or Router team activity. Choose Email, Slack, Discord or Telegram in Reports and explicitly connect the destination before scheduling. Platform acceptance does not establish that a person read it.
Channel operations and connection scope →Choose optional techniques#
Eight optional techniques default off and only apply to eligible requests. Read settings with GET /v1/techniques using account:read; change enabled with PATCH /v1/techniques/{id} using account:write. Exact-cache stores eligible response text per user for a 15-minute reuse window, not prompt text. Eligible hits have zero usage and charge. Account disable clears current cache; an active experiment explicitly enabling caching can store new entries. No unmeasured percentage savings is claimed.
All eight optional techniques default off. Read their eligibility and quality tradeoffs in workspace controls, or use the API to update your account. A technique only runs when the request meets its conditions.
curl 'https://your-router-domain/v1/techniques' \
-H 'Authorization: Bearer YOUR_API_KEY'curl "$ROUTER_BASE_URL/v1/techniques/concise-output" \
-X PATCH \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-H "Content-Type: application/json" \
-d '{"enabled":true}'Eligible exact-cache hits return zero usage and zero inference charge. Caching requires temperature 0, non-streaming plain text, and no tools. Model routing can change a simple request to a configured cheaper sibling; it does not promise equivalent quality. No percentage savings is claimed without measured control data.
Compare changes on your own traffic#
Create an experiment with 2–10 weighted variants and one control in the workspace. Compare models, system instructions or techniques. Add X-CI-Experiment with its slug; sticky assignment also needs X-CI-End-User. Draft, paused and completed experiments leave requests unchanged. Explicit completion stops new assignments and preserves results and in-flight settlements; a completed experiment can promote one variant for later traffic but cannot resume. Unknown or foreign slugs return 404. Explicit technique lists override account settings; null inherits them and [] disables optional techniques.
Create a draft in Experimentswith 2–10 weighted variants and one control. Compare model, system instructions, or techniques. Start the experiment, then attach its slug to inference requests. Sticky assignment also needs a stable, non-sensitive end-user identifier.
curl "$ROUTER_BASE_URL/v1/chat/completions" \
-H "Authorization: Bearer $ROUTER_API_KEY" \
-H "Content-Type: application/json" \
-H "X-CI-Experiment: your-experiment-slug" \
-H "X-CI-End-User: stable-user-id" \
-d '{"model":"deepseek-v4-flash","messages":[{"role":"user","content":"Summarize this idea."}],"max_tokens":128}'Draft and paused experiments leave the request unchanged. A promoted experiment uses its selected variant for all future matching requests. Unknown or another account’s slugs return 404. Fixed model variants cannot also explicitly enable model routing.
curl 'https://your-router-domain/v1/experiments' \
-H 'Authorization: Bearer YOUR_API_KEY'Experiment creation, draft editing, start, pause, promotion, and draft deletion use the signed-in workspace API. The complete configuration is limited to 150 KiB, with at most 12,000 characters per system prompt. Read the OpenAPI specification for the full management contract.
Use the tools you already know#
Use the integration guides for Codex through Responses, Claude Code through Anthropic Messages, or Cursor through its OpenAI-compatible base URL. Guides use this deployment origin and configured model IDs. Keep API keys in local environment variables or server settings rather than application source. Validate the actual model and tool combination you plan to use.