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

Keys and environments

  • One workspace 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

modelsfallback 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.
timeoutsclient
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.
retriesclient
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.
idempotencydesign
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 preferencesrouting
Use sort: "latency" for interactive paths, sort: "price" (or :floor) for batch, and require_parameters: true when a dropped parameter would silently change behaviour.
healthmonitoring
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

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." }
    ]
  }'