Quickstart
Three steps: store an API key, point your client at the odnoga base URL, identify the end user. You now have routing, fallbacks, prompts, cache, metering, and cost tracking — server-side.
1. Mint an API key
Workspace → Virtual keys → New key. Pick a scope:
| Scope | Use for | Notes |
|---|---|---|
server | Backend code, edge functions | Default. Full power. |
browser | Browser-issued calls via your own backend proxy | version_id is rejected; use label. |
Copy the sk_live_… (or sk_test_…) and put it in your environment:
AIROUTER_API_KEY=sk_live_...
AIROUTER_BASE_URL=https://api.odnoga.com/functions/v1/airouter-openai-compat
2. Fire the first request
curl "$AIROUTER_BASE_URL/v1/chat/completions" \
-H "authorization: Bearer $AIROUTER_API_KEY" \
-H "content-type: application/json" \
-H "x-airouter-end-user: user_123" \
-d '{
"model": "gpt-4o-mini",
"messages": [{"role":"user","content":"hello"}]
}' -i
You should see 200 OK and a response with these headers:
x-airouter-request-id: 8b1a…
x-airouter-vendor: openai
x-airouter-model: gpt-4o-mini
x-airouter-cost-usd: 0.000043
x-airouter-latency-ms: 612
x-airouter-cache: miss
x-ratelimit-remaining-usd: 49.9999
If you got 4xx, jump to Troubleshooting.
2.5. Always identify the end user
Set x-airouter-end-user on every call (max 256 chars, your stable user id). It unlocks:
- Per-end-user usage rollups in Overview → Top end users.
- Stripe meter passthrough (bill your own tenants on dollars or tokens).
- Sticky A/B bucket assignment for managed prompts.
Skipping it is the #1 reason analytics look empty.
3. Pick your SDK
- cURL — for shell scripts and reference.
- OpenAI Node SDK — drop-in
baseURL. - OpenAI Python SDK — same.
- Anthropic SDK — translated to OpenAI shape internally.
- LangChain —
ChatOpenAIwithmodelKwargs. - Vercel AI SDK —
createOpenAI. @odnoga/node— managed prompts +_meta.
4. Read the observability headers
Every successful response carries these — log them.
See the full headers reference.
5. Handle errors
All failures are OpenAI-shaped JSON, so SDKs parse them cleanly:
{
"error": {
"message": "Model not allowed for this workspace: gpt-5",
"type": "invalid_request_error",
"code": "model_not_allowed"
}
}
See the full errors table.
6. Lock down what your team can call
Workspace → Routing → Allowed models → pick the subset. Anything not in the list returns 400 model_not_allowed. Leave the toggle off to allow every active platform model (default).
7. Use managed prompts (recommended)
Stop shipping prompt strings from your backend. Define prompts in Prompts, call them by slug:
curl "$AIROUTER_BASE_URL/v1/chat/completions" \
-H "authorization: Bearer $AIROUTER_API_KEY" \
-H "content-type: application/json" \
-H "x-airouter-end-user: user_123" \
-d '{
"model": "gpt-4o-mini",
"prompt": {
"slug": "welcome-email",
"label": "production",
"variables": { "name": "Ada" }
}
}'
messages is omitted; the server renders it from the template + variables.
Next: Concepts.