{ "components": { "schemas": { "AliasRequest": { "description": "Request to create or update an alias.", "properties": { "name": { "description": "Display name callers use as the model, e.g. 'fast-model'.", "title": "Name", "type": "string" }, "target": { "description": "Selector the alias resolves to, as 'provider:model' or 'instance:model'.", "title": "Target", "type": "string" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "User this alias belongs to. Omit for a global alias every caller sees. A user-scoped alias resolves only for that user and shadows a global one of the same name.", "title": "User Id" } }, "required": [ "name", "target" ], "title": "AliasRequest", "type": "object" }, "AliasResponse": { "description": "A model alias and where it is defined.", "properties": { "created_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Created At" }, "name": { "title": "Name", "type": "string" }, "source": { "title": "Source", "type": "string" }, "target": { "title": "Target", "type": "string" }, "updated_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Updated At" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "name", "target", "source" ], "title": "AliasResponse", "type": "object" }, "AudioSpeechRequest": { "description": "OpenAI-compatible audio speech (TTS) request.\n\nThe speech fields are derived from any-llm's ``AudioSpeechParams`` (see\n``_schema_derive``) so the schema cannot silently drop a param any-llm\nforwards. ``user`` is gateway-only (billing / auth scoping); it is not an\nany-llm param and is stripped before the request is forwarded.", "properties": { "input": { "title": "Input", "type": "string" }, "instructions": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Instructions" }, "model": { "title": "Model", "type": "string" }, "response_format": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Response Format" }, "speed": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Speed" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" }, "voice": { "title": "Voice", "type": "string" } }, "required": [ "model", "input", "voice" ], "title": "AudioSpeechRequest", "type": "object" }, "BatchRequestItem": { "properties": { "body": { "additionalProperties": true, "title": "Body", "type": "object" }, "custom_id": { "title": "Custom Id", "type": "string" } }, "required": [ "custom_id", "body" ], "title": "BatchRequestItem", "type": "object" }, "Body_create_file_v1_files_post": { "properties": { "file": { "contentMediaType": "application/octet-stream", "title": "File", "type": "string" }, "purpose": { "default": "user_data", "title": "Purpose", "type": "string" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "file" ], "title": "Body_create_file_v1_files_post", "type": "object" }, "Body_create_transcription_v1_audio_transcriptions_post": { "properties": { "file": { "contentMediaType": "application/octet-stream", "title": "File", "type": "string" }, "language": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Language" }, "model": { "title": "Model", "type": "string" }, "prompt": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Prompt" }, "response_format": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Response Format" }, "temperature": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Temperature" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "file", "model" ], "title": "Body_create_transcription_v1_audio_transcriptions_post", "type": "object" }, "BudgetResetLogResponse": { "description": "Response model for one budget reset event (per user).", "properties": { "budget_id": { "title": "Budget Id", "type": "string" }, "id": { "title": "Id", "type": "integer" }, "next_reset_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Next Reset At" }, "previous_spend": { "title": "Previous Spend", "type": "number" }, "reset_at": { "title": "Reset At", "type": "string" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "id", "user_id", "budget_id", "previous_spend", "reset_at", "next_reset_at" ], "title": "BudgetResetLogResponse", "type": "object" }, "BudgetResponse": { "description": "Response model for budget information.\n\n``max_budget`` is the per-user spending limit, and multiple users can share\none budget, so the usage rollup is an aggregate over the users assigned to\nthis budget: how many there are and their combined ``spend`` / ``reserved``.\nAssigning users to a budget is done through the users API (dashboard support\nlands with user management), so a fresh gateway reports zeros here.", "properties": { "budget_duration_sec": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Budget Duration Sec" }, "budget_id": { "title": "Budget Id", "type": "string" }, "created_at": { "title": "Created At", "type": "string" }, "max_budget": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Max Budget" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "total_reserved": { "default": 0.0, "title": "Total Reserved", "type": "number" }, "total_spend": { "default": 0.0, "title": "Total Spend", "type": "number" }, "updated_at": { "title": "Updated At", "type": "string" }, "user_count": { "default": 0, "title": "User Count", "type": "integer" } }, "required": [ "budget_id", "name", "max_budget", "budget_duration_sec", "created_at", "updated_at" ], "title": "BudgetResponse", "type": "object" }, "ChatCompletionRequest": { "description": "OpenAI-compatible chat completion request.\n\nThe completion-param fields are derived from any-llm's ``CompletionParams``\n(see ``_schema_derive``) so the schema cannot silently drop a param any-llm\nforwards. Fields below either tighten a derived field (``messages``,\n``response_format``) or add gateway-internal behavior (``mcp_servers``,\n``mcp_server_ids``, ``guardrails``, ``tools_header``, ``max_tool_iterations``)\nthat is stripped before the request is forwarded upstream.", "properties": { "frequency_penalty": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Frequency Penalty" }, "guardrails": { "anyOf": [ { "items": { "$ref": "#/components/schemas/GuardrailConfig" }, "maxItems": 8, "type": "array" }, { "type": "null" } ], "title": "Guardrails" }, "logit_bias": { "anyOf": [ { "additionalProperties": { "type": "number" }, "type": "object" }, { "type": "null" } ], "title": "Logit Bias" }, "logprobs": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Logprobs" }, "max_completion_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Max Completion Tokens" }, "max_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Max Tokens" }, "max_tool_iterations": { "anyOf": [ { "maximum": 25.0, "minimum": 1.0, "type": "integer" }, { "type": "null" } ], "title": "Max Tool Iterations" }, "mcp_server_ids": { "anyOf": [ { "items": { "format": "uuid", "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Mcp Server Ids" }, "mcp_servers": { "anyOf": [ { "items": { "$ref": "#/components/schemas/McpServerConfig" }, "type": "array" }, { "type": "null" } ], "title": "Mcp Servers" }, "messages": { "items": { "additionalProperties": true, "type": "object" }, "minItems": 1, "title": "Messages", "type": "array" }, "model": { "title": "Model", "type": "string" }, "n": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "N" }, "parallel_tool_calls": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Parallel Tool Calls" }, "presence_penalty": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Presence Penalty" }, "reasoning_effort": { "anyOf": [ { "enum": [ "none", "minimal", "low", "medium", "high", "xhigh", "max", "auto" ], "type": "string" }, { "type": "null" } ], "default": "auto", "title": "Reasoning Effort" }, "response_format": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Response Format" }, "seed": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Seed" }, "session_label": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "description": "Optional caller-supplied label for cost attribution (per run, experiment, or conversation). In hybrid mode it is forwarded onto the platform usage report so spend can be sliced by session without standing up OpenTelemetry. Stripped before the request is forwarded upstream to the provider. Has no effect in standalone mode, where there is no platform to report it to.", "title": "Session Label" }, "stop": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Stop" }, "stream": { "default": false, "title": "Stream", "type": "boolean" }, "stream_options": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Stream Options" }, "temperature": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Temperature" }, "tool_choice": { "anyOf": [ { "type": "string" }, { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Tool Choice" }, "tools": { "anyOf": [ { "items": { "anyOf": [ { "additionalProperties": true, "type": "object" }, {} ] }, "type": "array" }, { "type": "null" } ], "title": "Tools" }, "tools_header": { "anyOf": [ { "maxLength": 4000, "type": "string" }, { "type": "null" } ], "description": "Optional override for the lead-in that the gateway prepends before the per-tool hint block in the system message. Useful for expressing global tool-selection policy (e.g. 'prefer MCP tools over code_execution'). Falls back to OTARI_TOOLS_HEADER env, then to the built-in default.", "title": "Tools Header" }, "top_logprobs": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Top Logprobs" }, "top_p": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Top P" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "model", "messages" ], "title": "ChatCompletionRequest", "type": "object" }, "ConfigField": { "description": "One effective config value surfaced to the dashboard's config viewer.", "properties": { "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "exclusive_minimum": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Exclusive Minimum" }, "group": { "title": "Group", "type": "string" }, "key": { "title": "Key", "type": "string" }, "minimum": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Minimum" }, "options": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Options" }, "settable": { "title": "Settable", "type": "boolean" }, "type": { "enum": [ "bool", "int", "float", "str", "list" ], "title": "Type", "type": "string" }, "value": { "anyOf": [ { "type": "boolean" }, { "type": "integer" }, { "type": "number" }, { "type": "string" }, { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Value" } }, "required": [ "key", "value", "type", "settable", "group" ], "title": "ConfigField", "type": "object" }, "CountTokensRequest": { "description": "Anthropic ``/v1/messages/count_tokens`` request.\n\nA subset of :class:`MessagesRequest`: the input fields that affect the token\ncount, minus ``max_tokens`` and the streaming/sampling controls, since the\nendpoint only counts input tokens. Clients such as Claude Code call this on\nevery turn to keep their prompt within the model's context window.", "properties": { "cache_control": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Cache Control" }, "messages": { "items": { "additionalProperties": true, "type": "object" }, "minItems": 1, "title": "Messages", "type": "array" }, "metadata": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Metadata" }, "model": { "title": "Model", "type": "string" }, "system": { "anyOf": [ { "type": "string" }, { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, { "type": "null" } ], "title": "System" }, "thinking": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Thinking" }, "tool_choice": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Tool Choice" }, "tools": { "anyOf": [ { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, { "type": "null" } ], "title": "Tools" } }, "required": [ "model", "messages" ], "title": "CountTokensRequest", "type": "object" }, "CountTokensResponse": { "description": "Anthropic ``/v1/messages/count_tokens`` response.", "properties": { "input_tokens": { "title": "Input Tokens", "type": "integer" } }, "required": [ "input_tokens" ], "title": "CountTokensResponse", "type": "object" }, "CreateBatchRequest": { "properties": { "completion_window": { "default": "24h", "title": "Completion Window", "type": "string" }, "metadata": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "title": "Metadata" }, "model": { "title": "Model", "type": "string" }, "requests": { "items": { "$ref": "#/components/schemas/BatchRequestItem" }, "maxItems": 10000, "minItems": 1, "title": "Requests", "type": "array" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "model", "requests" ], "title": "CreateBatchRequest", "type": "object" }, "CreateBudgetRequest": { "description": "Request model for creating a new budget.", "properties": { "budget_duration_sec": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "integer" }, { "type": "null" } ], "description": "Budget duration in seconds (e.g., 86400 for daily, 604800 for weekly)", "title": "Budget Duration Sec" }, "max_budget": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "description": "Maximum spending limit", "title": "Max Budget" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Admin-facing label for the budget", "title": "Name" } }, "title": "CreateBudgetRequest", "type": "object" }, "CreateKeyRequest": { "description": "Request model for creating a new API key.", "properties": { "allowed_models": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Model allow-list: null = any model, [] = deny all, or canonical instance:model entries (with instance:* / instance:prefix* wildcards).", "title": "Allowed Models" }, "exclude_from_budget": { "default": false, "description": "When true, requests on this key are logged with cost but never reserved, reconciled into the user's spend, or gated by budget.", "title": "Exclude From Budget", "type": "boolean" }, "expires_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Optional expiration timestamp", "title": "Expires At" }, "key_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional name for the key", "title": "Key Name" }, "metadata": { "additionalProperties": true, "description": "Optional metadata", "title": "Metadata", "type": "object" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional user ID to associate with this key", "title": "User Id" } }, "title": "CreateKeyRequest", "type": "object" }, "CreateKeyResponse": { "description": "Response model for creating a new API key.", "properties": { "allowed_models": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Allowed Models" }, "created_at": { "title": "Created At", "type": "string" }, "exclude_from_budget": { "title": "Exclude From Budget", "type": "boolean" }, "expires_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Expires At" }, "id": { "title": "Id", "type": "string" }, "is_active": { "title": "Is Active", "type": "boolean" }, "key": { "title": "Key", "type": "string" }, "key_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Key Name" }, "key_prefix": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Key Prefix" }, "metadata": { "additionalProperties": true, "title": "Metadata", "type": "object" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "id", "key", "key_prefix", "key_name", "user_id", "created_at", "expires_at", "is_active", "allowed_models", "exclude_from_budget", "metadata" ], "title": "CreateKeyResponse", "type": "object" }, "CreateSessionRequest": { "description": "Sign in to the dashboard by proving possession of the master key.", "properties": { "master_key": { "description": "The gateway master key; verified once and never stored by the browser.", "title": "Master Key", "type": "string" } }, "required": [ "master_key" ], "title": "CreateSessionRequest", "type": "object" }, "CreateStoredProviderRequest": { "description": "Create a stored provider. ``api_key`` is write-only and requires OTARI_SECRET_KEY.", "properties": { "api_base": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Base" }, "api_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Provider API key. Stored encrypted; never returned.", "title": "Api Key" }, "client_args": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Client Args" }, "instance": { "description": "Routing key, e.g. 'openai' or a named instance like 'home_lab'.", "minLength": 1, "title": "Instance", "type": "string" }, "provider_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "any-llm implementation when the instance name is not itself one.", "title": "Provider Type" } }, "required": [ "instance" ], "title": "CreateStoredProviderRequest", "type": "object" }, "CreateUserRequest": { "description": "Request model for creating a new user.", "properties": { "alias": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional admin-facing alias", "title": "Alias" }, "allowed_models": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "description": "Default model access-list this user's keys inherit; null = unrestricted, [] = deny all", "title": "Allowed Models" }, "blocked": { "default": false, "description": "Whether user is blocked", "title": "Blocked", "type": "boolean" }, "budget_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optional budget ID", "title": "Budget Id" }, "metadata": { "additionalProperties": true, "description": "Optional metadata", "title": "Metadata", "type": "object" }, "user_id": { "description": "Unique user identifier", "title": "User Id", "type": "string" } }, "required": [ "user_id" ], "title": "CreateUserRequest", "type": "object" }, "DiscoverableModel": { "description": "A model one provider instance reports as available.", "properties": { "id": { "description": "Bare model id as the provider reports it.", "title": "Id", "type": "string" }, "key": { "description": "Selector to send as `model`, in `instance:model` form.", "title": "Key", "type": "string" } }, "required": [ "id", "key" ], "title": "DiscoverableModel", "type": "object" }, "DiscoverableModelsResponse": { "description": "Per-provider discovery results for operator model selection.", "properties": { "providers": { "items": { "$ref": "#/components/schemas/DiscoverableProvider" }, "title": "Providers", "type": "array" } }, "required": [ "providers" ], "title": "DiscoverableModelsResponse", "type": "object" }, "DiscoverableProvider": { "description": "One provider instance's discovery result.", "properties": { "discovery_unsupported": { "default": false, "description": "True when discovery failed only because this backend serves no model-listing endpoint. The provider may still handle requests for models declared in config.", "title": "Discovery Unsupported", "type": "boolean" }, "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Why discovery failed. Null when `ok` is true.", "title": "Error" }, "models": { "items": { "$ref": "#/components/schemas/DiscoverableModel" }, "title": "Models", "type": "array" }, "ok": { "description": "False when this instance could not be queried.", "title": "Ok", "type": "boolean" }, "provider": { "title": "Provider", "type": "string" } }, "required": [ "provider", "ok", "models" ], "title": "DiscoverableProvider", "type": "object" }, "EmbeddingRequest": { "description": "OpenAI-compatible embedding request.", "properties": { "dimensions": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Dimensions" }, "encoding_format": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Encoding Format" }, "input": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" } ], "description": "Input text to embed", "title": "Input" }, "model": { "title": "Model", "type": "string" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "model", "input" ], "title": "EmbeddingRequest", "type": "object" }, "ExternalEventsRequest": { "additionalProperties": false, "description": "A batch of imported usage events sharing a source and default user.\n\n``extra=\"forbid\"`` here mirrors the per-event schema: a stray content field at\nthe batch level (e.g. a top-level ``prompt``) is a 422, not silently ignored.", "properties": { "events": { "items": { "$ref": "#/components/schemas/ExternalUsageEvent" }, "maxItems": 1000, "minItems": 1, "title": "Events", "type": "array" }, "source": { "maxLength": 64, "pattern": "^[a-zA-Z0-9._:-]+$", "title": "Source", "type": "string" }, "user_id": { "anyOf": [ { "maxLength": 256, "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "source", "events" ], "title": "ExternalEventsRequest", "type": "object" }, "ExternalIngestError": { "description": "A single rejected event, with enough context to fix it and retry.", "properties": { "detail": { "title": "Detail", "type": "string" }, "index": { "title": "Index", "type": "integer" }, "source_event_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Source Event Id" } }, "required": [ "index", "source_event_id", "detail" ], "title": "ExternalIngestError", "type": "object" }, "ExternalIngestResult": { "description": "Per-batch outcome. Re-submitting is safe: prior events count as duplicates.", "properties": { "accepted": { "default": 0, "title": "Accepted", "type": "integer" }, "duplicate": { "default": 0, "title": "Duplicate", "type": "integer" }, "errors": { "items": { "$ref": "#/components/schemas/ExternalIngestError" }, "title": "Errors", "type": "array" }, "rejected": { "default": 0, "title": "Rejected", "type": "integer" } }, "title": "ExternalIngestResult", "type": "object" }, "ExternalUsageEvent": { "additionalProperties": false, "description": "One imported usage event. Content-free: token counts and metadata only.\n\n``extra=\"forbid\"`` rejects any unexpected field (e.g. a stray ``prompt`` or\n``completion``) with a 422 rather than silently dropping it, so no prompt or\ncompletion text can ever be accepted here.", "properties": { "cache_read_tokens": { "default": 0, "maximum": 2147483647.0, "minimum": 0.0, "title": "Cache Read Tokens", "type": "integer" }, "cache_tokens_in_prompt": { "default": false, "title": "Cache Tokens In Prompt", "type": "boolean" }, "cache_write_1h_tokens": { "default": 0, "maximum": 2147483647.0, "minimum": 0.0, "title": "Cache Write 1H Tokens", "type": "integer" }, "cache_write_tokens": { "default": 0, "maximum": 2147483647.0, "minimum": 0.0, "title": "Cache Write Tokens", "type": "integer" }, "duration_ms": { "anyOf": [ { "maximum": 2147483647.0, "minimum": 0.0, "type": "integer" }, { "type": "null" } ], "title": "Duration Ms" }, "input_tokens": { "default": 0, "maximum": 2147483647.0, "minimum": 0.0, "title": "Input Tokens", "type": "integer" }, "model": { "maxLength": 256, "minLength": 1, "pattern": "^[A-Za-z0-9._:/\\-]+$", "title": "Model", "type": "string" }, "output_tokens": { "default": 0, "maximum": 2147483647.0, "minimum": 0.0, "title": "Output Tokens", "type": "integer" }, "provider": { "maxLength": 128, "minLength": 1, "pattern": "^[A-Za-z0-9._:/\\-]+$", "title": "Provider", "type": "string" }, "session_label": { "anyOf": [ { "maxLength": 256, "pattern": "^[A-Za-z0-9._:/\\-]+$", "type": "string" }, { "type": "null" } ], "title": "Session Label" }, "source_event_id": { "maxLength": 256, "minLength": 1, "pattern": "^[A-Za-z0-9._:/\\-]+$", "title": "Source Event Id", "type": "string" }, "status": { "default": "success", "pattern": "^(success|error)$", "title": "Status", "type": "string" }, "timestamp": { "format": "date-time", "title": "Timestamp", "type": "string" }, "user_id": { "anyOf": [ { "maxLength": 256, "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "source_event_id", "timestamp", "provider", "model" ], "title": "ExternalUsageEvent", "type": "object" }, "GatewaySettings": { "description": "Operator-facing runtime settings surfaced to the dashboard.\n\nThe top-level flags are kept for the callers that read them directly\n(pricing warnings, the models/providers pages); ``config`` is the full\nread-only view with the settable/startup-only marking.", "properties": { "config": { "items": { "$ref": "#/components/schemas/ConfigField" }, "title": "Config", "type": "array" }, "default_pricing": { "title": "Default Pricing", "type": "boolean" }, "master_key_source": { "description": "Whether the dashboard master key is configured at startup or generated and stored by Otari.", "enum": [ "configured", "generated" ], "title": "Master Key Source", "type": "string" }, "mode": { "title": "Mode", "type": "string" }, "model_discovery": { "title": "Model Discovery", "type": "boolean" }, "require_pricing": { "title": "Require Pricing", "type": "boolean" }, "secret_key_configured": { "description": "Whether OTARI_SECRET_KEY is set on the server. Provider credentials are encrypted at rest with it, so the dashboard disables adding stored providers when it is unset.", "title": "Secret Key Configured", "type": "boolean" }, "version": { "title": "Version", "type": "string" } }, "required": [ "mode", "version", "model_discovery", "default_pricing", "require_pricing", "master_key_source", "secret_key_configured", "config" ], "title": "GatewaySettings", "type": "object" }, "GuardrailConfig": { "description": "A single guardrail check the caller wants the gateway to enforce.\n\nURL safety: when ``url`` is supplied it is validated by\n:func:`gateway.services.guardrails.run_input_guardrails` (not here at parse\ntime \u2014 the check does a DNS lookup that must be awaited) with the same\nSSRF guard used for MCP server URLs (loopback allowed by default for\nsame-host sidecars; gated by ``OTARI_MCP_ALLOW_LOOPBACK`` /\n``OTARI_MCP_ALLOW_PRIVATE_HOSTS``). Most deployments omit ``url`` and rely\non the operator-set ``OTARI_GUARDRAILS_URL`` instead.", "properties": { "mode": { "default": "monitor", "enum": [ "block", "monitor" ], "title": "Mode", "type": "string" }, "on": { "items": { "enum": [ "input", "output" ], "type": "string" }, "title": "On", "type": "array" }, "profile": { "maxLength": 128, "minLength": 1, "title": "Profile", "type": "string" }, "url": { "anyOf": [ { "minLength": 1, "type": "string" }, { "type": "null" } ], "title": "Url" }, "validate_kwargs": { "additionalProperties": true, "title": "Validate Kwargs", "type": "object" } }, "required": [ "profile" ], "title": "GuardrailConfig", "type": "object" }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "title": "Detail", "type": "array" } }, "title": "HTTPValidationError", "type": "object" }, "ImageGenerationRequest": { "description": "OpenAI-compatible image generation request.\n\nFields are derived from any-llm's ``ImageGenerationParams`` (see\n``_schema_derive``) so the schema cannot silently drop a param any-llm\nforwards.", "properties": { "model": { "title": "Model", "type": "string" }, "n": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "N" }, "prompt": { "title": "Prompt", "type": "string" }, "quality": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Quality" }, "response_format": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Response Format" }, "size": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Size" }, "style": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Style" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "model", "prompt" ], "title": "ImageGenerationRequest", "type": "object" }, "KeyInfo": { "description": "Response model for key information.", "properties": { "allowed_models": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Allowed Models" }, "created_at": { "title": "Created At", "type": "string" }, "exclude_from_budget": { "title": "Exclude From Budget", "type": "boolean" }, "expires_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Expires At" }, "id": { "title": "Id", "type": "string" }, "is_active": { "title": "Is Active", "type": "boolean" }, "key_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Key Name" }, "key_prefix": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Key Prefix" }, "last_used_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last Used At" }, "metadata": { "additionalProperties": true, "title": "Metadata", "type": "object" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "id", "key_prefix", "key_name", "user_id", "created_at", "last_used_at", "expires_at", "is_active", "allowed_models", "exclude_from_budget", "metadata" ], "title": "KeyInfo", "type": "object" }, "KnownProviderSchema": { "description": "A selected provider's autofill hints for the add-provider form.", "properties": { "default_api_base": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Built-in endpoint; blank means the SDK's default.", "title": "Default Api Base" }, "env_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Env var the SDK reads this provider's key from.", "title": "Env Key" }, "env_key_present": { "default": false, "description": "True when env_key is already set on the server, so a pasted key is optional (env fallback).", "title": "Env Key Present", "type": "boolean" }, "id": { "description": "any-llm provider id, used as the default instance name.", "title": "Id", "type": "string" }, "name": { "description": "Human-friendly display name.", "title": "Name", "type": "string" }, "requires_api_key": { "description": "False for keyless local backends (Ollama, llama.cpp).", "title": "Requires Api Key", "type": "boolean" } }, "required": [ "id", "name", "requires_api_key" ], "title": "KnownProviderSchema", "type": "object" }, "KnownProviderSummarySchema": { "description": "A provider offered in the add-provider picker: id and display name only.", "properties": { "id": { "description": "any-llm provider id, used as the default instance name.", "title": "Id", "type": "string" }, "name": { "description": "Human-friendly display name.", "title": "Name", "type": "string" } }, "required": [ "id", "name" ], "title": "KnownProviderSummarySchema", "type": "object" }, "McpServerConfig": { "description": "Inline MCP server configuration accepted on the chat completions request.\n\nStreamable HTTP transport. The `url` must be reachable from the gateway process.\n\nURL safety (SSRF guard against private/link-local/reserved IP ranges, plus\nrejecting plain ``http://`` when ``authorization_token`` is set) is\nenforced by :func:`gateway.services.url_safety.validate_mcp_url`, called\nfrom the async request pipeline (``prepare_gateway_tools``) rather than\nhere at parse time: the safety check does a DNS lookup, which must be\nawaited so it can't block the event loop, and Pydantic validators run\nsynchronously during request-body parsing.", "properties": { "allowed_tools": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Allowed Tools" }, "authorization_token": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Authorization Token" }, "name": { "maxLength": 128, "minLength": 1, "title": "Name", "type": "string" }, "purpose_hint": { "anyOf": [ { "maxLength": 2000, "type": "string" }, { "type": "null" } ], "title": "Purpose Hint" }, "url": { "minLength": 1, "title": "Url", "type": "string" } }, "required": [ "name", "url" ], "title": "McpServerConfig", "type": "object" }, "MessagesRequest": { "description": "Anthropic Messages API-compatible request.\n\nThe wire fields are derived from any-llm's ``MessagesParams`` (see\n``_schema_derive``) so the schema cannot silently drop a param any-llm\nforwards. Gateway-internal fields (``mcp_servers``, ``mcp_server_ids``,\n``guardrails``, ``tools_header``, ``max_tool_iterations``) opt the request\ninto gateway-managed MCP / sandbox / web_search / guardrails without\nchanging the upstream wire shape. They're stripped before the request is\nforwarded.", "properties": { "cache_control": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Cache Control" }, "guardrails": { "anyOf": [ { "items": { "$ref": "#/components/schemas/GuardrailConfig" }, "maxItems": 8, "type": "array" }, { "type": "null" } ], "title": "Guardrails" }, "max_tokens": { "title": "Max Tokens", "type": "integer" }, "max_tool_iterations": { "anyOf": [ { "maximum": 25.0, "minimum": 1.0, "type": "integer" }, { "type": "null" } ], "title": "Max Tool Iterations" }, "mcp_server_ids": { "anyOf": [ { "items": { "format": "uuid", "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Mcp Server Ids" }, "mcp_servers": { "anyOf": [ { "items": { "$ref": "#/components/schemas/McpServerConfig" }, "type": "array" }, { "type": "null" } ], "title": "Mcp Servers" }, "messages": { "items": { "additionalProperties": true, "type": "object" }, "minItems": 1, "title": "Messages", "type": "array" }, "metadata": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Metadata" }, "model": { "title": "Model", "type": "string" }, "output_format": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Output Format" }, "session_label": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "description": "Optional caller-supplied label for cost attribution (per run, experiment, or conversation). In hybrid mode it is forwarded onto the platform usage report so spend can be sliced by session without standing up OpenTelemetry. Stripped before the request is forwarded upstream to the provider. Has no effect in standalone mode, where there is no platform to report it to.", "title": "Session Label" }, "stop_sequences": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Stop Sequences" }, "stream": { "default": false, "title": "Stream", "type": "boolean" }, "system": { "anyOf": [ { "type": "string" }, { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, { "type": "null" } ], "title": "System" }, "temperature": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Temperature" }, "thinking": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Thinking" }, "tool_choice": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Tool Choice" }, "tools": { "anyOf": [ { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, { "type": "null" } ], "title": "Tools" }, "tools_header": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Tools Header" }, "top_k": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Top K" }, "top_p": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Top P" } }, "required": [ "model", "messages", "max_tokens" ], "title": "MessagesRequest", "type": "object" }, "ModelListResponse": { "description": "OpenAI-compatible model list response.", "properties": { "data": { "items": { "$ref": "#/components/schemas/ModelObject" }, "title": "Data", "type": "array" }, "object": { "default": "list", "title": "Object", "type": "string" } }, "required": [ "data" ], "title": "ModelListResponse", "type": "object" }, "ModelMetadata": { "description": "models.dev metadata for one model, for the dashboard's detail view.", "properties": { "attachment": { "default": false, "title": "Attachment", "type": "boolean" }, "context_window": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Context Window" }, "cost_input": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cost Input" }, "cost_output": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cost Output" }, "deprecated": { "default": false, "title": "Deprecated", "type": "boolean" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "family": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Family" }, "input_modalities": { "items": { "type": "string" }, "title": "Input Modalities", "type": "array" }, "knowledge_cutoff": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Knowledge Cutoff" }, "last_updated": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last Updated" }, "max_output_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Max Output Tokens" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" }, "open_weights": { "default": false, "title": "Open Weights", "type": "boolean" }, "output_modalities": { "items": { "type": "string" }, "title": "Output Modalities", "type": "array" }, "reasoning": { "default": false, "title": "Reasoning", "type": "boolean" }, "release_date": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Release Date" }, "structured_output": { "default": false, "title": "Structured Output", "type": "boolean" }, "temperature": { "default": false, "title": "Temperature", "type": "boolean" }, "tool_call": { "default": false, "title": "Tool Call", "type": "boolean" } }, "title": "ModelMetadata", "type": "object" }, "ModelMetadataResponse": { "description": "models.dev metadata keyed by ``provider:model``.", "properties": { "available": { "description": "False when metadata could not be loaded (enrichment disabled or models.dev unreachable).", "title": "Available", "type": "boolean" }, "models": { "additionalProperties": { "$ref": "#/components/schemas/ModelMetadata" }, "title": "Models", "type": "object" }, "source": { "default": "models.dev", "title": "Source", "type": "string" } }, "required": [ "available" ], "title": "ModelMetadataResponse", "type": "object" }, "ModelObject": { "description": "OpenAI-compatible model object.", "properties": { "context_window": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Context Window" }, "created": { "title": "Created", "type": "integer" }, "id": { "title": "Id", "type": "string" }, "object": { "default": "model", "title": "Object", "type": "string" }, "owned_by": { "title": "Owned By", "type": "string" }, "pricing": { "anyOf": [ { "$ref": "#/components/schemas/ModelPricingInfo" }, { "type": "null" } ] }, "pricing_source": { "default": "none", "title": "Pricing Source", "type": "string" } }, "required": [ "id", "created", "owned_by" ], "title": "ModelObject", "type": "object" }, "ModelPricingInfo": { "description": "Pricing information for a model.", "properties": { "cache_read_price_per_million": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cache Read Price Per Million" }, "cache_write_1h_price_per_million": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cache Write 1H Price Per Million" }, "cache_write_price_per_million": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cache Write Price Per Million" }, "input_price_per_million": { "title": "Input Price Per Million", "type": "number" }, "output_price_per_million": { "title": "Output Price Per Million", "type": "number" }, "pricing_tiers": { "items": { "additionalProperties": { "anyOf": [ { "type": "number" }, { "type": "integer" } ] }, "type": "object" }, "title": "Pricing Tiers", "type": "array" } }, "required": [ "input_price_per_million", "output_price_per_million" ], "title": "ModelPricingInfo", "type": "object" }, "ModerationRequest": { "description": "OpenAI-compatible moderation request.", "properties": { "input": { "anyOf": [ { "type": "string" }, { "items": { "type": "string" }, "type": "array" }, { "items": { "additionalProperties": true, "type": "object" }, "type": "array" } ], "description": "Text, list of texts, or list of content-part dicts to moderate", "title": "Input" }, "model": { "title": "Model", "type": "string" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "model", "input" ], "title": "ModerationRequest", "type": "object" }, "ModerationResponse": { "description": "Normalized moderation response across providers.", "properties": { "id": { "title": "Id", "type": "string" }, "model": { "title": "Model", "type": "string" }, "results": { "items": { "$ref": "#/components/schemas/ModerationResult" }, "title": "Results", "type": "array" } }, "required": [ "id", "model", "results" ], "title": "ModerationResponse", "type": "object" }, "ModerationResult": { "description": "A single moderation decision, typically one per input item.", "properties": { "categories": { "additionalProperties": { "type": "boolean" }, "title": "Categories", "type": "object" }, "category_applied_input_types": { "anyOf": [ { "additionalProperties": { "items": { "type": "string" }, "type": "array" }, "type": "object" }, { "type": "null" } ], "title": "Category Applied Input Types" }, "category_scores": { "additionalProperties": { "type": "number" }, "title": "Category Scores", "type": "object" }, "flagged": { "title": "Flagged", "type": "boolean" }, "provider_raw": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Provider Raw" } }, "required": [ "flagged" ], "title": "ModerationResult", "type": "object" }, "PricingRefreshChangeResponse": { "description": "One default model price changed by a pending refresh.", "properties": { "change": { "title": "Change", "type": "string" }, "model_key": { "title": "Model Key", "type": "string" } }, "required": [ "model_key", "change" ], "title": "PricingRefreshChangeResponse", "type": "object" }, "PricingRefreshConfirmationResponse": { "description": "Result of activating a reviewed genai-prices refresh.", "properties": { "applied": { "default": true, "title": "Applied", "type": "boolean" } }, "title": "PricingRefreshConfirmationResponse", "type": "object" }, "PricingRefreshPreviewResponse": { "description": "Reviewable summary of a pending genai-prices refresh.", "properties": { "added_count": { "title": "Added Count", "type": "integer" }, "changed_count": { "title": "Changed Count", "type": "integer" }, "changes": { "items": { "$ref": "#/components/schemas/PricingRefreshChangeResponse" }, "title": "Changes", "type": "array" }, "changes_truncated": { "title": "Changes Truncated", "type": "boolean" }, "fetched_at": { "format": "date-time", "title": "Fetched At", "type": "string" }, "protected_model_count": { "title": "Protected Model Count", "type": "integer" }, "removed_count": { "title": "Removed Count", "type": "integer" } }, "required": [ "fetched_at", "added_count", "changed_count", "removed_count", "protected_model_count", "changes", "changes_truncated" ], "title": "PricingRefreshPreviewResponse", "type": "object" }, "PricingResponse": { "description": "Response model for model pricing.", "properties": { "cache_read_price_per_million": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cache Read Price Per Million" }, "cache_write_1h_price_per_million": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cache Write 1H Price Per Million" }, "cache_write_price_per_million": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cache Write Price Per Million" }, "created_at": { "title": "Created At", "type": "string" }, "effective_at": { "title": "Effective At", "type": "string" }, "input_price_per_million": { "title": "Input Price Per Million", "type": "number" }, "model_key": { "title": "Model Key", "type": "string" }, "output_price_per_million": { "title": "Output Price Per Million", "type": "number" }, "pricing_tiers": { "items": { "$ref": "#/components/schemas/PricingTier" }, "title": "Pricing Tiers", "type": "array" }, "updated_at": { "title": "Updated At", "type": "string" } }, "required": [ "model_key", "effective_at", "input_price_per_million", "output_price_per_million", "cache_read_price_per_million", "cache_write_price_per_million", "cache_write_1h_price_per_million", "pricing_tiers", "created_at", "updated_at" ], "title": "PricingResponse", "type": "object" }, "PricingTier": { "description": "Whole-request price cliff selected by total billable input tokens.", "properties": { "cache_read_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Cache Read Price Per Million" }, "cache_write_1h_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Cache Write 1H Price Per Million" }, "cache_write_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Cache Write Price Per Million" }, "input_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Input Price Per Million" }, "min_input_tokens": { "exclusiveMinimum": 0.0, "title": "Min Input Tokens", "type": "integer" }, "output_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Output Price Per Million" } }, "required": [ "min_input_tokens" ], "title": "PricingTier", "type": "object" }, "ProviderCapabilitiesSchema": { "description": "Curated capability flags for a provider.", "properties": { "audio": { "title": "Audio", "type": "boolean" }, "embeddings": { "title": "Embeddings", "type": "boolean" }, "image_generation": { "title": "Image Generation", "type": "boolean" }, "list_models": { "title": "List Models", "type": "boolean" }, "moderation": { "title": "Moderation", "type": "boolean" }, "pdf": { "title": "Pdf", "type": "boolean" }, "reasoning": { "title": "Reasoning", "type": "boolean" }, "rerank": { "title": "Rerank", "type": "boolean" }, "responses_api": { "title": "Responses Api", "type": "boolean" }, "streaming": { "title": "Streaming", "type": "boolean" }, "vision": { "title": "Vision", "type": "boolean" } }, "required": [ "streaming", "reasoning", "vision", "pdf", "embeddings", "image_generation", "audio", "rerank", "responses_api", "moderation", "list_models" ], "title": "ProviderCapabilitiesSchema", "type": "object" }, "ProviderHealthResponse": { "description": "Provider connectivity across the whole gateway, for the health monitor.\n\nCarries per-provider results plus the ``healthy`` / ``total`` counts and the\nmost recent ``checked_at`` so the overview page can render a summary tile\nwithout re-deriving them.", "properties": { "checked_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 time of the most recent per-provider check (null if none yet).", "title": "Checked At" }, "degraded": { "default": 0, "description": "How many providers are not counted as reachable only because model discovery is unavailable for them. These may still serve requests.", "title": "Degraded", "type": "integer" }, "healthy": { "description": "How many providers are currently reachable.", "title": "Healthy", "type": "integer" }, "providers": { "items": { "$ref": "#/components/schemas/ProviderHealthSchema" }, "title": "Providers", "type": "array" }, "total": { "description": "How many providers are configured.", "title": "Total", "type": "integer" } }, "required": [ "providers", "healthy", "total" ], "title": "ProviderHealthResponse", "type": "object" }, "ProviderHealthSchema": { "description": "One provider instance's reachability, from the model-discovery test path.", "properties": { "checked_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "ISO 8601 wall-clock time the provider's reachability was last checked (null if never).", "title": "Checked At" }, "discovery_unsupported": { "default": false, "description": "True when the check failed only because this backend serves no model-listing endpoint. The provider may still handle requests; only model discovery is unavailable.", "title": "Discovery Unsupported", "type": "boolean" }, "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Sanitized provider error when unreachable.", "title": "Error" }, "instance": { "title": "Instance", "type": "string" }, "model_count": { "description": "Number of models the last successful listing returned.", "title": "Model Count", "type": "integer" }, "ok": { "description": "True when the provider's credentials could list models.", "title": "Ok", "type": "boolean" } }, "required": [ "instance", "ok", "model_count" ], "title": "ProviderHealthSchema", "type": "object" }, "ProviderInfoSchema": { "description": "Static, network-free metadata for one configured provider instance.", "properties": { "capabilities": { "$ref": "#/components/schemas/ProviderCapabilitiesSchema" }, "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "doc_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Doc Url" }, "env_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Env var the credential is read from.", "title": "Env Key" }, "instance": { "description": "Configured provider key (may differ from the type).", "title": "Instance", "type": "string" }, "name": { "description": "Human-friendly provider name.", "title": "Name", "type": "string" }, "pricing_urls": { "items": { "type": "string" }, "title": "Pricing Urls", "type": "array" }, "provider_type": { "description": "Underlying any-llm provider type.", "title": "Provider Type", "type": "string" } }, "required": [ "instance", "provider_type", "name", "capabilities" ], "title": "ProviderInfoSchema", "type": "object" }, "ProvidersResponse": { "description": "Metadata for every configured provider.", "properties": { "providers": { "items": { "$ref": "#/components/schemas/ProviderInfoSchema" }, "title": "Providers", "type": "array" } }, "required": [ "providers" ], "title": "ProvidersResponse", "type": "object" }, "ReencryptProviderCredentialsResponse": { "description": "Result of re-encrypting stored provider keys with the primary secret key.", "properties": { "reencrypted": { "description": "Number of stored provider keys re-encrypted.", "title": "Reencrypted", "type": "integer" }, "unreadable": { "description": "Number of encrypted keys left untouched because they could not be decrypted.", "title": "Unreadable", "type": "integer" } }, "required": [ "reencrypted", "unreadable" ], "title": "ReencryptProviderCredentialsResponse", "type": "object" }, "RerankRequest": { "description": "Rerank request.", "properties": { "documents": { "description": "List of document strings to rerank", "items": { "type": "string" }, "minItems": 1, "title": "Documents", "type": "array" }, "max_tokens_per_doc": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "integer" }, { "type": "null" } ], "description": "Per-document truncation limit", "title": "Max Tokens Per Doc" }, "model": { "description": "Provider-prefixed model ID, e.g. 'cohere:rerank-v3.5'", "title": "Model", "type": "string" }, "query": { "description": "The search query to rerank documents against", "title": "Query", "type": "string" }, "top_n": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "integer" }, { "type": "null" } ], "description": "Maximum number of results to return", "title": "Top N" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "User ID for usage attribution", "title": "User" } }, "required": [ "model", "query", "documents" ], "title": "RerankRequest", "type": "object" }, "ResponsesRequest": { "additionalProperties": true, "description": "OpenAI Responses API-compatible request.\n\nThe wire fields are derived from any-llm's ``ResponsesParams`` (see\n``_schema_derive``) so the schema cannot silently drop a param any-llm\nforwards. Gateway-internal fields (``mcp_servers``, ``mcp_server_ids``,\n``guardrails``, ``tools_header``, ``max_tool_iterations``) opt the request\ninto gateway-managed MCP / sandbox / web_search / guardrails without\nchanging the upstream wire shape. They're stripped before the request is\nforwarded.", "properties": { "background": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Background" }, "conversation": { "anyOf": [ { "type": "string" }, { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Conversation" }, "frequency_penalty": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Frequency Penalty" }, "guardrails": { "anyOf": [ { "items": { "$ref": "#/components/schemas/GuardrailConfig" }, "maxItems": 8, "type": "array" }, { "type": "null" } ], "title": "Guardrails" }, "include": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Include" }, "input": { "title": "Input" }, "instructions": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Instructions" }, "max_output_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Max Output Tokens" }, "max_tool_calls": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Max Tool Calls" }, "max_tool_iterations": { "anyOf": [ { "maximum": 25.0, "minimum": 1.0, "type": "integer" }, { "type": "null" } ], "title": "Max Tool Iterations" }, "mcp_server_ids": { "anyOf": [ { "items": { "format": "uuid", "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Mcp Server Ids" }, "mcp_servers": { "anyOf": [ { "items": { "$ref": "#/components/schemas/McpServerConfig" }, "type": "array" }, { "type": "null" } ], "title": "Mcp Servers" }, "metadata": { "anyOf": [ { "additionalProperties": { "type": "string" }, "type": "object" }, { "type": "null" } ], "title": "Metadata" }, "model": { "title": "Model", "type": "string" }, "parallel_tool_calls": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Parallel Tool Calls" }, "presence_penalty": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Presence Penalty" }, "previous_response_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Previous Response Id" }, "prompt_cache_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Prompt Cache Key" }, "prompt_cache_retention": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Prompt Cache Retention" }, "reasoning": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Reasoning" }, "response_format": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Response Format" }, "safety_identifier": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Safety Identifier" }, "service_tier": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Service Tier" }, "session_label": { "anyOf": [ { "maxLength": 255, "type": "string" }, { "type": "null" } ], "description": "Optional caller-supplied label for cost attribution (per run, experiment, or conversation). In hybrid mode it is forwarded onto the platform usage report so spend can be sliced by session without standing up OpenTelemetry. Stripped before the request is forwarded upstream to the provider. Has no effect in standalone mode, where there is no platform to report it to.", "title": "Session Label" }, "store": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Store" }, "stream": { "default": false, "title": "Stream", "type": "boolean" }, "stream_options": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Stream Options" }, "temperature": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Temperature" }, "text": { "anyOf": [ {}, { "type": "null" } ], "title": "Text" }, "tool_choice": { "anyOf": [ { "type": "string" }, { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Tool Choice" }, "tools": { "anyOf": [ { "items": { "additionalProperties": true, "type": "object" }, "type": "array" }, { "type": "null" } ], "title": "Tools" }, "tools_header": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Tools Header" }, "top_logprobs": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Top Logprobs" }, "top_p": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Top P" }, "truncation": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Truncation" }, "user": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, "required": [ "model", "input" ], "title": "ResponsesRequest", "type": "object" }, "RotateMasterKeyResponse": { "description": "A newly generated dashboard master key, returned once.", "properties": { "master_key": { "description": "The new plaintext master key. Store it now; it is never returned again.", "title": "Master Key", "type": "string" } }, "required": [ "master_key" ], "title": "RotateMasterKeyResponse", "type": "object" }, "SessionResponse": { "description": "A freshly minted dashboard session (the token travels only in the cookie).", "properties": { "expires_at": { "description": "When the session cookie stops being accepted.", "format": "date-time", "title": "Expires At", "type": "string" } }, "required": [ "expires_at" ], "title": "SessionResponse", "type": "object" }, "SetPricingRequest": { "description": "Create a versioned per-model price, with optional cache and context tiers.", "properties": { "cache_read_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "description": "Price per 1M cached-input tokens", "title": "Cache Read Price Per Million" }, "cache_write_1h_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "description": "Price per 1M Anthropic 1-hour cache-write tokens", "title": "Cache Write 1H Price Per Million" }, "cache_write_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "description": "Price per 1M cache-write (creation) tokens", "title": "Cache Write Price Per Million" }, "effective_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "ISO 8601 datetime from which this price applies. Defaults to now if omitted.", "title": "Effective At" }, "input_price_per_million": { "description": "Price per 1M input tokens", "minimum": 0.0, "title": "Input Price Per Million", "type": "number" }, "model_key": { "description": "Model identifier in format 'provider:model'", "title": "Model Key", "type": "string" }, "output_price_per_million": { "description": "Price per 1M output tokens", "minimum": 0.0, "title": "Output Price Per Million", "type": "number" }, "pricing_tiers": { "anyOf": [ { "items": { "$ref": "#/components/schemas/PricingTier" }, "type": "array" }, { "type": "null" } ], "description": "Whole-request context thresholds. Fields omitted by a tier inherit the base rate.", "title": "Pricing Tiers" } }, "required": [ "model_key", "input_price_per_million", "output_price_per_million" ], "title": "SetPricingRequest", "type": "object" }, "StoredProviderResponse": { "description": "A runtime-stored provider. The API key is never returned, only ``last4``.", "properties": { "api_base": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Base" }, "client_args": { "additionalProperties": true, "title": "Client Args", "type": "object" }, "created_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Created At" }, "decryptable": { "default": true, "title": "Decryptable", "type": "boolean" }, "instance": { "title": "Instance", "type": "string" }, "last4": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Last4" }, "provider_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Provider Type" }, "updated_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Updated At" } }, "required": [ "instance" ], "title": "StoredProviderResponse", "type": "object" }, "TestProviderRequest": { "description": "Credentials to test before saving (from the add-provider form).", "properties": { "api_base": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Base" }, "api_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Key" }, "client_args": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Client Args" }, "instance": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Provider/instance name; the impl when no provider_type.", "title": "Instance" }, "provider_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Provider Type" } }, "title": "TestProviderRequest", "type": "object" }, "TestProviderResponse": { "description": "Result of a live provider connection test.", "properties": { "discovery_unsupported": { "default": false, "description": "True when the test failed only because this backend serves no model-listing endpoint, so the credentials could not be verified this way but may still work for requests.", "title": "Discovery Unsupported", "type": "boolean" }, "error": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Error" }, "model_count": { "title": "Model Count", "type": "integer" }, "ok": { "title": "Ok", "type": "boolean" } }, "required": [ "ok", "model_count" ], "title": "TestProviderResponse", "type": "object" }, "TestServiceRequest": { "description": "A (typically unsaved) URL to probe for reachability.", "properties": { "url": { "title": "Url", "type": "string" } }, "required": [ "url" ], "title": "TestServiceRequest", "type": "object" }, "TestServiceResponse": { "properties": { "ok": { "title": "Ok", "type": "boolean" }, "reason": { "title": "Reason", "type": "string" } }, "required": [ "ok", "reason" ], "title": "TestServiceResponse", "type": "object" }, "ToolSettingField": { "description": "One editable tool/guardrail field surfaced to the dashboard.", "properties": { "description": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Description" }, "key": { "title": "Key", "type": "string" }, "service": { "enum": [ "web_search", "sandbox", "guardrails" ], "title": "Service", "type": "string" }, "type": { "enum": [ "url", "str", "int", "bool" ], "title": "Type", "type": "string" }, "value": { "anyOf": [ { "type": "boolean" }, { "type": "integer" }, { "type": "string" }, { "type": "null" } ], "title": "Value" } }, "required": [ "key", "service", "type", "value" ], "title": "ToolSettingField", "type": "object" }, "ToolSettingsResponse": { "description": "The effective value of every editable tool/guardrail field.", "properties": { "fields": { "items": { "$ref": "#/components/schemas/ToolSettingField" }, "title": "Fields", "type": "array" } }, "required": [ "fields" ], "title": "ToolSettingsResponse", "type": "object" }, "UpdateBudgetRequest": { "description": "Request model for updating a budget.", "properties": { "budget_duration_sec": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "integer" }, { "type": "null" } ], "title": "Budget Duration Sec" }, "max_budget": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Max Budget" }, "name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Name" } }, "title": "UpdateBudgetRequest", "type": "object" }, "UpdateKeyRequest": { "description": "Request model for updating a key.", "properties": { "allowed_models": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Allowed Models" }, "exclude_from_budget": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Exclude From Budget" }, "expires_at": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Expires At" }, "is_active": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Is Active" }, "key_name": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Key Name" }, "metadata": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Metadata" } }, "title": "UpdateKeyRequest", "type": "object" }, "UpdateSettingsRequest": { "description": "Change one or more runtime settings. Omitted fields are left unchanged.\n\nOnly the hot-changeable subset is accepted; startup-only fields are not\nsettable over the API (they are display-only in the dashboard).", "properties": { "budget_estimate_default_output_tokens": { "anyOf": [ { "minimum": 0.0, "type": "integer" }, { "type": "null" } ], "title": "Budget Estimate Default Output Tokens" }, "default_pricing": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Default Pricing" }, "file_understanding_enabled": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "File Understanding Enabled" }, "model_cache_ttl_seconds": { "anyOf": [ { "minimum": 0.0, "type": "integer" }, { "type": "null" } ], "title": "Model Cache Ttl Seconds" }, "model_discovery": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Model Discovery" }, "model_discovery_negative_ttl_seconds": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Model Discovery Negative Ttl Seconds" }, "model_discovery_timeout_seconds": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Model Discovery Timeout Seconds" }, "models_dev_cache_ttl_seconds": { "anyOf": [ { "minimum": 0.0, "type": "integer" }, { "type": "null" } ], "title": "Models Dev Cache Ttl Seconds" }, "models_dev_metadata": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Models Dev Metadata" }, "reject_user_mismatch": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Reject User Mismatch" }, "require_pricing": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Require Pricing" }, "stream_missing_usage_policy": { "anyOf": [ { "enum": [ "estimate", "fail", "allow_free" ], "type": "string" }, { "type": "null" } ], "title": "Stream Missing Usage Policy" }, "vision_describe_max_tokens": { "anyOf": [ { "exclusiveMinimum": 0.0, "type": "integer" }, { "type": "null" } ], "title": "Vision Describe Max Tokens" }, "vision_describe_model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Vision Describe Model" }, "vision_strategy": { "anyOf": [ { "enum": [ "describe", "ocr", "off" ], "type": "string" }, { "type": "null" } ], "title": "Vision Strategy" } }, "title": "UpdateSettingsRequest", "type": "object" }, "UpdateStoredProviderRequest": { "description": "Update a stored provider. Omitted fields are unchanged; ``api_key`` rotates in place.", "properties": { "api_base": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Base" }, "api_key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "New API key. Omit to keep the existing one. Never returned.", "title": "Api Key" }, "client_args": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Client Args" }, "expected_updated_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Optimistic concurrency: if set, the update 412s unless it matches the stored updated_at.", "title": "Expected Updated At" }, "provider_type": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Provider Type" } }, "title": "UpdateStoredProviderRequest", "type": "object" }, "UpdateToolSettingsRequest": { "description": "Change one or more tool settings. Omitted fields are left unchanged; an\nexplicit ``null`` clears a field back to the configured env/YAML default.", "example": { "web_search_max_results": 5, "web_search_url": "http://searxng:8080" }, "properties": { "guardrails_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Guardrails Url" }, "sandbox_purpose_hint": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Sandbox Purpose Hint" }, "sandbox_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Sandbox Url" }, "web_search_engines": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Web Search Engines" }, "web_search_extract": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Web Search Extract" }, "web_search_max_results": { "anyOf": [ { "minimum": 1.0, "type": "integer" }, { "type": "null" } ], "title": "Web Search Max Results" }, "web_search_purpose_hint": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Web Search Purpose Hint" }, "web_search_url": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Web Search Url" } }, "title": "UpdateToolSettingsRequest", "type": "object" }, "UpdateUserRequest": { "description": "Request model for updating a user.", "properties": { "alias": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Alias" }, "allowed_models": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Allowed Models" }, "blocked": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Blocked" }, "budget_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Budget Id" }, "metadata": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Metadata" } }, "title": "UpdateUserRequest", "type": "object" }, "UsageCount": { "description": "Total number of usage logs matching a set of filters.", "properties": { "total": { "title": "Total", "type": "integer" } }, "required": [ "total" ], "title": "UsageCount", "type": "object" }, "UsageDeleteRequest": { "description": "Selection of imported usage rows to delete.", "properties": { "api_key_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Key Id" }, "by_filter": { "default": false, "title": "By Filter", "type": "boolean" }, "end_date": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "End Date" }, "endpoint": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Endpoint" }, "ids": { "anyOf": [ { "items": { "type": "string" }, "maxItems": 1000, "type": "array" }, { "type": "null" } ], "title": "Ids" }, "model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Model" }, "priced": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Priced" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Source" }, "start_date": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Start Date" }, "status": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Status" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "title": "UsageDeleteRequest", "type": "object" }, "UsageDeleteResult": { "description": "How many imported rows the delete removed.", "properties": { "deleted": { "default": 0, "title": "Deleted", "type": "integer" } }, "title": "UsageDeleteResult", "type": "object" }, "UsageEntry": { "description": "A single usage log entry.", "properties": { "api_key_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Key Id" }, "billing_meters": { "anyOf": [ { "additionalProperties": true, "type": "object" }, { "type": "null" } ], "title": "Billing Meters" }, "cache_read_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Cache Read Tokens" }, "cache_write_1h_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Cache Write 1H Tokens" }, "cache_write_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Cache Write Tokens" }, "completion_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Completion Tokens" }, "cost": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cost" }, "counts_toward_budget": { "title": "Counts Toward Budget", "type": "boolean" }, "endpoint": { "title": "Endpoint", "type": "string" }, "error_message": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Error Message" }, "id": { "title": "Id", "type": "string" }, "latency_ms": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Latency Ms" }, "model": { "title": "Model", "type": "string" }, "pricing_breakdown": { "anyOf": [ { "items": { "additionalProperties": { "anyOf": [ { "type": "number" }, { "type": "integer" }, { "type": "string" } ] }, "type": "object" }, "type": "array" }, { "type": "null" } ], "title": "Pricing Breakdown" }, "prompt_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Prompt Tokens" }, "provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Provider" }, "source": { "title": "Source", "type": "string" }, "source_label": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Source Label" }, "status": { "title": "Status", "type": "string" }, "timestamp": { "title": "Timestamp", "type": "string" }, "total_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Total Tokens" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "id", "user_id", "api_key_id", "timestamp", "model", "provider", "endpoint", "prompt_tokens", "completion_tokens", "total_tokens", "cache_read_tokens", "cache_write_tokens", "cache_write_1h_tokens", "billing_meters", "pricing_breakdown", "cost", "status", "error_message", "latency_ms", "source", "source_label", "counts_toward_budget" ], "title": "UsageEntry", "type": "object" }, "UsageGroupRow": { "description": "One breakdown row (a model, a user, or an API key).\n\n``key`` is None both for the synthesized fold row (``is_other=True``) and for a\nreal group whose column was NULL (e.g. usage from a since-deleted user, with\n``is_other=False``). ``is_other`` disambiguates the two so the UI does not\nmislabel deleted-user usage as the fold.", "properties": { "cost": { "title": "Cost", "type": "number" }, "is_other": { "default": false, "title": "Is Other", "type": "boolean" }, "key": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Key" }, "requests": { "title": "Requests", "type": "integer" }, "tokens": { "title": "Tokens", "type": "integer" } }, "required": [ "key", "cost", "tokens", "requests" ], "title": "UsageGroupRow", "type": "object" }, "UsageLogResponse": { "description": "Response model for usage log.", "properties": { "api_key_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Key Id" }, "completion_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Completion Tokens" }, "cost": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Cost" }, "endpoint": { "title": "Endpoint", "type": "string" }, "error_message": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Error Message" }, "id": { "title": "Id", "type": "string" }, "latency_ms": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Latency Ms" }, "model": { "title": "Model", "type": "string" }, "prompt_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Prompt Tokens" }, "provider": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Provider" }, "status": { "title": "Status", "type": "string" }, "timestamp": { "title": "Timestamp", "type": "string" }, "total_tokens": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Total Tokens" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "id", "user_id", "api_key_id", "timestamp", "model", "provider", "endpoint", "prompt_tokens", "completion_tokens", "total_tokens", "cost", "status", "error_message", "latency_ms" ], "title": "UsageLogResponse", "type": "object" }, "UsageSeriesPoint": { "description": "One time bucket. ``bucket_start`` is canonical ISO-8601 UTC (``...Z``),\nidentical across SQLite and PostgreSQL for the same underlying instant.", "properties": { "bucket_start": { "title": "Bucket Start", "type": "string" }, "cost": { "title": "Cost", "type": "number" }, "requests": { "title": "Requests", "type": "integer" }, "tokens": { "title": "Tokens", "type": "integer" } }, "required": [ "bucket_start", "cost", "tokens", "requests" ], "title": "UsageSeriesPoint", "type": "object" }, "UsageSetPriceRequest": { "description": "Selection of imported usage rows plus the manual per-1M rates to price them at.\n\n``input`` and ``output`` are required (every row is charged for them); the cache\nrates are optional and, when omitted, those tokens fold into the fresh-input charge\nexactly as an unpriced cache rate does in normal metered pricing.", "properties": { "api_key_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Api Key Id" }, "by_filter": { "default": false, "title": "By Filter", "type": "boolean" }, "cache_read_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Cache Read Price Per Million" }, "cache_write_price_per_million": { "anyOf": [ { "minimum": 0.0, "type": "number" }, { "type": "null" } ], "title": "Cache Write Price Per Million" }, "end_date": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "End Date" }, "endpoint": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Endpoint" }, "ids": { "anyOf": [ { "items": { "type": "string" }, "maxItems": 1000, "type": "array" }, { "type": "null" } ], "title": "Ids" }, "input_price_per_million": { "minimum": 0.0, "title": "Input Price Per Million", "type": "number" }, "model": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Model" }, "output_price_per_million": { "minimum": 0.0, "title": "Output Price Per Million", "type": "number" }, "priced": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "title": "Priced" }, "source": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Source" }, "start_date": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "title": "Start Date" }, "status": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Status" }, "user_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User Id" } }, "required": [ "input_price_per_million", "output_price_per_million" ], "title": "UsageSetPriceRequest", "type": "object" }, "UsageSetPriceResult": { "description": "Outcome of a manual repricing pass.\n\n``matched`` imported rows were recomputed; ``updated`` had their stored cost\nchanged and ``unchanged`` already matched the recomputed value.", "properties": { "matched": { "default": 0, "title": "Matched", "type": "integer" }, "unchanged": { "default": 0, "title": "Unchanged", "type": "integer" }, "updated": { "default": 0, "title": "Updated", "type": "integer" } }, "title": "UsageSetPriceResult", "type": "object" }, "UsageSummary": { "description": "Aggregate spend/volume for the Usage & analytics page.", "properties": { "bucket": { "enum": [ "hour", "day" ], "title": "Bucket", "type": "string" }, "by_api_key": { "items": { "$ref": "#/components/schemas/UsageGroupRow" }, "title": "By Api Key", "type": "array" }, "by_model": { "items": { "$ref": "#/components/schemas/UsageGroupRow" }, "title": "By Model", "type": "array" }, "by_source": { "items": { "$ref": "#/components/schemas/UsageGroupRow" }, "title": "By Source", "type": "array" }, "by_user": { "items": { "$ref": "#/components/schemas/UsageGroupRow" }, "title": "By User", "type": "array" }, "end_date": { "title": "End Date", "type": "string" }, "series": { "items": { "$ref": "#/components/schemas/UsageSeriesPoint" }, "title": "Series", "type": "array" }, "start_date": { "title": "Start Date", "type": "string" }, "totals": { "$ref": "#/components/schemas/UsageTotals" } }, "required": [ "start_date", "end_date", "bucket", "totals", "by_model", "by_user", "by_api_key", "by_source", "series" ], "title": "UsageSummary", "type": "object" }, "UsageTotals": { "description": "Grand totals over the filtered window.", "properties": { "avg_latency_ms": { "anyOf": [ { "type": "number" }, { "type": "null" } ], "title": "Avg Latency Ms" }, "cache_read_tokens": { "title": "Cache Read Tokens", "type": "integer" }, "cache_write_1h_tokens": { "title": "Cache Write 1H Tokens", "type": "integer" }, "cache_write_tokens": { "title": "Cache Write Tokens", "type": "integer" }, "completion_tokens": { "title": "Completion Tokens", "type": "integer" }, "cost": { "title": "Cost", "type": "number" }, "error_count": { "title": "Error Count", "type": "integer" }, "prompt_tokens": { "title": "Prompt Tokens", "type": "integer" }, "request_count": { "title": "Request Count", "type": "integer" }, "total_tokens": { "title": "Total Tokens", "type": "integer" }, "unpriced_requests": { "default": 0, "title": "Unpriced Requests", "type": "integer" } }, "required": [ "cost", "prompt_tokens", "completion_tokens", "total_tokens", "cache_read_tokens", "cache_write_tokens", "cache_write_1h_tokens", "request_count", "error_count", "avg_latency_ms" ], "title": "UsageTotals", "type": "object" }, "UserResponse": { "description": "Response model for user information.", "properties": { "alias": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Alias" }, "allowed_models": { "anyOf": [ { "items": { "type": "string" }, "type": "array" }, { "type": "null" } ], "title": "Allowed Models" }, "blocked": { "title": "Blocked", "type": "boolean" }, "budget_id": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Budget Id" }, "budget_started_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Budget Started At" }, "created_at": { "title": "Created At", "type": "string" }, "metadata": { "additionalProperties": true, "title": "Metadata", "type": "object" }, "next_budget_reset_at": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Next Budget Reset At" }, "reserved": { "title": "Reserved", "type": "number" }, "spend": { "title": "Spend", "type": "number" }, "updated_at": { "title": "Updated At", "type": "string" }, "user_id": { "title": "User Id", "type": "string" } }, "required": [ "user_id", "alias", "spend", "reserved", "budget_id", "allowed_models", "budget_started_at", "next_budget_reset_at", "blocked", "created_at", "updated_at", "metadata" ], "title": "UserResponse", "type": "object" }, "ValidationError": { "properties": { "ctx": { "title": "Context", "type": "object" }, "input": { "title": "Input" }, "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "title": "Location", "type": "array" }, "msg": { "title": "Message", "type": "string" }, "type": { "title": "Error Type", "type": "string" } }, "required": [ "loc", "msg", "type" ], "title": "ValidationError", "type": "object" } }, "securitySchemes": { "ApiKeyAuth": { "description": "Enter your API key here (sent as Otari-Key header).", "in": "header", "name": "Otari-Key", "type": "apiKey" }, "XApiKeyAuth": { "description": "Anthropic-native clients send credentials here (no Bearer prefix).", "in": "header", "name": "x-api-key", "type": "apiKey" } } }, "info": { "description": "Otari, an OpenAI-compatible LLM gateway with API key management", "title": "otari", "version": "0.0.0-dev" }, "openapi": "3.1.0", "paths": { "/health": { "get": { "description": "General health check endpoint.\n\nReturns basic health status. For infrastructure monitoring,\nuse /health/readiness or /health/liveness instead.", "operationId": "health_check_health_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": { "type": "string" }, "title": "Response Health Check Health Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "Health Check", "tags": [ "health" ] } }, "/health/liveness": { "get": { "description": "Liveness probe endpoint.\n\nSimple check to verify the process is alive and responding.\nUsed by Kubernetes/container orchestrators for liveness probes.\n\nReturns:\n Plain text \"I'm alive!\" message", "operationId": "health_liveness_health_liveness_get", "responses": { "200": { "content": { "application/json": { "schema": { "title": "Response Health Liveness Health Liveness Get", "type": "string" } } }, "description": "Successful Response" } }, "summary": "Health Liveness", "tags": [ "health" ] } }, "/health/readiness": { "get": { "description": "Readiness probe endpoint.\n\nChecks if the gateway is ready to serve requests by validating:\n- Database connectivity\n- Service availability\n\nUsed by Kubernetes/container orchestrators for readiness probes.\nReturns HTTP 503 if any dependency is unavailable.\n\nReturns:\n dict: Status object with health details\n\nRaises:\n HTTPException: 503 if service is not ready", "operationId": "health_readiness_health_readiness_get", "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Health Readiness Health Readiness Get", "type": "object" } } }, "description": "Successful Response" } }, "summary": "Health Readiness", "tags": [ "health" ] } }, "/v1/aliases": { "get": { "description": "List every alias in force, from config.yml and from storage.\n\nEvery scope at once, global and user-scoped alike: this is the master-key\nmanagement view, not what any one caller resolves.", "operationId": "list_aliases_v1_aliases_get", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/AliasResponse" }, "title": "Response List Aliases V1 Aliases Get", "type": "array" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Aliases", "tags": [ "aliases" ] }, "post": { "description": "Create or update a stored alias, global or scoped to one user.", "operationId": "set_alias_v1_aliases_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AliasRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AliasResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Set Alias", "tags": [ "aliases" ] } }, "/v1/aliases/{name}": { "delete": { "description": "Delete a stored alias in one scope.\n\nScoped by ``user_id`` for the same reason the upsert is: deleting the global\nalias must not take a user's override with it, and deleting an override must\nleave the global one serving everyone else.", "operationId": "delete_alias_v1_aliases__name__delete", "parameters": [ { "in": "path", "name": "name", "required": true, "schema": { "title": "Name", "type": "string" } }, { "description": "Delete the alias scoped to this user. Omit to delete the global alias of that name.", "in": "query", "name": "user_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Delete the alias scoped to this user. Omit to delete the global alias of that name.", "title": "User Id" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete Alias", "tags": [ "aliases" ] } }, "/v1/audio/speech": { "post": { "description": "OpenAI-compatible audio speech (TTS) endpoint.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "create_speech_v1_audio_speech_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AudioSpeechRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} }, "audio/L16": { "schema": { "format": "binary", "type": "string" } }, "audio/aac": { "schema": { "format": "binary", "type": "string" } }, "audio/flac": { "schema": { "format": "binary", "type": "string" } }, "audio/mpeg": { "schema": { "format": "binary", "type": "string" } }, "audio/opus": { "schema": { "format": "binary", "type": "string" } }, "audio/wav": { "schema": { "format": "binary", "type": "string" } } }, "description": "Audio bytes in the requested format" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Speech", "tags": [ "audio" ] } }, "/v1/audio/transcriptions": { "post": { "description": "OpenAI-compatible audio transcription endpoint.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "create_transcription_v1_audio_transcriptions_post", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_create_transcription_v1_audio_transcriptions_post" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Transcription", "tags": [ "audio" ] } }, "/v1/auth/session": { "delete": { "description": "Sign out: revoke the cookie's session server-side and expire the cookie.\n\nDeliberately unauthenticated and idempotent: it only ever revokes the\nsession named by the caller's own cookie, and the dashboard calls it on the\n401-bounce path where no valid credential exists anymore. Unlike the read\npath in ``deps.py`` it applies no Sec-Fetch-Site check: ``SameSite=Strict``\nalready keeps cross-site requests from carrying the cookie, and the worst a\nforged call could do is sign the operator out.", "operationId": "delete_session_v1_auth_session_delete", "responses": { "204": { "description": "Successful Response" } }, "summary": "Delete Session", "tags": [ "auth" ] }, "post": { "description": "Verify the master key and set the HttpOnly session cookie.\n\nThe rate-limit check deliberately runs only after a failed verification,\nnot before it: a pre-verification gate can't know whether *this* attempt\nwould have succeeded, so once an IP has used up its failure quota it\nwould end up blocking that IP's legitimate owner too, not just further\nattackers. The issue this implements explicitly rules that out. The\nDB/hash lookup this exposes to repeated attempts only runs when no fixed\nmaster_key is configured (the auto-generated bootstrap-key path); with a\nconfigured master_key, verification is a constant-time string compare,\nnot a DB round trip.", "operationId": "create_session_v1_auth_session_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateSessionRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "summary": "Create Session", "tags": [ "auth" ] } }, "/v1/batches": { "get": { "description": "List batches for a provider.\n\nNon-master keys only see batches they own (plus legacy batches without an\nownership marker); the page is filtered after the provider call, so a page\nmay contain fewer than ``limit`` items.", "operationId": "list_batches_v1_batches_get", "parameters": [ { "in": "query", "name": "provider", "required": true, "schema": { "title": "Provider", "type": "string" } }, { "in": "query", "name": "after", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "After" } }, { "in": "query", "name": "limit", "required": false, "schema": { "anyOf": [ { "type": "integer" }, { "type": "null" } ], "title": "Limit" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Batches", "tags": [ "batches" ] }, "post": { "description": "Create a batch of LLM requests for asynchronous processing.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "create_batch_v1_batches_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBatchRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Batch", "tags": [ "batches" ] } }, "/v1/batches/{batch_id}": { "get": { "description": "Retrieve the status of a batch.", "operationId": "retrieve_batch_v1_batches__batch_id__get", "parameters": [ { "in": "path", "name": "batch_id", "required": true, "schema": { "title": "Batch Id", "type": "string" } }, { "in": "query", "name": "provider", "required": true, "schema": { "title": "Provider", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Retrieve Batch", "tags": [ "batches" ] } }, "/v1/batches/{batch_id}/cancel": { "post": { "description": "Cancel a batch.", "operationId": "cancel_batch_v1_batches__batch_id__cancel_post", "parameters": [ { "in": "path", "name": "batch_id", "required": true, "schema": { "title": "Batch Id", "type": "string" } }, { "in": "query", "name": "provider", "required": true, "schema": { "title": "Provider", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Cancel Batch", "tags": [ "batches" ] } }, "/v1/batches/{batch_id}/results": { "get": { "description": "Retrieve the results of a completed batch.", "operationId": "retrieve_batch_results_v1_batches__batch_id__results_get", "parameters": [ { "in": "path", "name": "batch_id", "required": true, "schema": { "title": "Batch Id", "type": "string" } }, { "in": "query", "name": "provider", "required": true, "schema": { "title": "Provider", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "409": { "description": "Batch is not yet complete" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" }, "502": { "description": "LLM provider error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Retrieve Batch Results", "tags": [ "batches" ] } }, "/v1/budgets": { "get": { "description": "List all budgets with pagination.", "operationId": "list_budgets_v1_budgets_get", "parameters": [ { "in": "query", "name": "skip", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Skip", "type": "integer" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/BudgetResponse" }, "title": "Response List Budgets V1 Budgets Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Budgets", "tags": [ "budgets" ] }, "post": { "description": "Create a new budget.", "operationId": "create_budget_v1_budgets_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateBudgetRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BudgetResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Budget", "tags": [ "budgets" ] } }, "/v1/budgets/{budget_id}": { "delete": { "description": "Delete a budget.", "operationId": "delete_budget_v1_budgets__budget_id__delete", "parameters": [ { "in": "path", "name": "budget_id", "required": true, "schema": { "title": "Budget Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete Budget", "tags": [ "budgets" ] }, "get": { "description": "Get details of a specific budget.", "operationId": "get_budget_v1_budgets__budget_id__get", "parameters": [ { "in": "path", "name": "budget_id", "required": true, "schema": { "title": "Budget Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BudgetResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get Budget", "tags": [ "budgets" ] }, "patch": { "description": "Update a budget.", "operationId": "update_budget_v1_budgets__budget_id__patch", "parameters": [ { "in": "path", "name": "budget_id", "required": true, "schema": { "title": "Budget Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateBudgetRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BudgetResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Update Budget", "tags": [ "budgets" ] } }, "/v1/budgets/{budget_id}/reset-logs": { "get": { "description": "List per-user reset events for a budget, newest first.", "operationId": "list_budget_reset_logs_v1_budgets__budget_id__reset_logs_get", "parameters": [ { "in": "path", "name": "budget_id", "required": true, "schema": { "title": "Budget Id", "type": "string" } }, { "in": "query", "name": "skip", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Skip", "type": "integer" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/BudgetResetLogResponse" }, "title": "Response List Budget Reset Logs V1 Budgets Budget Id Reset Logs Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Budget Reset Logs", "tags": [ "budgets" ] } }, "/v1/chat/completions": { "post": { "description": "OpenAI-compatible chat completions endpoint.\n\nSupports both streaming and non-streaming responses.\nHandles reasoning content from otari providers.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "chat_completions_v1_chat_completions_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ChatCompletionRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Chat Completions", "tags": [ "chat" ] } }, "/v1/embeddings": { "post": { "description": "OpenAI-compatible embeddings endpoint.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "create_embedding_v1_embeddings_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/EmbeddingRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Embedding", "tags": [ "embeddings" ] } }, "/v1/files": { "get": { "description": "List the authenticated user's uploaded files.", "operationId": "list_files_v1_files_get", "parameters": [ { "in": "query", "name": "user", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } }, { "in": "query", "name": "purpose", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "Purpose" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response List Files V1 Files Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Files", "tags": [ "files" ] }, "post": { "description": "OpenAI-compatible file upload endpoint.", "operationId": "create_file_v1_files_post", "requestBody": { "content": { "multipart/form-data": { "schema": { "$ref": "#/components/schemas/Body_create_file_v1_files_post" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Create File V1 Files Post", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create File", "tags": [ "files" ] } }, "/v1/files/{file_id}": { "delete": { "description": "Soft-delete a file's metadata and remove its bytes from the backend.", "operationId": "delete_file_v1_files__file_id__delete", "parameters": [ { "in": "path", "name": "file_id", "required": true, "schema": { "title": "File Id", "type": "string" } }, { "in": "query", "name": "user", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Delete File V1 Files File Id Delete", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete File", "tags": [ "files" ] }, "get": { "description": "Retrieve metadata for a single file.", "operationId": "get_file_v1_files__file_id__get", "parameters": [ { "in": "path", "name": "file_id", "required": true, "schema": { "title": "File Id", "type": "string" } }, { "in": "query", "name": "user", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "additionalProperties": true, "title": "Response Get File V1 Files File Id Get", "type": "object" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get File", "tags": [ "files" ] } }, "/v1/files/{file_id}/content": { "get": { "description": "Download the raw bytes of a file, streamed rather than buffered whole.", "operationId": "get_file_content_v1_files__file_id__content_get", "parameters": [ { "in": "path", "name": "file_id", "required": true, "schema": { "title": "File Id", "type": "string" } }, { "in": "query", "name": "user", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "User" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get File Content", "tags": [ "files" ] } }, "/v1/images/generations": { "post": { "description": "OpenAI-compatible image generation endpoint.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "create_image_v1_images_generations_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ImageGenerationRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Image", "tags": [ "images" ] } }, "/v1/keys": { "get": { "description": "List all API keys.\n\nRequires master key authentication.", "operationId": "list_keys_v1_keys_get", "parameters": [ { "in": "query", "name": "skip", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Skip", "type": "integer" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/KeyInfo" }, "title": "Response List Keys V1 Keys Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Keys", "tags": [ "keys" ] }, "post": { "description": "Create a new API key.\n\nRequires master key authentication.\n\nIf user_id is provided, the key will be associated with that user (creates user if it doesn't exist).\nIf user_id is not provided, the key is associated with the shared \"default\" user, which is created\non first use. Keys without an explicit owner therefore share one identity, and so share budget,\nusage, and files.", "operationId": "create_key_v1_keys_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateKeyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateKeyResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Key", "tags": [ "keys" ] } }, "/v1/keys/{key_id}": { "delete": { "description": "Delete (revoke) an API key.\n\nRequires master key authentication.", "operationId": "delete_key_v1_keys__key_id__delete", "parameters": [ { "in": "path", "name": "key_id", "required": true, "schema": { "title": "Key Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete Key", "tags": [ "keys" ] }, "get": { "description": "Get details of a specific API key.\n\nRequires master key authentication.", "operationId": "get_key_v1_keys__key_id__get", "parameters": [ { "in": "path", "name": "key_id", "required": true, "schema": { "title": "Key Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyInfo" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get Key", "tags": [ "keys" ] }, "patch": { "description": "Update an API key.\n\nRequires master key authentication.", "operationId": "update_key_v1_keys__key_id__patch", "parameters": [ { "in": "path", "name": "key_id", "required": true, "schema": { "title": "Key Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateKeyRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KeyInfo" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Update Key", "tags": [ "keys" ] } }, "/v1/keys/{key_id}/rotate": { "post": { "description": "Rotate an API key's secret in place.\n\nRequires master key authentication.\n\nGenerates a new secret for the same key row (id, user, name, expiry, and\nmetadata are preserved) and returns the new raw key once, using the same\nresponse shape as key creation. The previous secret stops authenticating\nimmediately; there is no grace window.", "operationId": "rotate_key_v1_keys__key_id__rotate_post", "parameters": [ { "in": "path", "name": "key_id", "required": true, "schema": { "title": "Key Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateKeyResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Rotate Key", "tags": [ "keys" ] } }, "/v1/logs": { "post": { "description": "Ingest LLM usage from OTLP log events (Claude Code, Codex, or GenAI logs).", "operationId": "receive_logs_v1_logs_post", "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Receive Logs", "tags": [ "otel" ] } }, "/v1/messages": { "post": { "description": "Anthropic Messages API-compatible endpoint.\n\nSupports MCP tool-use loops, sandboxed code execution, and SearXNG\nweb_search in both standalone mode and hybrid mode. Hybrid-mode requests\nresolve credentials via the platform service and get multi-attempt\nfallback across the resolved route, tool-loop requests included (fallback\napplies up to the pre-lock-in point, same as chat).", "operationId": "create_message_v1_messages_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/MessagesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Message", "tags": [ "messages" ] } }, "/v1/messages/count_tokens": { "post": { "description": "Anthropic ``/v1/messages/count_tokens``-compatible endpoint.\n\nReturns ``{\"input_tokens\": N}`` without contacting an upstream provider:\ncounting is local, so there is no budget reservation, pricing, or usage\nlogging. Authentication mirrors :func:`create_message` \u2014 hybrid mode\nresolves the caller's token against the platform, standalone mode validates\nthe API key \u2014 so the endpoint is not an open token-counting oracle.", "operationId": "count_message_tokens_v1_messages_count_tokens_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountTokensRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CountTokensResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Count Message Tokens", "tags": [ "messages" ] } }, "/v1/models": { "get": { "description": "List all available models.\n\nReturns models auto-discovered from configured providers, enriched with\npricing data from the model_pricing table when available. Models that only\nexist in the pricing table are also included for backward compatibility.", "operationId": "list_models_v1_models_get", "parameters": [ { "description": "Filter models by provider name", "in": "query", "name": "provider", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter models by provider name", "title": "Provider" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelListResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Models", "tags": [ "models" ] } }, "/v1/models/discoverable": { "get": { "description": "List every model the configured provider credentials can reach.\n\nOperator-facing counterpart to GET /v1/models, which serves a curated catalog\nto API callers. This reports each provider separately and keeps its error, so\na provider with a bad key is distinguishable from one with no models. It is\nmaster-key gated because a provider error message describes the gateway's own\nconfiguration.", "operationId": "list_discoverable_models_v1_models_discoverable_get", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/DiscoverableModelsResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Discoverable Models", "tags": [ "models" ] } }, "/v1/models/metadata": { "get": { "description": "Per-model metadata for the dashboard's detail view, from models.dev.\n\nCovers every model models.dev lists under a configured provider, keyed by the\n``instance:model`` selector the dashboard uses. ``available`` is false when\nenrichment is disabled (``models_dev_metadata``) or models.dev could not be\nreached; the response is then empty and the UI falls back to bundled data.\nMaster-key gated: it describes the gateway's configured providers.", "operationId": "list_model_metadata_v1_models_metadata_get", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelMetadataResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Model Metadata", "tags": [ "models" ] } }, "/v1/models/{model_id}": { "get": { "description": "Get details for a specific model.", "operationId": "get_model_v1_models__model_id__get", "parameters": [ { "in": "path", "name": "model_id", "required": true, "schema": { "title": "Model Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModelObject" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get Model", "tags": [ "models" ] } }, "/v1/moderations": { "post": { "description": "OpenAI-compatible moderations endpoint.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "create_moderation_v1_moderations_post", "parameters": [ { "in": "query", "name": "include_raw", "required": false, "schema": { "default": false, "title": "Include Raw", "type": "boolean" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModerationRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ModerationResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Moderation", "tags": [ "moderations" ] } }, "/v1/pricing": { "get": { "description": "List all model pricing.", "operationId": "list_pricing_v1_pricing_get", "parameters": [ { "in": "query", "name": "skip", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Skip", "type": "integer" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/PricingResponse" }, "title": "Response List Pricing V1 Pricing Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Pricing", "tags": [ "pricing" ] }, "post": { "description": "Set or update pricing for a model.\n\nRejects an alias: pricing, budgets, and usage all key on the resolved\ntarget, so a row stored under an alias name would never be read.", "operationId": "set_pricing_v1_pricing_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SetPricingRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PricingResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Set Pricing", "tags": [ "pricing" ] } }, "/v1/pricing/refresh": { "post": { "description": "Fetch the latest defaults and hold them for operator review.", "operationId": "preview_pricing_refresh_v1_pricing_refresh_post", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PricingRefreshPreviewResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Preview Pricing Refresh", "tags": [ "pricing" ] } }, "/v1/pricing/refresh/confirm": { "post": { "description": "Activate the latest reviewed default-price snapshot.", "operationId": "confirm_pricing_refresh_v1_pricing_refresh_confirm_post", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PricingRefreshConfirmationResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Confirm Pricing Refresh", "tags": [ "pricing" ] } }, "/v1/pricing/refresh/reject": { "post": { "description": "Discard a reviewed default-price snapshot without applying it.", "operationId": "reject_pricing_refresh_v1_pricing_refresh_reject_post", "responses": { "204": { "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Reject Pricing Refresh", "tags": [ "pricing" ] } }, "/v1/pricing/{model_key}": { "delete": { "description": "Delete pricing entries for a model.", "operationId": "delete_pricing_v1_pricing__model_key__delete", "parameters": [ { "in": "path", "name": "model_key", "required": true, "schema": { "title": "Model Key", "type": "string" } }, { "description": "ISO datetime identifying a specific pricing row to delete", "in": "query", "name": "effective_at", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "ISO datetime identifying a specific pricing row to delete", "title": "Effective At" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete Pricing", "tags": [ "pricing" ] }, "get": { "description": "Get pricing for a specific model as of a timestamp.", "operationId": "get_pricing_v1_pricing__model_key__get", "parameters": [ { "in": "path", "name": "model_key", "required": true, "schema": { "title": "Model Key", "type": "string" } }, { "description": "ISO datetime for effective lookup", "in": "query", "name": "as_of", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "ISO datetime for effective lookup", "title": "as_of" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PricingResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get Pricing", "tags": [ "pricing" ] } }, "/v1/pricing/{model_key}/history": { "get": { "description": "Return the full pricing history for a model.", "operationId": "get_pricing_history_v1_pricing__model_key__history_get", "parameters": [ { "in": "path", "name": "model_key", "required": true, "schema": { "title": "Model Key", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/PricingResponse" }, "title": "Response Get Pricing History V1 Pricing Model Key History Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get Pricing History", "tags": [ "pricing" ] } }, "/v1/provider-credentials": { "get": { "description": "List runtime-stored providers. Keys are never returned, only ``last4``.", "operationId": "list_stored_providers_v1_provider_credentials_get", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/StoredProviderResponse" }, "title": "Response List Stored Providers V1 Provider Credentials Get", "type": "array" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Stored Providers", "tags": [ "providers" ] }, "post": { "description": "Add a provider at runtime. Storing a key requires OTARI_SECRET_KEY.", "operationId": "create_stored_provider_v1_provider_credentials_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateStoredProviderRequest" } } }, "required": true }, "responses": { "201": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StoredProviderResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Stored Provider", "tags": [ "providers" ] } }, "/v1/provider-credentials/reencrypt": { "post": { "description": "Re-encrypt stored provider keys with the primary OTARI_SECRET_KEY.\n\nOperators rotate ``OTARI_SECRET_KEY`` by setting it to ``new,old`` first,\nrestarting, running this endpoint, then removing the old key and restarting\nagain. Rows that cannot be decrypted are left untouched and must be recovered\nby replacing the affected provider keys.", "operationId": "reencrypt_stored_provider_keys_v1_provider_credentials_reencrypt_post", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ReencryptProviderCredentialsResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Reencrypt Stored Provider Keys", "tags": [ "providers" ] } }, "/v1/provider-credentials/test": { "post": { "description": "Test provider credentials without storing them (for the add/edit form).\n\nResolves the implementation from ``provider_type`` (honoring the\n``*-compatible`` aliases) or the ``instance`` name, then lists the provider's\nmodels with the supplied credentials. Nothing is persisted and the key is\nnever echoed.", "operationId": "test_provider_connection_v1_provider_credentials_test_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestProviderRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestProviderResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Test Provider Connection", "tags": [ "providers" ] } }, "/v1/provider-credentials/{instance}": { "delete": { "description": "Delete a stored provider. A config.yml provider cannot be deleted here.", "operationId": "delete_stored_provider_v1_provider_credentials__instance__delete", "parameters": [ { "in": "path", "name": "instance", "required": true, "schema": { "title": "Instance", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete Stored Provider", "tags": [ "providers" ] }, "patch": { "description": "Update a stored provider. Omitted fields are left as-is; an explicit ``null`` clears them.\n\n``api_key`` follows the same rule: omit it to keep the stored key, send a new\none to rotate, or send ``null`` to clear it. The row is locked ``FOR UPDATE``\nso the ``expected_updated_at`` check and the write it guards are atomic.", "operationId": "update_stored_provider_v1_provider_credentials__instance__patch", "parameters": [ { "in": "path", "name": "instance", "required": true, "schema": { "title": "Instance", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateStoredProviderRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StoredProviderResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Update Stored Provider", "tags": [ "providers" ] } }, "/v1/provider-credentials/{instance}/test": { "post": { "description": "Verify a stored provider's key by listing its models, without exposing the key.", "operationId": "test_stored_provider_v1_provider_credentials__instance__test_post", "parameters": [ { "in": "path", "name": "instance", "required": true, "schema": { "title": "Instance", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestProviderResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Test Stored Provider", "tags": [ "providers" ] } }, "/v1/providers": { "get": { "description": "List static metadata for every configured provider.\n\nOperator-facing: reports each provider's capabilities, documentation and\npricing links, and display name from the bundled any-llm and genai-prices\ndatasets. No provider is contacted, so this is cheap and always available.\nMaster-key gated because it describes the gateway's own configuration.", "operationId": "list_providers_v1_providers_get", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProvidersResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Providers", "tags": [ "providers" ] } }, "/v1/providers/catalog": { "get": { "description": "List every known provider for the add-provider picker: id and name only.\n\nLightweight by design so the picker never lags: provider ids come from the\nany-llm registry and names from the bundled genai-prices dataset, so no\nprovider SDK is imported. The autofill hints for a chosen provider come from\nGET /v1/providers/catalog/{provider_id}, which imports only that one SDK.\nMaster-key gated because it is operator-facing dashboard data.", "operationId": "provider_catalog_v1_providers_catalog_get", "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/KnownProviderSummarySchema" }, "title": "Response Provider Catalog V1 Providers Catalog Get", "type": "array" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Provider Catalog", "tags": [ "providers" ] } }, "/v1/providers/catalog/{provider_id}": { "get": { "description": "Autofill hints for one provider the add-provider form has selected.\n\nImports only the selected provider's any-llm module (not the whole catalog)\nto report its credential env var, default endpoint, whether a key is required,\nand whether that env var is already set on the server. Returns 404 for an\nunknown provider id. Master-key gated because it is operator-facing.\n\nThe SDK import is offloaded to a worker thread: the first fetch for a given\nprovider imports that provider's module, which would otherwise block the event\nloop (and thus every concurrent request) for the import's duration.", "operationId": "provider_catalog_detail_v1_providers_catalog__provider_id__get", "parameters": [ { "in": "path", "name": "provider_id", "required": true, "schema": { "title": "Provider Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/KnownProviderSchema" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Provider Catalog Detail", "tags": [ "providers" ] } }, "/v1/providers/health": { "get": { "description": "Report every configured provider's reachability, with a last-checked time.\n\nReuses the per-provider model-discovery test path, so a provider is healthy\nwhen its credentials can list models. Results are served from the discovery\ncache (cheap enough to poll), so ``checked_at`` reflects when each provider\nwas actually dialed. Pass ``refresh=true`` to force a live re-dial of every\nprovider. Master-key gated because it describes the gateway's own providers.\n\nA provider whose backend serves no model-listing endpoint cannot be verified\nthis way, but it is not unreachable either: it is reported with\n``discovery_unsupported`` and counted under ``degraded`` rather than as a\nreachability failure.", "operationId": "provider_health_v1_providers_health_get", "parameters": [ { "in": "query", "name": "refresh", "required": false, "schema": { "default": false, "title": "Refresh", "type": "boolean" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ProviderHealthResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Provider Health", "tags": [ "providers" ] } }, "/v1/rerank": { "post": { "description": "Rerank documents by relevance to a query.\n\nAuthentication modes:\n- Master key + user field: Use specified user (must exist)\n- API key + user field: Use specified user (must exist)\n- API key without user field: Use the shared \"default\" user", "operationId": "create_rerank_v1_rerank_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RerankRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Rerank", "tags": [ "rerank" ] } }, "/v1/responses": { "post": { "description": "OpenAI-compatible Responses endpoint.\n\nSupports MCP tool-use loops, sandboxed code execution, and SearXNG\nweb_search in both standalone mode and hybrid mode. Hybrid-mode requests\nresolve credentials via the platform service and get multi-attempt\nfallback across the resolved route, tool-loop requests included (fallback\napplies up to the pre-lock-in point, same as chat).", "operationId": "create_response_v1_responses_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ResponsesRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create Response", "tags": [ "responses" ] } }, "/v1/settings": { "get": { "description": "Return non-secret runtime settings for the admin dashboard.", "operationId": "get_settings_v1_settings_get", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GatewaySettings" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get Settings", "tags": [ "settings" ] }, "patch": { "description": "Persist and apply runtime setting changes.\n\nEach provided field is stored as an override (winning over config/env) and\napplied to the running gateway immediately. Master-key gated: these change\nhow the gateway meters and lists models.", "operationId": "update_settings_v1_settings_patch", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateSettingsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/GatewaySettings" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Update Settings", "tags": [ "settings" ] } }, "/v1/settings/master-key/rotate": { "post": { "description": "Regenerate the database-backed master key and invalidate the old one.\n\nOnly the first-run generated master key can be rotated here. When a master\nkey is supplied through config or ``OTARI_MASTER_KEY``, the dashboard cannot\ninvalidate it; the operator must change that value and restart instead.\n\nEvery dashboard session is revoked with the rotation (a session only proves\npossession of the now-dead key); the caller's own session is re-minted under\nthe new key so the tab that performed the rotation stays signed in.", "operationId": "rotate_master_key_v1_settings_master_key_rotate_post", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RotateMasterKeyResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Rotate Master Key", "tags": [ "settings" ] } }, "/v1/tool-settings": { "get": { "description": "Return the effective tool/guardrail settings for the dashboard.", "operationId": "get_tool_settings_v1_tool_settings_get", "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToolSettingsResponse" } } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get Tool Settings", "tags": [ "tool-settings" ] }, "patch": { "description": "Persist and apply tool/guardrail setting changes.\n\nUses ``model_fields_set`` so an explicit ``null`` clears a field while an\nomitted field is left unchanged. Master-key gated and standalone-only.", "operationId": "update_tool_settings_v1_tool_settings_patch", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateToolSettingsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ToolSettingsResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Update Tool Settings", "tags": [ "tool-settings" ] } }, "/v1/tool-settings/{service}/test": { "post": { "description": "Structurally validate a URL and probe it for reachability.\n\nTests the URL in the request body (typically unsaved), so an operator can\nverify before saving. The probe is a plain HTTP GET with a short timeout: any\nHTTP response means the host is reachable; a connection/timeout/DNS error means\nit is not. The operator is trusted (master key), so no SSRF deny-list applies;\nonly the structural check (http/https + host) runs first.", "operationId": "test_service_v1_tool_settings__service__test_post", "parameters": [ { "in": "path", "name": "service", "required": true, "schema": { "title": "Service", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestServiceRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TestServiceResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Test Service", "tags": [ "tool-settings" ] } }, "/v1/traces": { "post": { "description": "Ingest LLM usage from OTLP spans (GenAI semantic conventions).", "operationId": "receive_traces_v1_traces_post", "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Receive Traces", "tags": [ "otel" ] } }, "/v1/usage": { "delete": { "description": "Delete imported usage rows by explicit ids or by filter (standalone).\n\nTarget either the current selection (``ids``) or everything matching a filter\n(``by_filter: true`` plus optional ``source`` / ``model`` / ``user_id`` /\n``status`` / date range / ``priced``). Only imported rows\n(``counts_toward_budget = false``) are ever removed: enforced gateway rows and\nthe spend ledger (``users.spend``) are untouched, so a delete can never desync a\nbudget. Master-key only.", "operationId": "delete_usage_rows_v1_usage_delete", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageDeleteRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageDeleteResult" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete Usage Rows", "tags": [ "usage" ] }, "get": { "description": "List usage logs ordered by timestamp (most recent first).\n\nSupports optional filters for time range, user, status, model, and endpoint.\nPaginated via skip/limit. The return shape is a bare JSON array; external\nbilling/analytics consumers depend on this, so the total row count for a\npaginated UI is served separately by ``GET /v1/usage/count`` rather than\nwrapped in an envelope here. Timestamps accept either ISO 8601 strings or\nUnix epoch seconds (numeric).", "operationId": "list_usage_v1_usage_get", "parameters": [ { "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "start_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "title": "Start Date" } }, { "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "end_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "title": "End Date" } }, { "description": "Filter to a single user", "in": "query", "name": "user_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single user", "title": "User Id" } }, { "description": "Filter to a single status (e.g. 'success' or 'error')", "in": "query", "name": "status", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single status (e.g. 'success' or 'error')", "title": "Status" } }, { "description": "Filter to a single model", "in": "query", "name": "model", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single model", "title": "Model" } }, { "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "in": "query", "name": "endpoint", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "title": "Endpoint" } }, { "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "in": "query", "name": "source", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "title": "Source" } }, { "description": "Filter to a single API key id", "in": "query", "name": "api_key_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single API key id", "title": "Api Key Id" } }, { "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "in": "query", "name": "priced", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "title": "Priced" } }, { "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "in": "query", "name": "counts_toward_budget", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "title": "Counts Toward Budget" } }, { "in": "query", "name": "skip", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Skip", "type": "integer" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/UsageEntry" }, "title": "Response List Usage V1 Usage Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Usage", "tags": [ "usage" ] } }, "/v1/usage/count": { "get": { "description": "Total number of usage logs matching the given filters.\n\nServes the dashboard paginator's \"N of M\" total without changing the bare\narray contract of ``GET /v1/usage``. Runs only when the client asks (a\nseparate request), so the ``COUNT(*)`` is not paid on every page load. With\n``counts_toward_budget=false`` it also backs the \"select all N matching this\nfilter\" affordance for bulk delete / set-price, which touch imported rows only.", "operationId": "count_usage_v1_usage_count_get", "parameters": [ { "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "start_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "title": "Start Date" } }, { "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "end_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "title": "End Date" } }, { "description": "Filter to a single user", "in": "query", "name": "user_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single user", "title": "User Id" } }, { "description": "Filter to a single status (e.g. 'success' or 'error')", "in": "query", "name": "status", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single status (e.g. 'success' or 'error')", "title": "Status" } }, { "description": "Filter to a single model", "in": "query", "name": "model", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single model", "title": "Model" } }, { "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "in": "query", "name": "endpoint", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "title": "Endpoint" } }, { "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "in": "query", "name": "source", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "title": "Source" } }, { "description": "Filter to a single API key id", "in": "query", "name": "api_key_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single API key id", "title": "Api Key Id" } }, { "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "in": "query", "name": "priced", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "title": "Priced" } }, { "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "in": "query", "name": "counts_toward_budget", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "title": "Counts Toward Budget" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageCount" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Count Usage", "tags": [ "usage" ] } }, "/v1/usage/external-events": { "post": { "description": "Ingest a batch of externally-observed usage events (standalone).\n\nAuthenticated with either an API key or the master key. Usage binds to the\nauthenticated principal: an API key attributes to its own user (and stamps its\nid on the rows); the master key may name any user via ``user_id``. Records\nsubscription-backed usage (e.g. Claude Code) as usage-log rows tagged with their\n``source``, priced at the effective API rate for each event's timestamp.\nImported usage is real cost, but never counts toward budgets or mutates\n``users.spend`` (it is retrospective, so it cannot be reserved). Idempotent by\n``(source, source_event_id)``. The payload is content-free; any\nprompt/completion/tool field is rejected (422), not stored.", "operationId": "ingest_external_usage_v1_usage_external_events_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExternalEventsRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ExternalIngestResult" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Ingest External Usage", "tags": [ "usage" ] } }, "/v1/usage/set-price": { "post": { "description": "Set the cost of imported usage rows from manual per-1M rates (standalone).\n\nTarget either the current selection (``ids``) or everything matching a filter\n(``by_filter: true``). Cost / billing meters / pricing breakdown are recomputed\nfrom each row's own token counts at the supplied ``input`` / ``output`` /\n``cache_read`` / ``cache_write`` per-1M rates (manual rates, not a recompute from\nconfigured pricing). Only imported rows (``counts_toward_budget = false``) are\ntouched, so ``users.spend`` is never affected. Master-key only.", "operationId": "set_usage_price_rows_v1_usage_set_price_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageSetPriceRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageSetPriceResult" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Set Usage Price Rows", "tags": [ "usage" ] } }, "/v1/usage/summary": { "get": { "description": "Aggregate spend, tokens, and request volume for the dashboard Usage page.\n\nRange-bounded (default last 30 days, hard-capped): unlike the raw ``/v1/usage``\nlist, every aggregate is scoped to a bounded window so it stays served by the\ntimestamp index. Returns grand totals, breakdowns by model / user / API key\n(top rows plus a reconciling ``other`` fold), and a UTC-bucketed time series.", "operationId": "usage_summary_v1_usage_summary_get", "parameters": [ { "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "start_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "title": "Start Date" } }, { "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "end_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "title": "End Date" } }, { "description": "Filter to a single user", "in": "query", "name": "user_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single user", "title": "User Id" } }, { "description": "Filter to a single status (e.g. 'success' or 'error')", "in": "query", "name": "status", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single status (e.g. 'success' or 'error')", "title": "Status" } }, { "description": "Filter to a single model", "in": "query", "name": "model", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single model", "title": "Model" } }, { "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "in": "query", "name": "endpoint", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "title": "Endpoint" } }, { "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "in": "query", "name": "source", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "title": "Source" } }, { "description": "Filter to a single API key id", "in": "query", "name": "api_key_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single API key id", "title": "Api Key Id" } }, { "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "in": "query", "name": "priced", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "title": "Priced" } }, { "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "in": "query", "name": "counts_toward_budget", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "title": "Counts Toward Budget" } }, { "description": "Time-series granularity: 'hour' or 'day'", "in": "query", "name": "bucket", "required": false, "schema": { "default": "day", "description": "Time-series granularity: 'hour' or 'day'", "enum": [ "hour", "day" ], "title": "Bucket", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UsageSummary" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Usage Summary", "tags": [ "usage" ] } }, "/v1/usage/summary.csv": { "get": { "description": "Download the per-model / per-user / per-key / per-source breakdown as CSV.\n\nA dedicated route rather than a ``format=csv`` flag on ``/summary`` so that\nendpoint keeps a single JSON response model and a clean OpenAPI schema. The\nexport is **uncapped** (no top-N fold): finance wants every row. Kept separate\nfrom the bare-array ``/v1/usage`` contract, which is untouched.", "operationId": "usage_summary_csv_v1_usage_summary_csv_get", "parameters": [ { "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "start_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp >= start_date (ISO 8601 or Unix epoch seconds)", "title": "Start Date" } }, { "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "in": "query", "name": "end_date", "required": false, "schema": { "anyOf": [ { "format": "date-time", "type": "string" }, { "type": "null" } ], "description": "Return logs with timestamp < end_date (ISO 8601 or Unix epoch seconds)", "title": "End Date" } }, { "description": "Filter to a single user", "in": "query", "name": "user_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single user", "title": "User Id" } }, { "description": "Filter to a single status (e.g. 'success' or 'error')", "in": "query", "name": "status", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single status (e.g. 'success' or 'error')", "title": "Status" } }, { "description": "Filter to a single model", "in": "query", "name": "model", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single model", "title": "Model" } }, { "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "in": "query", "name": "endpoint", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single endpoint (e.g. '/v1/chat/completions')", "title": "Endpoint" } }, { "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "in": "query", "name": "source", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single provenance source (e.g. 'gateway' or 'claude_code')", "title": "Source" } }, { "description": "Filter to a single API key id", "in": "query", "name": "api_key_id", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "description": "Filter to a single API key id", "title": "Api Key Id" } }, { "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "in": "query", "name": "priced", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by pricing state: true = only rows with a cost, false = only unpriced rows (cost is null)", "title": "Priced" } }, { "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "in": "query", "name": "counts_toward_budget", "required": false, "schema": { "anyOf": [ { "type": "boolean" }, { "type": "null" } ], "description": "Filter by budget participation: true = only enforced gateway rows, false = only imported rows that never touch a budget", "title": "Counts Toward Budget" } } ], "responses": { "200": { "content": { "application/json": { "schema": {} } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Usage Summary Csv", "tags": [ "usage" ] } }, "/v1/users": { "get": { "description": "List all users with pagination.", "operationId": "list_users_v1_users_get", "parameters": [ { "in": "query", "name": "skip", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Skip", "type": "integer" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/UserResponse" }, "title": "Response List Users V1 Users Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "List Users", "tags": [ "users" ] }, "post": { "description": "Create a new user.", "operationId": "create_user_v1_users_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/CreateUserRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Create User", "tags": [ "users" ] } }, "/v1/users/{user_id}": { "delete": { "description": "Delete a user.", "operationId": "delete_user_v1_users__user_id__delete", "parameters": [ { "in": "path", "name": "user_id", "required": true, "schema": { "title": "User Id", "type": "string" } } ], "responses": { "204": { "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Delete User", "tags": [ "users" ] }, "get": { "description": "Get details of a specific user.", "operationId": "get_user_v1_users__user_id__get", "parameters": [ { "in": "path", "name": "user_id", "required": true, "schema": { "title": "User Id", "type": "string" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get User", "tags": [ "users" ] }, "patch": { "description": "Update a user.", "operationId": "update_user_v1_users__user_id__patch", "parameters": [ { "in": "path", "name": "user_id", "required": true, "schema": { "title": "User Id", "type": "string" } } ], "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UpdateUserRequest" } } }, "required": true }, "responses": { "200": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/UserResponse" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Update User", "tags": [ "users" ] } }, "/v1/users/{user_id}/usage": { "get": { "description": "Get usage history for a specific user.", "operationId": "get_user_usage_v1_users__user_id__usage_get", "parameters": [ { "in": "path", "name": "user_id", "required": true, "schema": { "title": "User Id", "type": "string" } }, { "in": "query", "name": "skip", "required": false, "schema": { "default": 0, "minimum": 0, "title": "Skip", "type": "integer" } }, { "in": "query", "name": "limit", "required": false, "schema": { "default": 100, "maximum": 1000, "minimum": 1, "title": "Limit", "type": "integer" } } ], "responses": { "200": { "content": { "application/json": { "schema": { "items": { "$ref": "#/components/schemas/UsageLogResponse" }, "title": "Response Get User Usage V1 Users User Id Usage Get", "type": "array" } } }, "description": "Successful Response" }, "422": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } }, "description": "Validation Error" } }, "security": [ { "ApiKeyAuth": [] }, { "XApiKeyAuth": [] } ], "summary": "Get User Usage", "tags": [ "users" ] } } } }