Concepts
API keys (sk_live_…, sk_test_…)
What your callers send in Authorization: Bearer. Created per workspace under Connect → API keys. Each key has:
- An environment label (
live/test). It is a label, not a sandbox:sk_test_andsk_live_keys behave the same, both call the real vendor, and both bill your organisation. Use a separate key per environment so staging traffic is attributed separately and can be revoked on its own. - Where it is used from (
server/browser, shown as Server / Website) — website keys only work from the sites you list, and cannot pinversion_idon prompts (use labels). - A replace secret + revoke lifecycle, every change recorded under API keys → Key activity.
Never ship an API key to a public client unless its scope is browser and the workspace is locked down with allowed-models + budget caps.
Vendor keys
Real OpenAI / Anthropic / Google / Mistral / xAI / Groq / DeepSeek keys, stored encrypted in the vault. odnoga picks one per request via round-robin and marks exhausted keys cool-down on 429/credit errors. Your organisation can add its own under Organisation admin → Vendor keys.
End users
The x-odnoga-end-user header (≤256 chars; the pre-rebrand x-airouter-end-user and the OpenAI-compatible user body field are also honoured). Drives:
- Per-end-user metering — flushed to your own Stripe via tenant meter flush.
- Top end users rollup on Overview.
- A/B stickiness — same end user always lands in the same prompt-version bucket.
Budgets
Workspace → Budget. Daily / monthly cap in USD. odnoga blocks new requests at 100% with budget_exhausted (HTTP 402). At 80% and 100% it enqueues budget_80 / budget_100 alert events.
Tenant admins can also set a global tenant spend cap (Tenant admin → Spend cap) that applies across every workspace in the tenant. Both caps are checked on every request — the stricter one wins.
Allowed models
Optional allowlist per workspace. When set, requests for any other model return 400 model_not_allowed before any vendor call.
Cache
Opt-in per workspace (Cache card). Cache key is a SHA-256 of the normalized request body. Hits return instantly with x-airouter-cache: hit and don't consume vendor tokens (cost = 0). TTL is per entry, default 3600s.
Response shape (openai vs native)
By default every vendor's answer is translated into the OpenAI shape (choices, usage), so one client works against all of them. A workspace — or its tenant admin, who can lock the choice — can instead select raw vendor responses: you then receive the vendor's own body (Gemini candidates / usageMetadata, Claude content blocks). Never assume the shape: every response carries x-airouter-response-format (openai | native), and the _odnoga block plus the x-airouter-*-tokens / x-airouter-cost-usd headers are attached in both modes — read tokens and cost from those, never from the body. Streamed responses are always OpenAI-shaped, in either mode, because a raw vendor stream carries no usage frame to meter. Configure under Workspace → Models → Response format; see the headers reference.
Batch jobs
Large offline workloads (backfills, re-classification, bulk embeddings) submitted once to /v1/batches instead of looping /v1/chat/completions. When every item is eligible, odnoga hands the job to the vendor's own Batch API — OpenAI, Anthropic and Google are live at a genuine 50% discount, xAI at its own 20% (grok-4.3 and the grok-4.20 family only; the discount is the vendor's term, not ours) — and reports execution_mode: "vendor_batch", billing_tier: "batch". Anything not eligible runs on odnoga's internal queue at standard rates with fallback_reason stating exactly why: odnoga never bills a discount it did not obtain, and per item billed_tier in the results is what that row was actually charged. Track jobs in Workspace → Batch jobs, or over MCP with batches.list / batches.get / batches.cancel; the full contract (per-vendor endpoints, windows, caps) is in the MCP batches.guide tool.
Pricing (GET /v1/pricing)
The price list your workspace pays, margins included — the same numbers the gateway bills from, so an integration can cost a job before running it. Per model: prices per 1M tokens (input, cached input, output) plus per-unit media rates, the service tiers it can route through, and the region uplift. The top-level service_tiers array carries each vendor's tier multiplier — a tier marked delivered: false bills at 100% (standard) until odnoga genuinely obtains it. Authenticated with your API key; end-user tokens are refused — end users buy at the plans you publish, never at your workspace's own terms. The same prices appear per model in MCP models.list.
Prompts (managed)
Prompts have a slug, multiple versions, optional labels (e.g. production, staging). Call by slug + label and you can swap implementations without redeploying.
version_id overrides the label — banned for browser keys and EUT JWTs.
A/B experiments
A prompt can have multiple active versions weighted by traffic share. Bucket assignment is sticky per x-airouter-end-user so a user keeps seeing the same variant across requests.
Routes and fallback
Workspace → Routing → Routes. A route (odnoga/<name>) is an ordered list of models your code sends instead of a model, versioned, with history and undo; a route can be connected to a function so every call from it is served by the route without a code change. On a retryable error (timeout, 5xx, vendor 429) odnoga walks the list; the response carries x-airouter-fallback: 1, the actually-used x-airouter-model, and x-odnoga-route / x-odnoga-route-version. The same page holds the automatic chain ("model": "auto") and per-model fallbacks.
Model lifecycle
A model is active, may get an announced retirement date (still serving; every response carries Sunset /
Deprecation headers and the replacement slug), and is then retired (model_deprecated on the old name). Nothing is
deleted: history stays attributable. Organisation admins are told by email and in the app when a retirement is announced
for a model they call, a week before, on the day, and daily while an integration still sends the old name.
Automatic fallback (Organisation → Defaults → Retired models) serves the catalog's replacement for the old name —
same vendor only, allow-lists respected, billed as the model that served — and marks the response with
x-odnoga-model-fallback. Off by default: the safe default for a gateway is to say no, not to guess.
Raw capture
Opt-in per workspace. When on, raw vendor request/response payloads are retained for the configured TTL. Use for debugging odd vendor behavior or compliance audits.
EUT (end-user tokens)
Short-lived JWTs your backend mints so a browser can call odnoga directly (without your API key leaking). EUTs always carry an end-user id and a budget. See Security.