Reference

Proxy endpoints

Per-endpoint reference for the OpenAI-compatible surface at PUBLIC_URL/v1.

POST /v1/chat/completions

The primary endpoint. For OpenAI-compatible upstreams the body is forwarded as sent, with a few exceptions: a display name in model is replaced by the model’s native name, streaming requests get stream_options.include_usage so usage can be metered, and Security Gateway redactions or router instructions are applied when configured. Requests to other providers (Anthropic, Gemini, Bedrock) are translated, and so are their responses. Set stream:true for server-sent events — frames are relayed as they arrive and usage is read from the final frame.

Successful buffered (non-streaming) responses carry X-Janus-Cost-USD with the cost attributed to the call under the model’s current rate card, and X-Janus-Token-Accounting naming how the figures were obtained (upstream_reported, upstream_reported_cost, byte_count_fallback, unmetered_modality). Streaming responses do not carry these headers — the cost is only known once the final frame has arrived — but the call is metered identically and appears in the request log and dashboards. Calls billed to a personal subscription report a cost of 0, and error responses are recorded as not_billable.

Throughput is returned too. When the provider measures it (Groq, llama.cpp, Ollama) the gateway forwards it as X-Janus-Tokens-In-Per-Second and X-Janus-Tokens-Out-Per-Second with X-Janus-Throughput-Source: upstream. When it does not, the gateway derives it from the token counts and its own clock and returns it under DIFFERENT names — X-Janus-Calculated-Tokens-In-Per-Second and X-Janus-Calculated-Tokens-Out-Per-Second with X-Janus-Throughput-Source: calculated — so a network-inclusive estimate can never be mistaken for a provider measurement. On streams the same fields arrive as HTTP trailers after the final frame (prompt throughput uses time-to-first-byte as its window, generation throughput the remainder). Input throughput counts only the prompt the provider actually processed: tokens served from its prompt cache are excluded (and cache writes included), so a mostly-cached request reports the model’s real prefill speed rather than a multiple of it.

curl ${JANUS_PUBLIC_URL}/v1/chat/completions \
  -H "Authorization: Bearer $JANUS_TOKEN" \
  -H "Content-Type: application/json" \
  -d '{"model": "gpt-4o-mini", "messages": [{"role": "user", "content": "Hello"}]}'

POST /v1/completions and POST /v1/embeddings

Legacy completions and embeddings work the same way: the same forwarding, grant and quota checks on the model, full metering. Embedding requests are recorded with the embedding modality so dashboards can separate them from chat.

GET /v1/models

Returns the OpenAI-shaped model list filtered to what your token may use. A model appears only when it is enabled and covered by a grant that matches you (outside local-only mode, a model cannot be enabled until it has a rate card). If a model you expect is missing, ask an administrator for a grant.

The list also includes managed models, your connected personal subscriptions, and decision models (marked kind: decision, with the endpoints that serve them). Each entry has a janus object with the upstream, modalities, price per million tokens, how you were granted it, and the native model name. Models blocked for a child account by Child Safety are left out.

Everything else under /v1

Paths without a dedicated route (audio, images, moderations, files, and so on) pass through to the upstream when policy allows, and are metered by modality. When a provider reports a cost directly (X.ai cost_in_usd_ticks) that exact figure is recorded. When a TEXT-shaped response returns no usage block, tokens are estimated from byte counts and the request log marks the accounting method byte_count_fallback. Media responses (audio, images, video) are never byte-estimated — a 30 KB MP3 is not 7,680 tokens — so one that carries no usage is recorded with zero tokens and zero cost under unmetered_modality, logged as a configuration gap, and counted in janus_unmetered_requests_total. Streamed TTS (stream_format: sse) reports exact usage on its final frame and is metered normally.

This includes /v1/responses and /v1/messages (Anthropic Messages), which get the same policy, routing and metering as chat completions. A request without a body (such as GET /v1/videos/{id}) names its model in the X-Janus-Model header or a ?model= query parameter.

POST /v1/decisions, /v1/systemone, /api/alpha/decisions

Call a decision model in the OpenAI Decisions format (/v1/decisions) or the System One format (the other two). Any decision model can be reached from any of the three: when the model speaks the other format, Janus translates both ways and says so in X-Janus-Decision-Translated; X-Janus-Decision-Dialect names the format the model was called in. Grants, policy rules, rate limits, the Security Gateway, quotas and metering apply as for chat.

Other headers

Responses also carry X-Janus-Request-ID (quote it when reporting a problem); X-Janus-Route, X-Janus-Route-Reason and X-Janus-Route-Model when an auto-router chose the model; X-Janus-Fallback-Reason when a managed model was served by its fallback; X-Janus-Security-Action and X-Janus-Redactions when the Security Gateway observed or redacted the request; and X-Janus-Reasoning-Adjusted when Janus changed the requested reasoning effort to fit the model.

Callers can label requests for reports with X-Janus-Project and X-Janus-Cost-Center, and name the calling application with X-Janus-Agent (X-OpenRouter-Title and X-Title are honored too).