openapi: 3.0.0 info: title: LowRouter API version: 1.0.0 description: | OpenAI-compatible API gateway for sustainable AI inference. Routes LLM requests to the provider, model, and region you choose while remaining fully compatible with OpenAI client libraries. # Renders as the "LowRouter Support" contact in Scalar and in any generated # client. Points at the real support surface (#322): /help recaps every # channel — docs, community, email, live chat. The previous contact linked # to a GitHub repo, which was not a support channel at all, and was removed. contact: name: LowRouter Support url: https://lowrouter.ai/help email: support@lowrouter.ai servers: # /v1 is the advertised base URL (api.lowrouter.ai already carries the api. # subdomain, so the /api segment is redundant — issue #313). Absolute so # Scalar "Try it" targets prod. /api/v1 stays as a back-compat alias for # existing integrations. - url: https://api.lowrouter.ai/v1 description: Production API (v1) - url: https://api.lowrouter.ai/api/v1 description: Production API (legacy /api/v1 alias) security: - bearerAuth: [] paths: /chat/completions: post: summary: Create chat completion description: | Creates a chat completion with automatic routing to the most carbon-efficient provider. Fully compatible with OpenAI's chat completions API. operationId: createChatCompletion tags: - Completions requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/ChatCompletionRequest' examples: autoRouted: summary: Auto-routed model (LowRouter picks the route) value: messages: - role: user content: "What is the capital of France?" model: auto/mistralai/mistral-large-2512 stream: false explicitModel: summary: Explicit model selection value: messages: - role: user content: "Write a short poem" model: openai/gpt-4 stream: false withUser: summary: With an end-user identifier for reporting value: messages: - role: user content: "Continue our conversation" model: openai/openai/gpt-4o/global user: user-123 responses: '200': description: Successful completion content: application/json: schema: $ref: '#/components/schemas/ChatCompletionResponse' text/event-stream: schema: type: string description: Server-Sent Events stream '401': $ref: '#/components/responses/UnauthorizedError' '400': $ref: '#/components/responses/BadRequestError' '500': $ref: '#/components/responses/InternalServerError' /completions: post: summary: Create text completion description: | Creates a text completion (legacy endpoint for compatibility). Routes to providers supporting text completion format. operationId: createCompletion tags: - Completions requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/CompletionRequest' examples: simple: summary: Simple completion value: prompt: "Once upon a time" model: openai/gpt-3.5-turbo-instruct max_tokens: 100 responses: '200': description: Successful completion content: application/json: schema: $ref: '#/components/schemas/CompletionResponse' text/event-stream: schema: type: string description: Server-Sent Events stream '401': $ref: '#/components/responses/UnauthorizedError' '400': $ref: '#/components/responses/BadRequestError' '500': $ref: '#/components/responses/InternalServerError' /embeddings: post: summary: Create embeddings description: | Creates an embedding vector representing the input text. Routes to providers supporting embeddings via Bifrost. Applies billing (input tokens only) and carbon tracking. operationId: createEmbedding tags: - Embeddings requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/EmbeddingRequest' examples: simple_string: summary: Single string input value: model: openai/text-embedding-3-small input: "The quick brown fox" array_input: summary: Array of strings value: model: openai/text-embedding-3-small input: ["Hello world", "Goodbye world"] responses: '200': description: Embedding created successfully content: application/json: schema: $ref: '#/components/schemas/EmbeddingResponse' '400': $ref: '#/components/responses/BadRequestError' '401': $ref: '#/components/responses/UnauthorizedError' '402': description: Insufficient credits content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': $ref: '#/components/responses/InternalServerError' /models: get: summary: List available models description: | Returns a list of all available models with their capabilities, pricing, and carbon intensity metrics. The catalogue includes non-chat models (embeddings and similar). Each entry carries a `modality` field saying which interaction mode it serves; filter with `?modality=chat` to list only models callable on `/v1/chat/completions`. operationId: listModels tags: - Models parameters: - $ref: '#/components/parameters/JurisdictionFacet' - $ref: '#/components/parameters/ModalityFilter' responses: '200': description: List of models content: application/json: schema: $ref: '#/components/schemas/ModelsListResponse' '400': $ref: '#/components/responses/BadRequestError' '401': $ref: '#/components/responses/UnauthorizedError' '500': $ref: '#/components/responses/InternalServerError' /models/{model}: get: summary: Retrieve a model description: | Returns details for a single model matching the OpenAI retrieve model format. The model parameter may contain slashes (e.g. nebius/NousResearch/Hermes-4-70B). operationId: getModel tags: - Models parameters: - name: model in: path required: true description: The model ID to retrieve schema: type: string example: openai/gpt-4 responses: '200': description: Model details content: application/json: schema: $ref: '#/components/schemas/ModelRetrieveResponse' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '500': $ref: '#/components/responses/InternalServerError' /providers: get: summary: List available providers description: | Returns a list of all configured providers with their status and regions. (NICE TO HAVE - may not be implemented in MVP) operationId: listProviders tags: - Providers parameters: - $ref: '#/components/parameters/JurisdictionFacet' responses: '200': description: List of providers content: application/json: schema: $ref: '#/components/schemas/ProvidersListResponse' '400': $ref: '#/components/responses/BadRequestError' '401': $ref: '#/components/responses/UnauthorizedError' '500': $ref: '#/components/responses/InternalServerError' /generation/{generation_id}: get: summary: Get generation statistics description: | Retrieves detailed statistics for a specific generation including tokens, cost, carbon metrics, and latency. (NICE TO HAVE - may not be implemented in MVP) operationId: getGeneration tags: - Generations parameters: - name: generation_id in: path required: true schema: type: string description: The generation ID returned in the completion response responses: '200': description: Generation statistics content: application/json: schema: $ref: '#/components/schemas/GenerationStats' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '500': $ref: '#/components/responses/InternalServerError' /metrics/{generation_id}: get: summary: Get generation metrics description: | Retrieves carbon and energy metrics for a specific generation. This endpoint provides historical access to energy consumption and carbon emissions data for completed requests. operationId: getGenerationMetrics tags: - Metrics parameters: - name: generation_id in: path required: true schema: type: string description: The generation ID returned in the completion response example: chatcmpl-abc123 responses: '200': description: Generation metrics retrieved successfully content: application/json: schema: $ref: '#/components/schemas/GenerationMetricsResponse' example: generation_id: chatcmpl-abc123 provider: openai model: gpt-4 prompt_tokens: 50 completion_tokens: 100 total_tokens: 150 energy_wh: 0.0000117 carbon_gco2e: 0.0000156 request_duration_ms: 1250 created_at: "2025-10-24T10:15:30Z" '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '500': $ref: '#/components/responses/InternalServerError' /aliases: get: summary: List model aliases description: | Lists the account's model aliases with quota usage. Aliases are account-wide: every API key sees the same set. operationId: listAliases tags: - Aliases responses: '200': description: Aliases listed successfully content: application/json: schema: $ref: '#/components/schemas/AliasListResponse' '401': $ref: '#/components/responses/UnauthorizedError' '500': $ref: '#/components/responses/InternalServerError' post: summary: Create a model alias description: | Creates a named pointer to a concrete route. The target is validated against the live catalogue with the same fail-closed semantics the router applies at request time; unroutable targets are rejected with `invalid_alias_target`, duplicate names with `alias_exists`, and creations beyond the account limit with `alias_limit_reached`. operationId: createAlias tags: - Aliases requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AliasCreateRequest' responses: '201': description: Alias created content: application/json: schema: $ref: '#/components/schemas/Alias' '400': $ref: '#/components/responses/BadRequestError' '401': $ref: '#/components/responses/UnauthorizedError' '409': description: An alias with this name already exists (`alias_exists`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Target invalid/unroutable (`invalid_alias_target`) or account alias limit reached (`alias_limit_reached`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': $ref: '#/components/responses/InternalServerError' /aliases/{name}: parameters: - name: name in: path required: true schema: type: string description: The alias name (bare, without the `alias/` prefix) example: big get: summary: Get a model alias operationId: getAlias tags: - Aliases responses: '200': description: Alias retrieved content: application/json: schema: $ref: '#/components/schemas/Alias' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '500': $ref: '#/components/responses/InternalServerError' patch: summary: Rename and/or repoint a model alias description: | Repointing takes the full target triple (provider, canonical_id, optional locode) and takes effect on the very next request that uses the alias. Rename and repoint may be combined; the update is atomic. operationId: updateAlias tags: - Aliases requestBody: required: true content: application/json: schema: $ref: '#/components/schemas/AliasUpdateRequest' responses: '200': description: Alias updated content: application/json: schema: $ref: '#/components/schemas/Alias' '400': $ref: '#/components/responses/BadRequestError' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '409': description: The new name is already taken (`alias_exists`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '422': description: Target invalid or unroutable (`invalid_alias_target`) content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' '500': $ref: '#/components/responses/InternalServerError' delete: summary: Delete a model alias description: | Hard delete. The name is immediately reusable; requests still sending `alias/` fail with `404 alias_not_found`. operationId: deleteAlias tags: - Aliases responses: '204': description: Alias deleted '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '500': $ref: '#/components/responses/InternalServerError' /aliases/{name}/stats: get: summary: Get usage stats for a model alias description: | Usage totals and a per-(model, provider, region) breakdown over a time window. Stats are keyed to the alias itself: renaming keeps continuity; deleting and recreating a name starts fresh. Only traffic since alias attribution shipped is counted. operationId: getAliasStats tags: - Aliases parameters: - name: name in: path required: true schema: type: string description: The alias name (bare, without the `alias/` prefix) - name: days in: query required: false schema: type: integer minimum: 1 maximum: 365 default: 30 description: Time window in days responses: '200': description: Stats retrieved content: application/json: schema: $ref: '#/components/schemas/AliasStatsResponse' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '500': $ref: '#/components/responses/InternalServerError' /aliases/{name}/history: get: summary: Get change history for a model alias description: | Every create, rename, and repoint recorded for the alias, newest first, with old and new values. operationId: getAliasHistory tags: - Aliases parameters: - name: name in: path required: true schema: type: string description: The alias name (bare, without the `alias/` prefix) - name: limit in: query required: false schema: type: integer minimum: 1 maximum: 200 default: 50 description: Maximum number of events to return responses: '200': description: History retrieved content: application/json: schema: $ref: '#/components/schemas/AliasHistoryResponse' '401': $ref: '#/components/responses/UnauthorizedError' '404': $ref: '#/components/responses/NotFoundError' '500': $ref: '#/components/responses/InternalServerError' components: securitySchemes: bearerAuth: type: http scheme: bearer bearerFormat: sk-or-v1-{token} description: API key in format sk-or-v1-{random_alphanumeric} parameters: JurisdictionFacet: name: jurisdiction in: query required: false description: | Optional sovereignty facet that restricts the catalogue to providers meeting a jurisdiction test, mirroring the model-browser API. Omit for the full catalogue (default). An unrecognized value returns 400. - `cloud-act-free` — the provider entity is outside US legal reach. - `eu-sovereign` — EU legal jurisdiction and EU-native (stronger than `cloud-act-free`; excludes e.g. Canada). - `eu-hosted` — served from an EU region (data residency only; says nothing about legal control). schema: type: string enum: - cloud-act-free - eu-sovereign - eu-hosted example: eu-sovereign ModalityFilter: name: modality in: query required: false description: | Optional filter restricting the listing to models of one interaction mode. Omit for the full catalogue (default), which includes non-chat models such as embeddings. An unrecognized value returns 400. Pass `chat` to list only what `/v1/chat/completions` can serve. Models whose modality is unknown are EXCLUDED by any filter value, since a model with no published mode cannot be asserted to match one. schema: type: string enum: - chat - embedding - responses - completion - realtime example: chat schemas: EmbeddingRequest: type: object required: - model - input properties: model: type: string description: | Model to use for embeddings. Must be an explicit model ID or an account alias ('alias/') — no auto-routing for embeddings. example: openai/text-embedding-3-small input: description: | Input text to embed. Can be a string, array of strings, or array of integers (token IDs). oneOf: - type: string - type: array items: type: string - type: array items: type: integer encoding_format: type: string enum: [float, base64] default: float description: The format for the embedding output. dimensions: type: integer description: | The number of dimensions to reduce the embedding to. Only supported by certain models. user: type: string description: A unique identifier for the end-user. EmbeddingResponse: type: object properties: object: type: string enum: [list] data: type: array items: $ref: '#/components/schemas/EmbeddingData' model: type: string usage: $ref: '#/components/schemas/EmbeddingUsage' lowrouter_metadata: $ref: '#/components/schemas/LowRouterMetadata' EmbeddingData: type: object properties: object: type: string enum: [embedding] embedding: description: The embedding vector (float array or base64 string). oneOf: - type: array items: type: number - type: string index: type: integer EmbeddingUsage: type: object properties: prompt_tokens: type: integer total_tokens: type: integer cost: type: number format: float description: Cost of the request, in the currency given by `currency`. remaining_balance: type: number format: float description: Remaining account balance after this request, in the currency given by `currency`. currency: type: string description: ISO-4217 currency code for `cost` and `remaining_balance` (e.g. `EUR`). example: EUR ChatCompletionRequest: type: object required: - messages - model properties: model: type: string description: | Model to use for completion. Required. Send an explicit '///' id to pin the route, name just the model with 'auto//' to let LowRouter pick the greenest eligible route for it, or call one of your account's named aliases with 'alias/' (resolved to its stored route at request time; unknown aliases return 404 alias_not_found, malformed names 400 invalid_alias_name). example: auto/mistralai/mistral-large-2512 messages: type: array minItems: 1 items: $ref: '#/components/schemas/Message' description: Array of messages in the conversation temperature: type: number minimum: 0 maximum: 2 default: 1 description: Sampling temperature between 0 and 2 top_p: type: number minimum: 0 maximum: 1 default: 1 description: Nucleus sampling parameter n: type: integer minimum: 1 default: 1 description: Number of completions to generate stream: type: boolean default: false description: Whether to stream the response via SSE stop: oneOf: - type: string - type: array items: type: string description: Stop sequence(s) max_tokens: type: integer minimum: 1 description: Maximum tokens to generate presence_penalty: type: number minimum: -2 maximum: 2 default: 0 description: Presence penalty parameter frequency_penalty: type: number minimum: -2 maximum: 2 default: 0 description: Frequency penalty parameter user: type: string description: | Optional end-user identifier, passed through to the upstream provider as request metadata (e.g. Anthropic's `metadata.user_id`) for their abuse monitoring. It does not influence routing, and it is NOT what appears as `user_identifier` on your generation log — that column carries your billing customer id. Because the value leaves LowRouter, send an opaque, stable id rather than an email or other personal data. example: user-123 tools: type: array items: $ref: '#/components/schemas/Tool' description: A list of tools the model may call. tool_choice: description: | Controls which (if any) tool is called by the model. "none" means the model will not call any tool. "auto" means the model can pick between generating a message or calling one or more tools. "required" means the model must call one or more tools. Can also be an object specifying a particular function to call. oneOf: - type: string enum: [none, auto, required] - type: object properties: type: type: string enum: [function] function: type: object required: - name properties: name: type: string parallel_tool_calls: type: boolean default: true description: Whether to enable parallel function calling during tool use. Message: type: object required: - role - content properties: role: type: string enum: [system, user, assistant, function, tool] # Pin the generated constant names. Without x-enum-varnames, # codegen's collision-avoidance picks BARE names for some values # (User, System, Assistant) and prefixed ones for others # (MessageRoleTool), and which it picks shifts as unrelated schemas # are added — so an innocent spec edit silently renames constants and # breaks every call site. Pinning them makes regeneration safe and # keeps `openapi.User` from squatting such a generic name (#395 # follow-up). x-enum-varnames: - MessageRoleSystem - MessageRoleUser - MessageRoleAssistant - MessageRoleFunction - MessageRoleTool description: Role of the message sender content: type: string # Kept as raw JSON in Go, NOT a string: OpenAI-compatible `content` is # either a string or an array of typed content blocks, and structured # content (e.g. Anthropic prompt-cache `cache_control`) must pass # through to the provider untouched. api/openapi/message_content.go # hand-implements that union over the raw bytes. # # This was a hand-edit to types.gen.go until #395's follow-up, so every # regen silently reverted it to `string` and broke message_content.go. # Declaring it here makes regeneration reproduce the intended type. # No x-go-type-import needed: codegen already imports encoding/json # for the generated types, and declaring it again emits a duplicate. x-go-type: json.RawMessage description: Content of the message. Required for all roles except assistant with tool_calls. name: type: string description: Optional name of the sender tool_calls: type: array items: $ref: '#/components/schemas/ToolCall' description: The tool calls generated by the model, such as function calls. Present in assistant messages. tool_call_id: type: string description: Tool call that this message is responding to. Required for tool role messages. ChatCompletionResponse: type: object required: - id - object - created - model - choices properties: id: type: string description: Unique completion identifier example: chatcmpl-abc123 object: type: string enum: [chat.completion] description: Object type created: type: integer description: Unix timestamp of creation example: 1234567890 model: type: string description: Model used for completion example: openai/gpt-4 choices: type: array items: $ref: '#/components/schemas/ChatCompletionChoice' description: Array of completion choices usage: $ref: '#/components/schemas/Usage' lowrouter_metadata: $ref: '#/components/schemas/LowRouterMetadata' ChatCompletionChoice: type: object required: - index - message - finish_reason properties: index: type: integer description: Index of the choice message: $ref: '#/components/schemas/Message' finish_reason: type: string enum: [stop, length, content_filter, tool_calls, null] description: Reason for completion finish nullable: true ChatCompletionChunk: type: object required: - id - object - created - model - choices properties: id: type: string description: Unique completion identifier object: type: string enum: [chat.completion.chunk] description: Object type for streaming created: type: integer description: Unix timestamp of creation model: type: string description: Model used for completion choices: type: array items: $ref: '#/components/schemas/ChatCompletionChunkChoice' lowrouter_metadata: $ref: '#/components/schemas/LowRouterMetadata' description: Only present in final chunk before [DONE] ChatCompletionChunkChoice: type: object required: - index - delta properties: index: type: integer description: Index of the choice delta: $ref: '#/components/schemas/Delta' finish_reason: type: string enum: [stop, length, content_filter, tool_calls, null] nullable: true description: Present only in final chunk Delta: type: object properties: role: type: string enum: [system, user, assistant] description: Present only in first chunk content: type: string description: Incremental content tool_calls: type: array items: $ref: '#/components/schemas/DeltaToolCall' description: Tool calls in streaming responses Tool: type: object required: - type - function properties: type: type: string enum: [function] description: The type of the tool. Currently, only function is supported. function: $ref: '#/components/schemas/ToolFunction' ToolFunction: type: object required: - name properties: name: type: string description: The name of the function to be called. description: type: string description: A description of what the function does. parameters: type: object description: The parameters the function accepts, described as a JSON Schema object. ToolCall: type: object required: - id - type - function properties: id: type: string description: The ID of the tool call. type: type: string enum: [function] # Pinned like MessageRole above: unpinned this generates as a bare # `Function`, which collides with MessageRole's `function` value and # makes codegen rename one of them unpredictably. x-enum-varnames: - ToolCallTypeFunction description: The type of the tool. Currently, only function is supported. function: $ref: '#/components/schemas/ToolCallFunction' ToolCallFunction: type: object required: - name - arguments properties: name: type: string description: The name of the function to call. arguments: type: string description: The arguments to call the function with, as a JSON string. DeltaToolCall: type: object required: - index properties: index: type: integer description: The index of the tool call in the tool_calls array. id: type: string description: The ID of the tool call. type: type: string enum: [function] description: The type of the tool. function: $ref: '#/components/schemas/DeltaToolCallFunction' DeltaToolCallFunction: type: object properties: name: type: string description: The name of the function to call (may be partial in streaming). arguments: type: string description: The arguments fragment (appended incrementally in streaming). CompletionRequest: type: object required: - prompt - model properties: model: type: string description: | Model to use for completion. Required. Accepts an explicit '///' id, an auto-routed 'auto//' id, or an account alias ('alias/'). prompt: type: string description: The prompt to generate completion for max_tokens: type: integer minimum: 1 default: 16 description: Maximum tokens to generate temperature: type: number minimum: 0 maximum: 2 default: 1 description: Sampling temperature top_p: type: number minimum: 0 maximum: 1 default: 1 description: Nucleus sampling parameter n: type: integer minimum: 1 default: 1 description: Number of completions to generate stream: type: boolean default: false description: Whether to stream the response stop: oneOf: - type: string - type: array items: type: string description: Stop sequence(s) presence_penalty: type: number minimum: -2 maximum: 2 default: 0 frequency_penalty: type: number minimum: -2 maximum: 2 default: 0 user: type: string description: | Optional end-user identifier, passed through to the upstream provider as request metadata. It does not influence routing. Send an opaque, stable id rather than an email — the value leaves LowRouter. CompletionResponse: type: object required: - id - object - created - model - choices properties: id: type: string description: Unique completion identifier example: cmpl-abc123 object: type: string enum: [text_completion] description: Object type created: type: integer description: Unix timestamp of creation model: type: string description: Model used for completion choices: type: array items: $ref: '#/components/schemas/CompletionChoice' usage: $ref: '#/components/schemas/Usage' lowrouter_metadata: $ref: '#/components/schemas/LowRouterMetadata' CompletionChoice: type: object required: - index - text - finish_reason properties: index: type: integer description: Index of the choice text: type: string description: Completion text finish_reason: type: string enum: [stop, length, content_filter] description: Reason for completion finish Usage: type: object required: - prompt_tokens - completion_tokens - total_tokens properties: prompt_tokens: type: integer description: Number of tokens in the prompt example: 10 completion_tokens: type: integer description: Number of tokens in the completion example: 20 total_tokens: type: integer description: Total tokens used example: 30 cost: type: number format: float description: Cost of this request, in the currency given by `currency`. example: 0.0042 remaining_balance: type: number format: float description: Remaining account balance after this request, in the currency given by `currency`. example: 4.95 currency: type: string description: ISO-4217 currency code for `cost` and `remaining_balance` (e.g. `EUR`). example: EUR Alias: type: object required: [id, name, full_name, provider, canonical_id, locode, target, created_at, updated_at] properties: id: type: string format: uuid description: Alias id (stable across renames) name: type: string description: Bare alias name example: big full_name: type: string description: The callable form to put in the `model` request field example: alias/big provider: type: string description: Target provider example: aws-bedrock canonical_id: type: string description: Target canonical model ({creator}/{model-slug}) example: mistral/ministral-3-3b-instruct locode: type: string description: Target region UN/LOCODE, or `global` example: br-gru target: type: string description: The resolved full model ID the alias points at example: aws-bedrock/mistral/ministral-3-3b-instruct/br-gru created_at: type: string format: date-time updated_at: type: string format: date-time AliasCreateRequest: type: object required: [name] description: >- The target is `provider` + `canonical_id` (+ optional `locode`) as flat top-level fields — the canonical form. Two alternatives are also accepted so a target copied out of a response needs no reshaping: a nested `target` object with the same three fields, or a `target` string in `provider/creator/model[/locode]` form. Where a flat field and a `target` value disagree, the flat field wins. properties: name: type: string description: "1-64 chars: lowercase a-z, 0-9, '-' or '_', starting alphanumeric. Lowercased on write." example: big provider: type: string example: aws-bedrock canonical_id: type: string example: mistral/ministral-3-3b-instruct locode: type: string description: Optional; defaults to `global` example: br-gru target: description: >- Alternative to the flat fields — either an object carrying the same three fields, or a `provider/creator/model[/locode]` string. oneOf: - $ref: '#/components/schemas/AliasTarget' - type: string example: aws-bedrock/mistral/ministral-3-3b-instruct/br-gru AliasTarget: type: object description: The target triple in nested form. required: [provider, canonical_id] properties: provider: type: string example: aws-bedrock canonical_id: type: string example: mistral/ministral-3-3b-instruct locode: type: string description: Optional; defaults to `global` example: br-gru AliasUpdateRequest: type: object description: >- Provide `name` to rename and/or the full target triple to repoint. Repointing takes all of `provider`, `canonical_id` and `locode`, not just the field being changed. The same three target shapes as AliasCreateRequest are accepted. properties: name: type: string provider: type: string canonical_id: type: string locode: type: string target: description: >- Alternative to the flat fields — either an object carrying the same three fields, or a `provider/creator/model[/locode]` string. oneOf: - $ref: '#/components/schemas/AliasTarget' - type: string AliasQuota: type: object required: [used, max] properties: used: type: integer format: int64 max: type: integer AliasListResponse: type: object required: [aliases, quota] properties: aliases: type: array items: $ref: '#/components/schemas/Alias' quota: $ref: '#/components/schemas/AliasQuota' AliasStatsTotals: type: object required: [requests, prompt_tokens, completion_tokens, total_tokens, cost, carbon_gco2e] properties: requests: type: integer format: int64 prompt_tokens: type: integer format: int64 completion_tokens: type: integer format: int64 total_tokens: type: integer format: int64 cost: type: number description: Total billed cost over the window, in the account currency carbon_gco2e: type: number description: Total estimated CO2e over the window, in grams AliasStatsRow: allOf: - $ref: '#/components/schemas/AliasStatsTotals' - type: object required: [provider, model, region] properties: provider: type: string model: type: string description: >- Canonical id of the model the alias resolved to — the same string used as the alias target, sent in the request, and listed by GET /v1/models, so these rows join against a caller's own logs. example: mistral/mistral-large-2512 display_name: type: string description: >- Human-readable model name. Absent when the catalogue has none. Not a join key — use `model` for that. example: Mistral Large 3 region: type: string AliasStatsResponse: type: object required: [alias, days, totals, breakdown] properties: alias: $ref: '#/components/schemas/Alias' days: type: integer description: The window the stats cover totals: $ref: '#/components/schemas/AliasStatsTotals' breakdown: type: array description: One row per (model, provider, region) the alias resolved to items: $ref: '#/components/schemas/AliasStatsRow' AliasEvent: type: object required: [id, event_type, created_at] properties: id: type: string format: uuid event_type: type: string enum: [created, renamed, repointed, deleted] old_name: type: string new_name: type: string old_target: type: string description: Previous full model ID, present on repoint/delete events new_target: type: string description: New full model ID, present on create/repoint events created_at: type: string format: date-time AliasHistoryResponse: type: object required: [alias, events] properties: alias: $ref: '#/components/schemas/Alias' events: type: array description: Newest first items: $ref: '#/components/schemas/AliasEvent' LowRouterMetadata: type: object required: - provider - routing_mode - fallback_occurred properties: provider: type: string description: Provider that handled the request example: openai region: type: string description: | Region the request was physically served from. `unknown` when the serving region is not resolvable — never a fabricated placeholder. When this is `unknown`, `carbon_intensity_gco2_per_kwh` and `carbon_gco2e` are omitted rather than reported against a world-average intensity. example: eu energy_wh: type: number format: float description: Energy consumed in Wh example: 0.0403 carbon_gco2e: type: number format: float description: Carbon emissions in grams of CO2 equivalent example: 23.4 estimation_methodology: type: string description: Methodology used for carbon/energy estimation example: TDP-based calculation with regional grid intensity carbon_intensity_gco2_per_kwh: type: integer description: Grid carbon intensity in gCO2/kWh example: 460 routing_mode: type: string enum: [auto, explicit] # Pinned for the same reason as MessageRole above: unpinned, these # generate as bare `Auto`/`Explicit`. x-enum-varnames: - LowRouterMetadataRoutingModeAuto - LowRouterMetadataRoutingModeExplicit description: Routing mode used for this request routing_reason: type: string description: | Reason for provider selection. For `auto//` requests (#32) this names the stage of the fixed priority order that decided the route: `eu_sovereign_preferred` when a sovereign route beat a non-sovereign one, `lowest_carbon_intensity` / `lowest_cost` when carbon or price broke the ranking, `round_robin` when fully-tied routes rotated, and `only_route` when the model has a single eligible route to rank. example: lowest_carbon_intensity enum: - lowest_carbon_intensity - lowest_cost - lowest_latency - round_robin - eu_sovereign_preferred - only_route fallback_occurred: type: boolean description: Whether fallback to another provider occurred fallback_reason: type: string description: | Why the route changed after selection. Present only when `fallback_occurred` is true. `routing_reason` is NOT overwritten on a fallback — it keeps describing the original pick, while this field explains why that pick did not serve the request. example: primary_rate_limited enum: - primary_rate_limited - primary_timeout - primary_unavailable - primary_error providers_attempted: type: array items: type: string description: List of providers attempted (for fallback scenarios) example: [openai, anthropic] requested_alias: type: string description: | The alias the client sent in `model` (e.g. `alias/big`). Present only when the request was aliased; `model` in the response carries the resolved canonical model id. example: alias/big requested_auto: type: string description: | The auto-routed id the client sent in `model` (e.g. `auto/mistralai/mistral-large-2512`). Present only when the request used the `auto/` namespace; `model` in the response carries the resolved 4-part id, and `provider` / `region` name the route that was chosen. example: auto/mistralai/mistral-large-2512 eu_sovereign: type: boolean description: | Whether the resolved route satisfies the sovereign PAIR: an EU-sovereign provider entity serving from an EU/EEA region. Present only on `auto/` requests, where sovereignty is a preference rather than a guarantee — `false` means no sovereign route existed and the request degraded down the priority order. Absent on explicit and aliased requests, where the caller chose the route themselves. Hard sovereignty guarantees are enforced per-key, not here. example: true # Prompt-cache visibility, needed to reconstruct a bill externally # (#339 A0). These four ARE serialised — unlike the internal Usage # counters, which cannot be expressed here at all — and were hand-added # to types.gen.go, so every regen dropped them. Declared here so # regeneration reproduces them. cache_read_tokens: type: integer description: Prompt tokens served from the provider's prompt cache example: 1024 cache_creation_tokens: type: integer description: Prompt tokens written to the provider's prompt cache example: 512 cache_creation_5m_tokens: type: integer description: 5-minute-TTL portion of cache_creation_tokens example: 512 cache_creation_1h_tokens: type: integer description: 1-hour-TTL portion of cache_creation_tokens example: 0 GenerationMetricsResponse: type: object required: - generation_id - prompt_tokens - completion_tokens - total_tokens - created_at properties: generation_id: type: string description: Unique generation identifier example: chatcmpl-abc123 provider: type: string description: Provider that handled the request example: openai nullable: true model: type: string description: Model used for completion example: gpt-4 nullable: true prompt_tokens: type: integer description: Number of tokens in the prompt example: 50 completion_tokens: type: integer description: Number of tokens in the completion example: 100 total_tokens: type: integer description: Total tokens used example: 150 energy_wh: type: number format: float description: Energy consumed in Wh (nullable if emissions data unavailable) example: 0.0000117 nullable: true carbon_gco2e: type: number format: float description: Carbon emissions in grams CO2 equivalent (nullable if emissions data unavailable) example: 0.0000156 nullable: true request_duration_ms: type: integer description: Request duration in milliseconds example: 1250 nullable: true created_at: type: string format: date-time description: Timestamp when the generation was created example: "2025-10-24T10:15:30Z" ModelsListResponse: type: object required: - data properties: object: type: string enum: [list] default: list data: type: array items: $ref: '#/components/schemas/ModelInfo' ModelRetrieveResponse: allOf: - $ref: '#/components/schemas/ModelInfo' - type: object required: - object - created - owned_by properties: object: type: string enum: [model] default: model created: type: integer format: int64 description: Unix timestamp when the model was created example: 1686935002 owned_by: type: string description: The organization that owns the model example: openai ModelInfo: type: object required: - id - name - provider properties: id: type: string description: >- Canonical routable model id in the 3-part form `{provider}/{creator}/{model}`. Passing this to the completions `model` field defaults to the `global` region. To pin a region, use one of the 4-part ids in `regions[]` instead. example: vertex/anthropic/claude-opus-4.6 name: type: string description: Display name of the model example: vertex/anthropic/claude-opus-4.6 provider: type: string description: Provider name example: vertex context_length: type: integer description: >- Maximum context length in tokens, scraped from the provider's own source. Omitted when unknown — never reported as 0. These limits are per-provider and can differ between providers serving the same model. example: 200000 max_output_tokens: type: integer description: >- Maximum number of output/completion tokens the model can generate, scraped from the provider's own source. Omitted when the source does not publish it — never a fabricated default. example: 8192 modality: type: string description: >- The interaction mode this model is served for, as published by the provider's own pricing source. Only `chat` and `completion` models can serve `/v1/chat/completions`; sending any other modality there returns a typed 400 rather than an upstream error. Omitted when the source does not publish a mode — never guessed. An omitted value means "unknown", NOT "chat", so a client that requires certainty should treat it as unverified. enum: - chat - embedding - responses - completion - realtime example: chat capabilities: type: object description: >- Advertised capabilities. A field is omitted when the underlying source does not publish it, so an absent field means "unknown" rather than "unsupported" — do not read a missing `function_calling` as false. properties: streaming: type: boolean description: Supports streaming responses function_calling: type: boolean description: >- Whether the provider states this model supports function calling / tool use. Taken verbatim from the provider's own published capability data — never inferred from the model's family, name or description. OMITTED when the provider publishes no capability field, which is the common case: most providers (including Anthropic, Google, Vertex and AWS Bedrock) expose nothing machine-readable here. An absent field therefore means UNKNOWN, not unsupported — do not read it as false. The value is per provider, not per model: the same model served by two providers can legitimately differ. required: - streaming regions: type: array description: >- Routable per-region variants of this model. Pricing and carbon vary by region, so they live here rather than at the model level. `global` is always the first entry when present. When a model has no regional rows, a single synthesized `global` entry carries the model's pricing. Use one of these `id`s (or the 3-part `id` above) as the completions `model`. items: $ref: '#/components/schemas/ModelRegion' example: id: vertex/anthropic/claude-opus-4.6 name: vertex/anthropic/claude-opus-4.6 provider: vertex context_length: 200000 max_output_tokens: 64000 capabilities: streaming: true function_calling: true regions: - id: vertex/anthropic/claude-opus-4.6/global locode: global pricing: prompt_per_1m_tokens: 5.0 completion_per_1m_tokens: 25.0 currency: EUR carbon_metrics: GLOBAL-AVERAGE: energy_per_token_wh: 0.000000033 carbon_per_token_gco2e: 0.000055 grid_carbon_intensity_gco2_per_kwh: 475 - id: vertex/anthropic/claude-opus-4.6/sg-sin locode: sg-sin pricing: prompt_per_1m_tokens: 5.5 completion_per_1m_tokens: 27.5 currency: EUR carbon_metrics: sg-sin: energy_per_token_wh: 0.000000033 carbon_per_token_gco2e: 0.00006 grid_carbon_intensity_gco2_per_kwh: 495 ModelRegion: type: object required: - id - locode properties: id: type: string description: >- Full routable 4-part id `{provider}/{creator}/{model}/{locode}`. Pass this to the completions `model` field to pin this region and be billed at its rate. example: vertex/anthropic/claude-opus-4.6/sg-sin locode: type: string description: >- UN/LOCODE naming the region (e.g. `sg-sin`), or `global` for the provider's default endpoint. example: sg-sin pricing: type: object properties: prompt_per_1m_tokens: type: number format: float description: Price per 1M prompt tokens, in the currency given by `currency`. example: 30.0 completion_per_1m_tokens: type: number format: float description: Price per 1M completion tokens, in the currency given by `currency`. example: 60.0 cache_read_per_1m_tokens: type: number format: float description: >- Price per 1M cached prompt tokens read from the provider cache, in the currency given by `currency`. Omitted when the model has no cache pricing. example: 0.09 cache_write_per_1m_tokens: type: number format: float description: >- Price per 1M prompt tokens written to the provider cache, in the currency given by `currency`. Omitted when the model has no cache pricing. example: 1.11 batch_prompt_per_1m_tokens: type: number format: float description: >- Price per 1M prompt tokens for batch requests, in the currency given by `currency`. Omitted when the model has no batch pricing. example: 15.0 batch_completion_per_1m_tokens: type: number format: float description: >- Price per 1M completion tokens for batch requests, in the currency given by `currency`. Omitted when the model has no batch pricing. example: 30.0 currency: type: string description: ISO-4217 currency code for the prices above (e.g. `EUR`). example: EUR carbon_metrics: type: object description: >- Carbon intensity for this region, keyed by region label (`GLOBAL-AVERAGE` for the synthesized global entry). additionalProperties: type: object properties: energy_per_token_wh: type: number format: float description: Energy per token in Wh carbon_per_token_gco2e: type: number format: float description: Carbon per token in gCO2e grid_carbon_intensity_gco2_per_kwh: type: integer description: Grid carbon intensity example: us-east-1: energy_per_token_wh: 0.000000033 carbon_per_token_gco2e: 0.000055 grid_carbon_intensity_gco2_per_kwh: 460 ProvidersListResponse: type: object required: - data properties: object: type: string enum: [list] default: list data: type: array items: $ref: '#/components/schemas/ProviderInfo' ProviderInfo: type: object required: - name - status properties: name: type: string description: Provider name example: openai status: type: string enum: [healthy, degraded, down] description: Current provider health status regions: type: array items: type: string description: Supported regions example: [us-east-1, us-west-2, eu-west-1] model_count: type: integer description: Number of models offered by this provider GenerationStats: type: object required: - generation_id - model - provider - region - usage - carbon_metrics - created_at - interrupted properties: generation_id: type: string description: Unique generation identifier interrupted: type: boolean description: >- True when a streamed generation ended before completion (client disconnect, cancel, or timeout). The request is still billed — the upstream produced the tokens — so this is the field to reconcile app-logged spend against. example: false model: type: string description: Model used provider: type: string description: Provider that handled the request region: type: string description: Region where processed usage: $ref: '#/components/schemas/Usage' cost: type: object properties: prompt_cost: type: number format: float completion_cost: type: number format: float total_cost: type: number format: float currency: type: string description: ISO-4217 currency code for the cost values above (e.g. `EUR`). example: EUR carbon_metrics: type: object properties: energy_wh: type: number format: float carbon_gco2e: type: number format: float grid_carbon_intensity_gco2_per_kwh: type: integer latency: type: object properties: request_duration_ms: type: integer time_to_first_token_ms: type: integer nullable: true routing_info: type: object properties: routing_mode: type: string enum: [auto, explicit] routing_reason: type: string fallback_occurred: type: boolean providers_attempted: type: array items: type: string created_at: type: string format: date-time description: Timestamp of generation ErrorResponse: type: object required: - error properties: error: $ref: '#/components/schemas/ErrorDetail' ErrorDetail: type: object required: - message properties: type: type: string enum: - invalid_request_error - authentication_error - rate_limit_error - provider_error - provider_unavailable - internal_server_error - not_found description: Error type matching OpenAI error format message: type: string description: Human-readable error message code: type: string description: Machine-readable error code nullable: true param: type: string description: Parameter that caused the error (if applicable) nullable: true providers_attempted: type: array items: type: string description: Providers attempted before failure (fallback context) last_error: type: string description: Last error message from provider (fallback context) responses: UnauthorizedError: description: Authentication failed content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: type: authentication_error message: Invalid API key provided code: invalid_api_key BadRequestError: description: Invalid request content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: type: invalid_request_error message: Missing required field 'messages' code: missing_required_field param: messages NotFoundError: description: Resource not found content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: type: not_found message: Generation not found code: null param: generation_id InternalServerError: description: Internal server error content: application/json: schema: $ref: '#/components/schemas/ErrorResponse' example: error: type: internal_server_error message: An unexpected error occurred code: internal_error tags: - name: Completions description: Chat and text completion endpoints - name: Models description: Model listing and information - name: Providers description: Provider status and information - name: Generations description: Generation statistics and history - name: Metrics description: Carbon and energy metrics for generations