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

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.

webhookHTTPS · signed
JSON { object: "list", data: [event…] }. Header x-er-signature: t=<unix>,v1=<hex> where v1 = HMAC_SHA256(secret, `${t}.{raw body}`); reject when t is older than five minutes.
otlpOpenTelemetry collector
OTLP/HTTP JSON logs posted to <url>/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.
s3S3-compatible
NDJSON objects under prefix/YYYY/MM/DD/, signed with SigV4. Custom endpoints (MinIO, Cloudflare R2, Backblaze) with path-style addressing.
// 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.

# 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.

# 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.

// 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 for what ships next.