openapi: 3.1.0
info:
  title: LLM Proxy HTTP API
  version: 1.0.0
  description: >-
    The sole canonical wire contract for llm-proxy-owned proxy, browser
    configuration, and management endpoints. Each configured text model owns
    one explicit upstream wire contract and execution lifecycle. OpenAI
    Responses and Gemini 3.x Interactions use stored pollable resources;
    Gemini 2.5 Interactions, OpenAI-compatible Chat Completions, and Anthropic
    Messages complete synchronously. Public proxy operations remain blocking and never expose an
    upstream resource id. OpenAI resource ids remain in memory only, but the
    current adapter does not cancel or delete stored Responses, so OpenAI
    account retention policy applies. Background Gemini interaction ids are
    also request-local; the adapter cancels active resources and deletes every
    stored interaction on exit. Synchronous Gemini interactions are non-stored.
    TAuth-owned endpoints are outside this contract.
    Contributors must update this document in the same change as any owned
    handler or bundled-client wire change.
servers:
  - url: https://llm-proxy-api.mprlab.com
    description: Production API origin
x-llm-proxy-protocol-methods:
  - OPTIONS
tags:
  - name: Proxy
    description: Tenant-key-authenticated text and dictation operations.
  - name: Configuration
    description: Public browser runtime configuration owned by llm-proxy.
  - name: Capabilities
    description: Public provider, model, capability, and request-limit resources.
  - name: Management
    description: TAuth-session-authenticated tenant management operations.
paths:
  /:
    get:
      operationId: getText
      summary: Generate text from a query prompt
      tags:
        - Proxy
      security:
        - TenantClientKey: []
      x-llm-proxy-allow-undeclared-query: true
      parameters:
        - $ref: '#/components/parameters/TenantClientKey'
        - $ref: '#/components/parameters/Prompt'
        - $ref: '#/components/parameters/Provider'
        - $ref: '#/components/parameters/Model'
        - $ref: '#/components/parameters/WebSearch'
        - $ref: '#/components/parameters/SystemPrompt'
        - $ref: '#/components/parameters/MaxTokens'
        - $ref: '#/components/parameters/ReasoningEffort'
        - $ref: '#/components/parameters/ResponseFormat'
        - $ref: '#/components/parameters/Accept'
        - $ref: '#/components/parameters/RequestTimeout'
      responses:
        '200':
          $ref: '#/components/responses/TextSuccess'
        '400':
          $ref: '#/components/responses/ProxyBadRequest'
        '403':
          $ref: '#/components/responses/ProxyForbidden'
        '429':
          $ref: '#/components/responses/ProxyRateLimited'
        '499':
          $ref: '#/components/responses/CallerClosed'
        '502':
          $ref: '#/components/responses/ProxyBadGateway'
        '503':
          $ref: '#/components/responses/ProxyUnavailable'
        '504':
          $ref: '#/components/responses/ProxyTimeout'
    post:
      operationId: postText
      summary: Generate text from a prompt or messages JSON body
      tags:
        - Proxy
      security:
        - TenantClientKey: []
      x-llm-proxy-allow-undeclared-query: true
      parameters:
        - $ref: '#/components/parameters/TenantClientKey'
        - $ref: '#/components/parameters/Provider'
        - $ref: '#/components/parameters/Model'
        - $ref: '#/components/parameters/ResponseFormat'
        - $ref: '#/components/parameters/Accept'
        - $ref: '#/components/parameters/RequestTimeout'
      requestBody:
        $ref: '#/components/requestBodies/TextRequest'
      responses:
        '200':
          $ref: '#/components/responses/TextSuccess'
        '400':
          $ref: '#/components/responses/ProxyBadRequest'
        '403':
          $ref: '#/components/responses/ProxyForbidden'
        '413':
          $ref: '#/components/responses/ProxyPayloadTooLarge'
        '429':
          $ref: '#/components/responses/ProxyRateLimited'
        '499':
          $ref: '#/components/responses/CallerClosed'
        '502':
          $ref: '#/components/responses/ProxyBadGateway'
        '503':
          $ref: '#/components/responses/ProxyUnavailable'
        '504':
          $ref: '#/components/responses/ProxyTimeout'
  /v2:
    post:
      operationId: postV2Messages
      summary: Generate text from canonical messages
      description: >-
        The current messages-only operation. `messages` is required. User
        messages may include ordered inline or tenant-asset-backed image and
        audio attachments. `model`, `web_search`, `max_tokens`, and
        `reasoning_effort` are optional. Omitting `reasoning_effort` selects
        the tenant or route default. A supplied value must be non-blank and
        supported by the resolved route. The selected provider offering owns
        media admission and transport limits. Unsupported media or route
        capabilities return HTTP 400 before an upstream call. The service
        rejects an encoded request body above 8 MiB before JSON decoding. A
        smaller catalog-derived body limit applies when configured. Current
        Moonshot Kimi image routes preserve attachment order and exact bytes
        through Chat Completions Data URL blocks.
      tags:
        - Proxy
      security:
        - TenantClientKey: []
      x-llm-proxy-allow-undeclared-query: true
      parameters:
        - $ref: '#/components/parameters/TenantClientKey'
        - $ref: '#/components/parameters/Provider'
        - $ref: '#/components/parameters/ResponseFormat'
        - $ref: '#/components/parameters/Accept'
        - $ref: '#/components/parameters/RequestTimeout'
      requestBody:
        $ref: '#/components/requestBodies/V2Request'
      responses:
        '200':
          $ref: '#/components/responses/TextSuccess'
        '400':
          $ref: '#/components/responses/V2BadRequest'
        '403':
          $ref: '#/components/responses/ProxyForbidden'
        '404':
          $ref: '#/components/responses/AssetFailure'
        '410':
          $ref: '#/components/responses/AssetFailure'
        '413':
          $ref: '#/components/responses/ProxyPayloadTooLarge'
        '429':
          $ref: '#/components/responses/ProxyRateLimited'
        '499':
          $ref: '#/components/responses/CallerClosed'
        '502':
          $ref: '#/components/responses/ProxyBadGateway'
        '503':
          $ref: '#/components/responses/ProxyUnavailable'
        '504':
          $ref: '#/components/responses/ProxyTimeout'
        '500':
          $ref: '#/components/responses/AssetFailure'
  /model/v1/assets:
    post:
      operationId: uploadTenantAsset
      summary: Upload exact tenant media bytes
      description: >-
        Stores one hash-bound image or audio asset for the configured retention
        period. The authenticated tenant owns the returned opaque asset id.
      tags:
        - Proxy
      security:
        - TenantClientKey: []
      parameters:
        - $ref: '#/components/parameters/TenantClientKey'
        - $ref: '#/components/parameters/AssetSHA256'
        - $ref: '#/components/parameters/RequestTimeout'
      requestBody:
        $ref: '#/components/requestBodies/AssetUpload'
      responses:
        '201':
          $ref: '#/components/responses/AssetCreated'
        '400':
          $ref: '#/components/responses/AssetFailure'
        '403':
          $ref: '#/components/responses/ProxyForbidden'
        '413':
          $ref: '#/components/responses/AssetFailure'
        '499':
          $ref: '#/components/responses/CallerClosed'
        '504':
          $ref: '#/components/responses/ProxyTimeout'
        '500':
          $ref: '#/components/responses/AssetFailure'
  /model/v1/assets/{asset_id}:
    delete:
      operationId: deleteTenantAsset
      summary: Delete one tenant asset
      tags:
        - Proxy
      security:
        - TenantClientKey: []
      parameters:
        - $ref: '#/components/parameters/TenantClientKey'
        - $ref: '#/components/parameters/AssetID'
      responses:
        '204':
          description: The asset is deleted.
        '403':
          $ref: '#/components/responses/ProxyForbidden'
        '404':
          $ref: '#/components/responses/AssetFailure'
        '410':
          $ref: '#/components/responses/AssetFailure'
        '500':
          $ref: '#/components/responses/AssetFailure'
  /dictate:
    post:
      operationId: postDictation
      summary: Transcribe an audio upload
      tags:
        - Proxy
      security:
        - TenantClientKey: []
      x-llm-proxy-allow-undeclared-query: true
      parameters:
        - $ref: '#/components/parameters/TenantClientKey'
        - $ref: '#/components/parameters/Provider'
        - $ref: '#/components/parameters/Model'
        - $ref: '#/components/parameters/RequestTimeout'
      requestBody:
        $ref: '#/components/requestBodies/DictationRequest'
      responses:
        '200':
          $ref: '#/components/responses/DictationSuccess'
        '400':
          $ref: '#/components/responses/ProxyBadRequest'
        '403':
          $ref: '#/components/responses/ProxyForbidden'
        '413':
          $ref: '#/components/responses/ProxyPayloadTooLarge'
        '429':
          $ref: '#/components/responses/ProxyRateLimited'
        '499':
          $ref: '#/components/responses/CallerClosed'
        '502':
          $ref: '#/components/responses/ProxyBadGateway'
        '503':
          $ref: '#/components/responses/ProxyUnavailable'
        '504':
          $ref: '#/components/responses/ProxyTimeout'
  /config-ui.yaml:
    get:
      operationId: getBrowserConfiguration
      summary: Read the browser runtime configuration
      tags:
        - Configuration
      security: []
      parameters:
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          description: Current browser runtime configuration.
          headers:
            Cache-Control:
              description: Prevents persistence of environment-specific browser configuration.
              schema:
                type: string
                const: no-store
              x-required: true
          content:
            application/yaml:
              schema:
                type: string
  /api/public/capabilities:
    get:
      operationId: getPublicCapabilities
      summary: Read the public normalized model capability catalog
      description: Returns the deterministic, secret-free projection of model publishers, families, exact models, provider offerings, and public proxy request limits.
      tags:
        - Capabilities
      security: []
      responses:
        '200':
          description: Current public capability catalog.
          headers:
            Cache-Control:
              description: Allows short-lived caching of the public catalog.
              schema:
                type: string
                const: public, max-age=300
              x-required: true
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicCapabilityCatalog'
  /api/management/account:
    get:
      operationId: getManagementAccount
      summary: Read the authenticated user and owned tenant summaries
      tags:
        - Management
      security:
        - TAuthSession: []
      parameters:
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/AccountSuccess'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/usage:
    get:
      operationId: getManagementAccountUsage
      summary: Read interval-scoped usage across every owned tenant
      tags:
        - Management
      security:
        - TAuthSession: []
      parameters:
        - $ref: '#/components/parameters/UsageInterval'
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/UsageSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/usage/failures:
    get:
      operationId: getManagementAccountUsageFailures
      summary: Read safe failure details across every owned tenant and interval
      description: Returns a newest-first snapshot page of failed managed proxy events across every tenant owned by the authenticated user. Each row identifies its tenant by opaque ID and current name while exposing only bounded diagnostic metadata and canonical outcome codes. Rows never include prompts, responses, provider bodies, free-form errors, credentials, or another user's ownership data.
      tags:
        - Management
      security:
        - TAuthSession: []
      parameters:
        - $ref: '#/components/parameters/UsageInterval'
        - $ref: '#/components/parameters/UsageFailureLimit'
        - $ref: '#/components/parameters/UsageFailureCursor'
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/AccountUsageFailuresSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants:
    post:
      operationId: createManagementTenant
      summary: Create an owned tenant
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/OptionalOrigin'
      requestBody:
        $ref: '#/components/requestBodies/TenantNameRequest'
      responses:
        '201':
          $ref: '#/components/responses/TenantProfileCreated'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '409':
          $ref: '#/components/responses/ManagementConflict'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/admin/users:
    get:
      operationId: getManagementAdminUsers
      summary: Read the administrative user and tenant usage summary
      tags:
        - Management
      security:
        - TAuthSession: []
      parameters:
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/AdminUsersSuccess'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants/{tenant_id}:
    get:
      operationId: getManagementTenant
      summary: Read an owned tenant profile
      tags:
        - Management
      security:
        - TAuthSession: []
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/TenantProfileSuccess'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
    put:
      operationId: renameManagementTenant
      summary: Rename an owned tenant
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/OptionalOrigin'
      requestBody:
        $ref: '#/components/requestBodies/TenantNameRequest'
      responses:
        '200':
          $ref: '#/components/responses/TenantProfileSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '409':
          $ref: '#/components/responses/ManagementConflict'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
    delete:
      operationId: deleteManagementTenant
      summary: Delete an owned non-final tenant
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '204':
          description: Tenant deleted.
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '409':
          $ref: '#/components/responses/ManagementConflict'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants/{tenant_id}/usage:
    get:
      operationId: getManagementTenantUsage
      summary: Read interval-scoped usage for an owned tenant
      tags:
        - Management
      security:
        - TAuthSession: []
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/UsageInterval'
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/UsageSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants/{tenant_id}/usage/failures:
    get:
      operationId: getManagementTenantUsageFailures
      summary: Read safe failure details for an owned tenant and interval
      description: Returns a newest-first snapshot page of failed managed proxy events. Rows expose only bounded diagnostic metadata and canonical outcome codes; they never include prompts, responses, provider bodies, free-form errors, credentials, or ownership identifiers. Historical rows use status-derived normalized outcome codes rather than reconstructed error messages.
      tags:
        - Management
      security:
        - TAuthSession: []
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/UsageInterval'
        - $ref: '#/components/parameters/UsageFailureLimit'
        - $ref: '#/components/parameters/UsageFailureCursor'
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/UsageFailuresSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants/{tenant_id}/provider-keys/{provider}:
    put:
      operationId: putManagementProviderKey
      summary: Verify and save provider settings and a provider credential
      description: A nonempty api_key performs exactly one provider-authenticated verification operation for the selected provider, text model, and provider base URL under the management request context and shared upstream admission/rate-limit boundary. Changing a saved DashScope base_url also verifies the retained key against the new URL. Only a successful verification atomically persists the credential and submitted settings, reconciles routing defaults, and returns a keyed profile. Rejection and unconfirmed transient outcomes never mutate the provider key, settings, defaults, or managed usage. An empty api_key retains the existing verified credential. The operation returns 409 without a mutation if that retained credential changes before the verified update can persist.
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/ProviderPath'
        - $ref: '#/components/parameters/OptionalOrigin'
      requestBody:
        $ref: '#/components/requestBodies/ProviderKeyRequest'
      responses:
        '200':
          $ref: '#/components/responses/TenantProfileSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '409':
          $ref: '#/components/responses/ManagementConflict'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '422':
          $ref: '#/components/responses/ProviderKeyRejected'
        '429':
          $ref: '#/components/responses/ProviderKeyVerificationRateLimited'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
        '503':
          $ref: '#/components/responses/ProviderKeyVerificationUnavailable'
        '504':
          $ref: '#/components/responses/ProviderKeyVerificationTimedOut'
    delete:
      operationId: deleteManagementProviderKey
      summary: Remove provider settings and a provider credential
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/ProviderPath'
        - $ref: '#/components/parameters/OptionalOrigin'
      responses:
        '200':
          $ref: '#/components/responses/TenantProfileSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants/{tenant_id}/provider-keys/{provider}/reveal:
    post:
      operationId: revealManagementProviderKey
      summary: Reveal one saved provider credential
      description: This credentialed action requires the exact configured public Origin in addition to the TAuth session.
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/ProviderPath'
        - $ref: '#/components/parameters/RequiredOrigin'
      requestBody:
        $ref: '#/components/requestBodies/EmptyJSONRequest'
      responses:
        '200':
          $ref: '#/components/responses/ProviderKeyRevealSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants/{tenant_id}/defaults:
    put:
      operationId: putManagementTenantDefaults
      summary: Replace the tenant routing defaults
      description: Every nonempty provider/model pair must use a provider for which this tenant has a saved API key. The text pair is empty only when no provider key exists. The dictation pair is empty when no keyed provider supports dictation.
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/OptionalOrigin'
      requestBody:
        $ref: '#/components/requestBodies/DefaultsRequest'
      responses:
        '200':
          $ref: '#/components/responses/TenantProfileSuccess'
        '400':
          $ref: '#/components/responses/ManagementBadRequest'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
  /api/management/tenants/{tenant_id}/secrets:
    post:
      operationId: postManagementTenantSecret
      summary: Generate and replace the tenant client secret
      tags:
        - Management
      security:
        - TAuthSession: []
      x-llm-proxy-required-request-content-type: application/json
      parameters:
        - $ref: '#/components/parameters/TenantID'
        - $ref: '#/components/parameters/OptionalOrigin'
      requestBody:
        $ref: '#/components/requestBodies/EmptyJSONRequest'
      responses:
        '200':
          $ref: '#/components/responses/TenantSecretSuccess'
        '401':
          $ref: '#/components/responses/ManagementUnauthorized'
        '403':
          $ref: '#/components/responses/ManagementForbidden'
        '404':
          $ref: '#/components/responses/ManagementNotFound'
        '415':
          $ref: '#/components/responses/ManagementUnsupportedMediaType'
        '500':
          $ref: '#/components/responses/ManagementInternalError'
components:
  securitySchemes:
    TenantClientKey:
      type: apiKey
      in: query
      name: key
      description: The tenant client secret generated by the management API.
    TAuthSession:
      type: apiKey
      in: cookie
      name: app_session_llm_proxy
      description: The exact deployment-configured TAuth session cookie. The production cookie name is configured through management.session_cookie_name.
  parameters:
    TenantClientKey:
      name: key
      in: query
      required: true
      description: Tenant client secret.
      schema:
        type: string
        minLength: 1
    Prompt:
      name: prompt
      in: query
      required: true
      description: User prompt.
      schema:
        type: string
        minLength: 1
    Provider:
      name: provider
      in: query
      required: false
      description: Canonical provider identifier from the public capability catalog, such as zai. Retired zhipu and glm values are invalid. Omission uses the tenant default.
      schema:
        type: string
        minLength: 1
    Model:
      name: model
      in: query
      required: false
      description: Model identifier. Omission uses the resolved provider default.
      schema:
        type: string
        minLength: 1
    WebSearch:
      name: web_search
      in: query
      required: false
      description: Exact boolean query parameter. Use true or false; omission disables web search. Any other supplied spelling is invalid and returns HTTP 400.
      schema:
        type: boolean
    SystemPrompt:
      name: system_prompt
      in: query
      required: false
      schema:
        type: string
    MaxTokens:
      name: max_tokens
      in: query
      required: false
      description: Initial per-attempt output budget. The same budget is reused when the proxy requests a missing suffix; after a zero-text output-budget stop, a configured model output limit bounds any generic increase.
      schema:
        type: integer
        minimum: 1
    ReasoningEffort:
      name: reasoning_effort
      in: query
      required: false
      description: Non-blank effort supported by the resolved route. Omission selects the tenant or route default.
      schema:
        type: string
        minLength: 1
    ResponseFormat:
      name: format
      in: query
      required: false
      description: Preferred response media type. Unknown values select text/plain.
      schema:
        type: string
        enum:
          - text/plain
          - application/json
          - application/xml
          - text/xml
          - text/csv
    Accept:
      name: Accept
      in: header
      required: false
      description: Response media preference used when format is omitted.
      schema:
        type: string
    RequestTimeout:
      name: X-LLM-Proxy-Request-Timeout-Seconds
      in: header
      required: false
      description: A positive whole-second request budget no greater than the server maximum. Omission selects the configured default.
      schema:
        type: integer
        minimum: 1
    AssetSHA256:
      name: X-LLM-Proxy-Asset-SHA256
      in: header
      required: true
      description: Lowercase hexadecimal SHA-256 of the exact request body.
      schema:
        type: string
        pattern: ^[0-9a-f]{64}$
    AssetID:
      name: asset_id
      in: path
      required: true
      description: Opaque tenant asset identifier.
      schema:
        type: string
        pattern: ^ast_[0-9a-f]{32}$
    TenantID:
      name: tenant_id
      in: path
      required: true
      description: Opaque tenant identifier from the authenticated account response.
      schema:
        type: string
        minLength: 1
    ProviderPath:
      name: provider
      in: path
      required: true
      description: Canonical provider identifier from the public capability catalog, such as zai. Retired zhipu and glm values are invalid.
      schema:
        type: string
        minLength: 1
    UsageInterval:
      name: interval
      in: query
      required: true
      schema:
        type: string
        enum:
          - 1d
          - 7d
          - 30d
          - all
    UsageFailureLimit:
      name: limit
      in: query
      required: false
      description: Maximum failure rows in this page. Omission selects 25.
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 25
    UsageFailureCursor:
      name: cursor
      in: query
      required: false
      description: Opaque continuation cursor returned by the preceding page for the same interval and reporting scope.
      schema:
        type: string
        minLength: 1
    OptionalOrigin:
      name: Origin
      in: header
      required: false
      description: When supplied, must exactly match the configured public origin for mutations. Matching origins receive credentialed CORS headers.
      schema:
        type: string
        format: uri
    RequiredOrigin:
      name: Origin
      in: header
      required: true
      description: Must exactly match the configured public origin.
      schema:
        type: string
        format: uri
  requestBodies:
    TextRequest:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/TextRequest'
    V2Request:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/V2Request'
    DictationRequest:
      required: true
      content:
        multipart/form-data:
          schema:
            $ref: '#/components/schemas/DictationRequest'
          encoding:
            audio:
              contentType: audio/*,application/octet-stream
    AssetUpload:
      required: true
      content:
        image/jpeg:
          schema:
            type: string
            format: binary
        image/png:
          schema:
            type: string
            format: binary
        image/webp:
          schema:
            type: string
            format: binary
        audio/m4a:
          schema:
            type: string
            format: binary
        audio/mpeg:
          schema:
            type: string
            format: binary
        audio/wav:
          schema:
            type: string
            format: binary
    TenantNameRequest:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/TenantNameRequest'
    ProviderKeyRequest:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ProviderKeyRequest'
    DefaultsRequest:
      required: true
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/DefaultsRequest'
    EmptyJSONRequest:
      required: false
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/EmptyObject'
  responses:
    TextSuccess:
      description: 'Complete generated text in the selected representation. The selected model has one validated wire contract and one execution lifecycle; no lifecycle is inferred from an endpoint or upstream id. The proxy internally observes queued and in_progress states for OpenAI Responses and background-capable Gemini Interactions while keeping every public operation blocking; synchronous Gemini Interactions must return an immediate terminal state. Separately, it continues exact output-budget stops through new provider calls: OpenAI Responses incomplete/max_output_tokens, OpenAI-compatible Chat Completions length, Gemini Interactions incomplete, and Anthropic max_tokens. HTTP 200 is returned only after the adapter reports its complete signal: OpenAI or Gemini completed, Chat stop, or Anthropic end_turn|stop_sequence. Intermediate, safety, refusal, tool, malformed, missing, and unknown states never return text as success.'
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
        X-LLM-Proxy-Request-Tokens:
          $ref: '#/components/headers/OptionalTokenCount'
        X-LLM-Proxy-Response-Tokens:
          $ref: '#/components/headers/OptionalTokenCount'
        X-LLM-Proxy-Total-Tokens:
          $ref: '#/components/headers/OptionalTokenCount'
      content:
        text/plain:
          schema:
            type: string
        application/json:
          schema:
            $ref: '#/components/schemas/TextJSONResponse'
        application/xml:
          schema:
            type: string
        text/csv:
          schema:
            type: string
    DictationSuccess:
      description: Transcription result.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/DictationResponse'
    ProxyBadRequest:
      description: The request is malformed, names an invalid route/capability, or supplies an invalid timeout. Text validation failures use the canonical plain-text error. Timeout-header validation uses the canonical JSON error.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/OptionalResolvedRequestTimeout'
      content:
        text/plain:
          schema:
            type: string
        application/json:
          schema:
            $ref: '#/components/schemas/ProxyErrorEnvelope'
    ProxyForbidden:
      description: The tenant client key is absent or unknown.
      content:
        text/plain:
          schema:
            type: string
            const: unknown client key
    ProxyPayloadTooLarge:
      description: The compatibility JSON request limit, dictation audio limit, tenant asset limit, or selected provider media limit was exceeded.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
      content:
        text/plain:
          schema:
            type: string
        application/json:
          schema:
            $ref: '#/components/schemas/ProviderErrorEnvelope'
    V2BadRequest:
      description: The canonical message input or referenced asset is invalid.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/OptionalResolvedRequestTimeout'
      content:
        text/plain:
          schema:
            type: string
        application/json:
          schema:
            oneOf:
              - $ref: '#/components/schemas/ProxyErrorEnvelope'
              - $ref: '#/components/schemas/AssetErrorEnvelope'
    AssetCreated:
      description: The asset is available to its authenticated tenant.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/TenantAsset'
    AssetFailure:
      description: The asset operation failed with a stable safe code.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/OptionalResolvedRequestTimeout'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AssetErrorEnvelope'
    ProxyRateLimited:
      description: The selected upstream provider returned HTTP 429. The proxy preserves 429 at its public boundary and returns only sanitized provider metadata; it never exposes the raw provider body or message.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
        X-LLM-Proxy-Request-ID:
          $ref: '#/components/headers/ProxyRequestID'
        Retry-After:
          $ref: '#/components/headers/SafeRetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ProviderErrorEnvelope'
    CallerClosed:
      description: The caller canceled or closed the request.
    ProxyBadGateway:
      description: The selected upstream provider failed, returned a non-429 unsuccessful HTTP status, or returned an unusable success payload. Output-budget stops are continued internally and do not create this response. The response contains only sanitized provider metadata and never exposes partial generated text, token-count headers, a raw provider body, or a provider error message; provider-reported usage can still be retained in managed failure accounting.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
        X-LLM-Proxy-Request-ID:
          $ref: '#/components/headers/ProxyRequestID'
        Retry-After:
          $ref: '#/components/headers/SafeRetryAfter'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ProviderErrorEnvelope'
    ProxyUnavailable:
      description: The selected provider is not configured or the bounded request queue is full.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
      content:
        text/plain:
          schema:
            type: string
    ProxyTimeout:
      description: The proxy request budget or upstream operation timed out.
      headers:
        X-LLM-Proxy-Request-Timeout-Seconds:
          $ref: '#/components/headers/ResolvedRequestTimeout'
      content:
        text/plain:
          schema:
            type: string
        application/json:
          schema:
            $ref: '#/components/schemas/ProxyErrorEnvelope'
    AccountSuccess:
      description: Authenticated account snapshot.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ManagementAccount'
    TenantProfileSuccess:
      description: Current tenant profile.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/TenantProfile'
    TenantProfileCreated:
      description: Created tenant profile.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/TenantProfile'
    UsageSuccess:
      description: Usage summary for the exact requested interval and authenticated reporting scope.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/UsageSummary'
    UsageFailuresSuccess:
      description: Snapshot page of safe tenant failure details for the exact requested interval.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/UsageFailurePage'
    AccountUsageFailuresSuccess:
      description: Snapshot page of safe failure details across every owned tenant for the exact requested interval.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AccountUsageFailurePage'
    AdminUsersSuccess:
      description: Administrative user and tenant usage summary.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/AdminUsersSummary'
    ProviderKeyRevealSuccess:
      description: The saved provider credential. Never persist or log this response.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ProviderKeyReveal'
    TenantSecretSuccess:
      description: The newly generated tenant client secret and current profile. The secret is returned only by this response.
      headers:
        Cache-Control:
          $ref: '#/components/headers/NoStore'
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/TenantSecret'
    ManagementBadRequest:
      description: Malformed or invalid management input.
      content:
        text/plain:
          schema:
            type: string
    ManagementUnauthorized:
      description: The TAuth session is absent or invalid.
    ManagementForbidden:
      description: The user lacks the required role or the supplied Origin is not allowed.
    ManagementNotFound:
      description: The tenant or provider credential does not exist within the authenticated ownership boundary.
    ManagementConflict:
      description: The requested tenant name conflicts, the final owned tenant cannot be deleted, or a retained provider credential changed after verification began.
      content:
        text/plain:
          schema:
            type: string
    ManagementUnsupportedMediaType:
      description: A management mutation did not supply application/json.
    ProviderKeyRejected:
      description: The candidate credential was rejected or cannot access the selected text model. Nothing was saved.
      content:
        text/plain:
          schema:
            type: string
            const: provider_key_rejected
    ProviderKeyVerificationRateLimited:
      description: The provider rate-limited the single verification operation. The credential remains unconfirmed and nothing was saved.
      content:
        text/plain:
          schema:
            type: string
            const: provider_key_verification_rate_limited
    ProviderKeyVerificationUnavailable:
      description: The provider was unavailable or returned a malformed success envelope. The credential remains unconfirmed and nothing was saved.
      content:
        text/plain:
          schema:
            type: string
            const: provider_key_verification_unavailable
    ProviderKeyVerificationTimedOut:
      description: The single verification operation timed out or was canceled. The credential remains unconfirmed and nothing was saved.
      content:
        text/plain:
          schema:
            type: string
            const: provider_key_verification_timed_out
    ManagementInternalError:
      description: The management operation failed internally.
      content:
        text/plain:
          schema:
            type: string
  headers:
    ResolvedRequestTimeout:
      description: The resolved whole-second budget used for the request.
      schema:
        type: integer
        minimum: 1
      x-required: true
    OptionalResolvedRequestTimeout:
      description: Present after the supplied timeout header passes validation.
      schema:
        type: integer
        minimum: 1
    ProxyRequestID:
      description: Proxy-owned identifier matching error.request_id and the request_id field in structured proxy logs.
      schema:
        type: string
        minLength: 1
      x-required: true
    SafeRetryAfter:
      description: Present only when the provider supplied a syntactically valid Retry-After value. Delta seconds are normalized to unsigned decimal form and HTTP dates are normalized to IMF-fixdate.
      schema:
        type: string
        minLength: 1
    OptionalTokenCount:
      description: Provider-reported token count when available.
      schema:
        type: integer
        minimum: 0
    NoStore:
      description: Prevents persistence of authenticated or secret-bearing management responses.
      schema:
        type: string
        const: no-store
      x-required: true
  schemas:
    PublicCapabilityCatalog:
      type: object
      additionalProperties: false
      required:
        - revision
        - operations
        - providers
        - publishers
        - families
        - models
        - offerings
        - prices
        - counts
        - max_prompt_bytes
        - max_input_audio_bytes
        - max_request_timeout_seconds
      properties:
        revision:
          type: string
          minLength: 1
        operations:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PublicModelOperation'
        providers:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PublicProviderCapability'
        publishers:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PublicModelPublisher'
        families:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PublicModelFamily'
        models:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PublicExactModelCapability'
        offerings:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PublicProviderOffering'
        prices:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/PublicPriceDescriptor'
        counts:
          $ref: '#/components/schemas/PublicCapabilityCounts'
        max_prompt_bytes:
          type: integer
          format: int64
          minimum: 1
        max_input_audio_bytes:
          type: integer
          format: int64
          minimum: 1
        max_request_timeout_seconds:
          type: integer
          minimum: 1
    PublicProviderCapability:
      type: object
      additionalProperties: false
      required:
        - identifier
        - label
        - credential_kinds
      properties:
        identifier:
          type: string
          minLength: 1
        label:
          type: string
          minLength: 1
        credential_kinds:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            enum:
              - api_key
    PublicModelOperation:
      type: object
      additionalProperties: false
      required:
        - id
        - input_artifacts
        - output_artifacts
      properties:
        id:
          type: string
          enum:
            - text
            - dictation
            - video_generation
        input_artifacts:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            $ref: '#/components/schemas/PublicArtifactKind'
        output_artifacts:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            $ref: '#/components/schemas/PublicArtifactKind'
    PublicArtifactKind:
      type: string
      enum:
        - text
        - image
        - audio
        - video
    PublicModelPublisher:
      type: object
      additionalProperties: false
      required:
        - identifier
        - label
        - model_count
      properties:
        identifier:
          type: string
          minLength: 1
        label:
          type: string
          minLength: 1
        model_count:
          type: integer
          minimum: 1
    PublicModelFamily:
      type: object
      additionalProperties: false
      required:
        - identifier
        - publisher
        - label
        - weight_access
      properties:
        identifier:
          type: string
          minLength: 1
        publisher:
          type: string
          minLength: 1
        label:
          type: string
          minLength: 1
        weight_access:
          type: string
          enum:
            - proprietary
            - open_weights
    PublicExactModelCapability:
      type: object
      additionalProperties: false
      required:
        - identifier
        - publisher
        - family
        - version
        - operations
        - media_inputs
        - capabilities
        - provider_offerings
      properties:
        identifier:
          type: string
          minLength: 1
        publisher:
          type: string
          minLength: 1
        family:
          type: string
          minLength: 1
        version:
          type: string
          minLength: 1
        operations:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            enum:
              - text
              - dictation
              - video_generation
        media_inputs:
          type: array
          uniqueItems: true
          items:
            type: string
            enum:
              - image
              - audio
        capabilities:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            enum:
              - text
              - dictation
              - web_search
              - image_input
              - audio_input
              - reasoning
              - video_generation
        provider_offerings:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            minLength: 1
    PublicProviderOffering:
      type: object
      additionalProperties: false
      required:
        - identifier
        - provider
        - model
        - capabilities
        - wire_contract
        - execution_lifecycle
        - output_token_limit
        - reasoning_efforts
        - controls
        - limits
        - media_limits
      properties:
        identifier:
          type: string
          minLength: 1
        provider:
          type: string
          minLength: 1
        model:
          type: string
          minLength: 1
        capabilities:
          type: array
          minItems: 1
          uniqueItems: true
          items:
            type: string
            enum:
              - text
              - dictation
              - web_search
              - image_input
              - audio_input
              - reasoning
              - video_generation
        wire_contract:
          type: string
          minLength: 1
        execution_lifecycle:
          type: string
          enum:
            - synchronous_completion
            - pollable_resource
        output_token_limit:
          type: integer
          minimum: 0
        reasoning_efforts:
          type: array
          uniqueItems: true
          items:
            type: string
            minLength: 1
        controls:
          type: array
          items:
            $ref: '#/components/schemas/PublicCatalogControl'
        limits:
          type: array
          items:
            $ref: '#/components/schemas/PublicCatalogLimit'
        media_limits:
          type: array
          items:
            $ref: '#/components/schemas/PublicCatalogMediaLimit'
    PublicCatalogControl:
      type: object
      additionalProperties: false
      required:
        - id
        - kind
        - values
        - minimum
        - maximum
        - account_dependent
      properties:
        id:
          type: string
          minLength: 1
        kind:
          type: string
          enum:
            - enum
            - integer
            - boolean
        values:
          type: array
          uniqueItems: true
          items:
            type: string
            minLength: 1
        minimum:
          oneOf:
            - type: integer
              minimum: 0
            - type: 'null'
        maximum:
          oneOf:
            - type: integer
              minimum: 0
            - type: 'null'
        account_dependent:
          type: boolean
    PublicCatalogLimit:
      type: object
      additionalProperties: false
      required:
        - id
        - value
        - unit
        - account_dependent
      properties:
        id:
          type: string
          minLength: 1
        value:
          oneOf:
            - type: integer
              minimum: 0
            - type: 'null'
        unit:
          type: string
          minLength: 1
        account_dependent:
          type: boolean
    PublicCatalogMediaLimit:
      type: object
      additionalProperties: false
      required:
        - id
        - media_type
        - transport
        - status
        - value
        - unit
        - scope
        - source
        - last_verified
      properties:
        id:
          type: string
          minLength: 1
        media_type:
          type: string
          enum:
            - all
            - image
            - audio
        transport:
          type: string
          enum:
            - any
            - inline
            - file
        status:
          type: string
          enum:
            - bounded
            - unbounded
            - unknown
        value:
          oneOf:
            - type: integer
              minimum: 1
            - type: 'null'
        unit:
          type: string
          enum:
            - bytes
            - files
        scope:
          type: string
          enum:
            - attachment
            - attachment_encoded_bytes
            - request
            - request_encoded_bytes
        source:
          type: string
          format: uri
          pattern: '^https://'
        last_verified:
          type: string
          format: date
    PublicPriceDescriptor:
      type: object
      additionalProperties: false
      required:
        - provider
        - model
        - operation
        - available
        - rates
        - minimum_charge
        - source
        - last_verified
        - unavailable_reason
      properties:
        provider:
          type: string
          minLength: 1
        model:
          type: string
          minLength: 1
        operation:
          type: string
          enum:
            - text
            - dictation
            - video_generation
        available:
          type: boolean
        rates:
          type: array
          items:
            $ref: '#/components/schemas/PublicPriceRate'
        minimum_charge:
          oneOf:
            - $ref: '#/components/schemas/PublicMinimumCharge'
            - type: 'null'
        source:
          type: string
          format: uri
          pattern: '^https://'
        last_verified:
          type: string
          format: date
        unavailable_reason:
          type: string
    PublicPriceRate:
      type: object
      additionalProperties: false
      required:
        - component
        - currency
        - rate
        - unit
        - conditions
      properties:
        component:
          type: string
          minLength: 1
        currency:
          type: string
          const: USD
        rate:
          type: number
          minimum: 0
        unit:
          type: string
          minLength: 1
        conditions:
          $ref: '#/components/schemas/PublicPriceConditions'
    PublicMinimumCharge:
      type: object
      additionalProperties: false
      required:
        - currency
        - amount
        - unit
      properties:
        currency:
          type: string
          const: USD
        amount:
          type: number
          minimum: 0
        unit:
          type: string
          minLength: 1
    PublicPriceConditions:
      type: object
      additionalProperties: false
      required:
        - resolution
        - generated_audio
        - input_media
        - output_media
        - duration
        - quantity
        - quality
        - mode
        - api_version
        - avatar_type
        - billing_mode
        - billing_outcome
      properties:
        resolution: {type: string}
        generated_audio: {type: string}
        input_media: {type: string}
        output_media: {type: string}
        duration: {type: string}
        quantity: {type: string}
        quality: {type: string}
        mode: {type: string}
        api_version: {type: string}
        avatar_type: {type: string}
        billing_mode: {type: string}
        billing_outcome: {type: string}
    PublicCapabilityCounts:
      type: object
      additionalProperties: false
      required:
        - providers
        - model_publishers
        - model_families
        - exact_models
        - provider_offerings
      properties:
        providers:
          type: integer
          minimum: 1
        model_publishers:
          type: integer
          minimum: 1
        model_families:
          type: integer
          minimum: 1
        exact_models:
          type: integer
          minimum: 1
        provider_offerings:
          type: integer
          minimum: 1
    ChatMessage:
      type: object
      additionalProperties: false
      required:
        - role
        - content
      properties:
        role:
          type: string
          enum:
            - system
            - user
            - assistant
        content:
          type: string
          minLength: 1
        order:
          type: integer
          minimum: 0
    MessageAttachment:
      description: One provider-neutral image or audio input with a MIME type that matches its declared media type. The resolved catalog route determines support. Current Moonshot Kimi image routes accept the image variants.
      oneOf:
        - $ref: '#/components/schemas/ImageMessageAttachment'
        - $ref: '#/components/schemas/AudioMessageAttachment'
        - $ref: '#/components/schemas/ImageAssetMessageAttachment'
        - $ref: '#/components/schemas/AudioAssetMessageAttachment'
    ImageMessageAttachment:
      type: object
      additionalProperties: false
      required:
        - type
        - mime_type
        - data
        - sha256
      properties:
        type:
          type: string
          const: image
        mime_type:
          type: string
          enum:
            - image/jpeg
            - image/png
            - image/webp
        data:
          type: string
          minLength: 4
          description: Exact nonempty media bytes encoded as canonical padded RFC 4648 base64.
        sha256:
          type: string
          pattern: ^[0-9a-f]{64}$
          description: Lowercase hexadecimal SHA-256 of the decoded media bytes.
    AudioMessageAttachment:
      type: object
      additionalProperties: false
      required:
        - type
        - mime_type
        - data
        - sha256
      properties:
        type:
          type: string
          const: audio
        mime_type:
          type: string
          enum:
            - audio/m4a
            - audio/mpeg
            - audio/wav
        data:
          type: string
          minLength: 4
          description: Exact nonempty media bytes encoded as canonical padded RFC 4648 base64.
        sha256:
          type: string
          pattern: ^[0-9a-f]{64}$
          description: Lowercase hexadecimal SHA-256 of the decoded media bytes.
    ImageAssetMessageAttachment:
      type: object
      additionalProperties: false
      required:
        - type
        - mime_type
        - asset_id
        - sha256
      properties:
        type:
          type: string
          const: image
        mime_type:
          type: string
          enum:
            - image/jpeg
            - image/png
            - image/webp
        asset_id:
          type: string
          pattern: ^ast_[0-9a-f]{32}$
        sha256:
          type: string
          pattern: ^[0-9a-f]{64}$
    AudioAssetMessageAttachment:
      type: object
      additionalProperties: false
      required:
        - type
        - mime_type
        - asset_id
        - sha256
      properties:
        type:
          type: string
          const: audio
        mime_type:
          type: string
          enum:
            - audio/m4a
            - audio/mpeg
            - audio/wav
        asset_id:
          type: string
          pattern: ^ast_[0-9a-f]{32}$
        sha256:
          type: string
          pattern: ^[0-9a-f]{64}$
    TenantAsset:
      type: object
      additionalProperties: false
      required:
        - asset_id
        - mime_type
        - size_bytes
        - sha256
        - state
        - created_at
        - expires_at
      properties:
        asset_id:
          type: string
          pattern: ^ast_[0-9a-f]{32}$
        mime_type:
          type: string
          enum:
            - image/jpeg
            - image/png
            - image/webp
            - audio/m4a
            - audio/mpeg
            - audio/wav
        size_bytes:
          type: integer
          format: int64
          minimum: 1
        sha256:
          type: string
          pattern: ^[0-9a-f]{64}$
        state:
          type: string
          const: available
        created_at:
          type: string
          format: date-time
        expires_at:
          type: string
          format: date-time
    AssetErrorEnvelope:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
          properties:
            code:
              type: string
              enum:
                - asset_invalid
                - asset_not_found
                - asset_expired
                - asset_deleted
                - asset_mime_mismatch
                - asset_digest_mismatch
                - asset_too_large
                - asset_store_error
    V2ChatMessage:
      description: A user message that may carry attachments, or a text-only system or assistant message.
      oneOf:
        - $ref: '#/components/schemas/V2UserChatMessage'
        - $ref: '#/components/schemas/V2SystemOrAssistantChatMessage'
    V2UserChatMessage:
      type: object
      additionalProperties: false
      required:
        - role
        - content
      properties:
        role:
          type: string
          const: user
        content:
          type: string
          minLength: 1
        attachments:
          type: array
          minItems: 1
          description: Ordered exact media inputs accepted only when the resolved model declares each media type.
          items:
            $ref: '#/components/schemas/MessageAttachment'
        order:
          type: integer
          minimum: 0
    V2SystemOrAssistantChatMessage:
      type: object
      additionalProperties: false
      required:
        - role
        - content
      properties:
        role:
          type: string
          enum:
            - system
            - assistant
        content:
          type: string
          minLength: 1
        order:
          type: integer
          minimum: 0
    TextRequest:
      type: object
      additionalProperties: false
      properties:
        prompt:
          type: string
          minLength: 1
        messages:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/ChatMessage'
        model:
          type: string
          minLength: 1
        web_search:
          type: boolean
        system_prompt:
          type: string
        max_tokens:
          type: integer
          minimum: 1
          description: Initial per-attempt output budget. Reused for missing-suffix attempts, with any zero-progress increase bounded by the configured model output limit.
        reasoning_effort:
          type: string
          minLength: 1
    V2Request:
      type: object
      additionalProperties: false
      required:
        - messages
      properties:
        messages:
          type: array
          minItems: 1
          description: All messages must have an allowed role and non-blank content, include at least one user message, and either all omit order or all provide unique non-negative order values. Only user messages may carry attachments; message order and attachment order are preserved.
          items:
            $ref: '#/components/schemas/V2ChatMessage'
        model:
          type: string
          minLength: 1
          description: Omission selects the resolved provider default.
        web_search:
          type: boolean
          description: The resolved route must declare web-search capability when true.
        max_tokens:
          type: integer
          minimum: 1
          description: Initial per-attempt output budget. Reused for missing-suffix attempts, with any zero-progress increase bounded by the configured model output limit.
        reasoning_effort:
          type: string
          minLength: 1
          description: Omission selects the tenant or route default. An explicit value must be non-blank and supported by the resolved provider/model route. Kimi K3 accepts low, high, or max.
    DictationRequest:
      type: object
      additionalProperties: false
      required:
        - audio
      properties:
        audio:
          type: string
          format: binary
          description: The canonical incoming audio file part.
    DictationResponse:
      type: object
      additionalProperties: false
      required:
        - text
      properties:
        text:
          type: string
    TokenUsage:
      type: object
      additionalProperties: false
      required:
        - request_tokens
        - response_tokens
        - total_tokens
      properties:
        request_tokens:
          type: integer
          minimum: 0
        response_tokens:
          type: integer
          minimum: 0
        total_tokens:
          type: integer
          minimum: 0
    TextJSONResponse:
      type: object
      additionalProperties: false
      required:
        - request
        - response
        - object
        - model
        - choices
        - messages
      properties:
        request:
          type: string
        response:
          type: string
        object:
          type: string
          const: chat.completion
        model:
          type: string
        choices:
          type: array
          minItems: 1
          items:
            $ref: '#/components/schemas/Choice'
        messages:
          type: array
          items:
            $ref: '#/components/schemas/ResponseMessage'
        usage:
          $ref: '#/components/schemas/TokenUsage'
    Choice:
      type: object
      additionalProperties: false
      required:
        - index
        - finish_reason
        - message
      properties:
        index:
          type: integer
          minimum: 0
        finish_reason:
          type: string
          const: stop
        message:
          $ref: '#/components/schemas/ResponseMessage'
    ResponseMessage:
      type: object
      additionalProperties: false
      required:
        - role
        - content
      properties:
        role:
          type: string
          enum:
            - system
            - user
            - assistant
        content:
          type: string
        order:
          type: integer
          minimum: 0
    ProxyErrorEnvelope:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
          properties:
            code:
              type: string
              enum:
                - invalid_request_timeout
                - request_timeout
            max_request_timeout_seconds:
              type: integer
              minimum: 1
            request_timeout_seconds:
              type: integer
              minimum: 1
    ProviderErrorEnvelope:
      type: object
      additionalProperties: false
      required:
        - error
      properties:
        error:
          type: object
          additionalProperties: false
          required:
            - code
            - provider
            - upstream_status
            - retryable
            - request_id
            - retry_after
          properties:
            code:
              type: string
              enum:
                - provider_error
                - provider_media_limit_exceeded
                - provider_rate_limited
            provider:
              type: string
              minLength: 1
              description: Canonical provider selector resolved for the request.
            upstream_status:
              oneOf:
                - type: integer
                  minimum: 100
                  maximum: 599
                - type: 'null'
              description: Exact provider HTTP status when an upstream response was received; null for transport, request-construction, and response-protocol failures without a usable unsuccessful HTTP response.
            retryable:
              type: boolean
              description: True only for upstream HTTP 408, 425, 429, 500, 502, 503, or 504. This classifies the provider condition; clients remain responsible for duplicate-work and billing consequences before retrying.
            request_id:
              type: string
              minLength: 1
              description: Proxy-owned correlation identifier also returned in X-LLM-Proxy-Request-ID and recorded in structured proxy logs.
            retry_after:
              oneOf:
                - type: string
                  minLength: 1
                - type: 'null'
              description: Validated and normalized provider Retry-After value, or null when the provider omitted it or supplied an invalid value. A non-null value is also returned in the Retry-After response header.
    TenantNameRequest:
      type: object
      additionalProperties: false
      required:
        - name
      properties:
        name:
          type: string
          minLength: 1
    ProviderKeyRequest:
      type: object
      additionalProperties: false
      required:
        - api_key
        - base_url
        - text_model
        - system_prompt
      properties:
        api_key:
          type: string
          description: An unverified new or replacement provider key. A nonempty value is verified against the exact path provider, selected text_model, and submitted base_url before any persistence. Send an empty string to retain the tenant's existing verified credential; an empty value is rejected when no credential exists.
        base_url:
          type: string
          description: Exact tenant-owned Singapore Model Studio URL for dashscope. It must use https://{resource-id}.ap-southeast-1.maas.aliyuncs.com/compatible-mode/v1. It must be empty for every other provider.
        text_model:
          type: string
          minLength: 1
        system_prompt:
          type: string
    DefaultsRequest:
      type: object
      additionalProperties: false
      required:
        - provider
        - model
        - dictation_provider
        - dictation_model
        - system_prompt
        - reasoning_effort
      properties:
        provider:
          type: string
          description: Canonical keyed text-provider id, or empty together with model when the tenant has no saved provider key.
        model:
          type: string
          description: Canonical model for provider, or empty together with provider when the tenant has no saved provider key.
        dictation_provider:
          type: string
          description: Canonical keyed dictation-capable provider id, or empty together with dictation_model when no keyed provider supports dictation.
        dictation_model:
          type: string
          description: Canonical model for dictation_provider, or empty together with dictation_provider when no keyed provider supports dictation.
        system_prompt:
          type: string
        reasoning_effort:
          type: string
    EmptyObject:
      type: object
      additionalProperties: false
      properties: {}
    ManagementAccount:
      type: object
      additionalProperties: false
      required:
        - user
        - tenants
      properties:
        user:
          $ref: '#/components/schemas/ManagementUser'
        tenants:
          type: array
          items:
            $ref: '#/components/schemas/TenantSummary'
    ManagementUser:
      type: object
      additionalProperties: false
      required:
        - id
        - is_admin
      properties:
        id:
          type: string
          minLength: 1
        email:
          type: string
        display_name:
          type: string
        avatar_url:
          type: string
        is_admin:
          type: boolean
    TenantSummary:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - has_secret
        - created_at
        - updated_at
      properties:
        id:
          type: string
        name:
          type: string
        has_secret:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    TenantProfile:
      type: object
      additionalProperties: false
      required:
        - tenant
        - providers
        - proxy
      properties:
        tenant:
          $ref: '#/components/schemas/Tenant'
        providers:
          type: array
          items:
            $ref: '#/components/schemas/ProviderProfile'
        proxy:
          $ref: '#/components/schemas/ProxyPaths'
    Tenant:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - has_secret
        - defaults
        - created_at
        - updated_at
      properties:
        id:
          type: string
        name:
          type: string
        has_secret:
          type: boolean
        defaults:
          $ref: '#/components/schemas/TenantDefaults'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    TenantDefaults:
      type: object
      additionalProperties: false
      required:
        - provider
        - model
        - dictation_provider
        - dictation_model
        - system_prompt
        - reasoning_effort
      properties:
        provider:
          type: string
          description: Canonical keyed text-provider id, or empty when the tenant has no saved provider key.
        model:
          type: string
          description: Canonical text model paired with provider, or empty when provider is empty.
        dictation_provider:
          type: string
          description: Canonical keyed dictation-capable provider id, or empty when no keyed provider supports dictation.
        dictation_model:
          type: string
          description: Canonical dictation model paired with dictation_provider, or empty when dictation_provider is empty.
        system_prompt:
          type: string
        reasoning_effort:
          type: string
    ProviderProfile:
      type: object
      additionalProperties: false
      required:
        - id
        - label
        - aliases
        - has_key
        - base_url
        - text_model
        - system_prompt
        - text_default_model
        - text_models
        - supports_dictation
        - dictation_models
      properties:
        id:
          type: string
        label:
          type: string
        aliases:
          type: array
          items:
            type: string
        has_key:
          type: boolean
        masked_key:
          type: string
        base_url:
          type: string
          description: Saved tenant-owned DashScope API URL, or empty for an unconfigured DashScope provider and every other provider.
        text_model:
          type: string
        system_prompt:
          type: string
        text_default_model:
          type: string
        text_models:
          type: array
          items:
            $ref: '#/components/schemas/TextModel'
        supports_dictation:
          type: boolean
        dictation_default_model:
          type: string
        dictation_models:
          type: array
          items:
            type: string
    TextModel:
      type: object
      additionalProperties: false
      required:
        - id
      properties:
        id:
          type: string
        reasoning_effort:
          $ref: '#/components/schemas/ReasoningEffortCapability'
    ReasoningEffortCapability:
      type: object
      additionalProperties: false
      required:
        - adapter
        - efforts
      properties:
        adapter:
          type: string
        efforts:
          type: array
          items:
            type: string
    ProxyPaths:
      type: object
      additionalProperties: false
      required:
        - text_path
        - v2_path
        - dictation_path
      properties:
        text_path:
          type: string
          const: /
        v2_path:
          type: string
          const: /v2
        dictation_path:
          type: string
          const: /dictate
    TenantSecret:
      type: object
      additionalProperties: false
      required:
        - secret
        - profile
      properties:
        secret:
          type: string
          minLength: 1
        profile:
          $ref: '#/components/schemas/TenantProfile'
    ProviderKeyReveal:
      type: object
      additionalProperties: false
      required:
        - api_key
      properties:
        api_key:
          type: string
          minLength: 1
    UsageAggregate:
      type: object
      additionalProperties: false
      required:
        - requests
        - successful_requests
        - failed_requests
        - text_requests
        - dictation_requests
        - request_tokens
        - response_tokens
        - total_tokens
        - average_latency_ms
      properties:
        requests:
          type: integer
          minimum: 0
        successful_requests:
          type: integer
          minimum: 0
        failed_requests:
          type: integer
          minimum: 0
        text_requests:
          type: integer
          minimum: 0
        dictation_requests:
          type: integer
          minimum: 0
        request_tokens:
          type: integer
          minimum: 0
        response_tokens:
          type: integer
          minimum: 0
        total_tokens:
          type: integer
          minimum: 0
        average_latency_ms:
          type: integer
          minimum: 0
    UsageBucket:
      type: object
      additionalProperties: false
      required:
        - start
        - data
      properties:
        start:
          type: string
          format: date-time
        data:
          $ref: '#/components/schemas/UsageAggregate'
    UsageProvider:
      type: object
      additionalProperties: false
      required:
        - provider
        - data
      properties:
        provider:
          type: string
        data:
          $ref: '#/components/schemas/UsageAggregate'
    UsageModel:
      type: object
      additionalProperties: false
      required:
        - provider
        - model
        - data
      properties:
        provider:
          type: string
        model:
          type: string
        data:
          $ref: '#/components/schemas/UsageAggregate'
    UsageStatus:
      type: object
      additionalProperties: false
      required:
        - status_code
        - requests
      properties:
        status_code:
          type: integer
          minimum: 100
        requests:
          type: integer
          minimum: 0
    UsageSummary:
      type: object
      additionalProperties: false
      required:
        - interval
        - bucket_unit
        - totals
        - buckets
        - providers
        - models
        - status_codes
      properties:
        interval:
          type: string
          enum:
            - 1d
            - 7d
            - 30d
            - all
        bucket_unit:
          type: string
          enum:
            - hour
            - day
            - month
        totals:
          $ref: '#/components/schemas/UsageAggregate'
        buckets:
          type: array
          items:
            $ref: '#/components/schemas/UsageBucket'
        providers:
          type: array
          items:
            $ref: '#/components/schemas/UsageProvider'
        models:
          type: array
          items:
            $ref: '#/components/schemas/UsageModel'
        status_codes:
          type: array
          items:
            $ref: '#/components/schemas/UsageStatus'
    UsageOutcomeCode:
      type: string
      enum:
        - success
        - invalid_request
        - payload_too_large
        - rate_limited
        - service_unavailable
        - request_timeout
        - upstream_error
    UsageFailure:
      type: object
      additionalProperties: false
      required:
        - occurred_at
        - endpoint
        - provider
        - model
        - status_code
        - outcome_code
        - latency_ms
      properties:
        occurred_at:
          type: string
          format: date-time
        endpoint:
          type: string
        provider:
          type: string
        model:
          type: string
        status_code:
          type: integer
          minimum: 100
          maximum: 599
        outcome_code:
          $ref: '#/components/schemas/UsageOutcomeCode'
        latency_ms:
          type: integer
          minimum: 0
    UsageFailurePage:
      type: object
      additionalProperties: false
      required:
        - interval
        - failures
      properties:
        interval:
          type: string
          enum:
            - 1d
            - 7d
            - 30d
            - all
        failures:
          type: array
          items:
            $ref: '#/components/schemas/UsageFailure'
        next_cursor:
          type: string
          minLength: 1
    AccountUsageFailure:
      type: object
      additionalProperties: false
      required:
        - tenant_id
        - tenant_name
        - occurred_at
        - endpoint
        - provider
        - model
        - status_code
        - outcome_code
        - latency_ms
      properties:
        tenant_id:
          type: string
          minLength: 1
        tenant_name:
          type: string
          minLength: 1
        occurred_at:
          type: string
          format: date-time
        endpoint:
          type: string
        provider:
          type: string
        model:
          type: string
        status_code:
          type: integer
          minimum: 100
          maximum: 599
        outcome_code:
          $ref: '#/components/schemas/UsageOutcomeCode'
        latency_ms:
          type: integer
          minimum: 0
    AccountUsageFailurePage:
      type: object
      additionalProperties: false
      required:
        - interval
        - failures
      properties:
        interval:
          type: string
          enum:
            - 1d
            - 7d
            - 30d
            - all
        failures:
          type: array
          items:
            $ref: '#/components/schemas/AccountUsageFailure'
        next_cursor:
          type: string
          minLength: 1
    AdminUsageSummary:
      type: object
      additionalProperties: false
      required:
        - period_days
        - totals
        - daily
        - providers
        - models
        - status_codes
      properties:
        period_days:
          type: integer
          minimum: 1
        totals:
          $ref: '#/components/schemas/UsageAggregate'
        daily:
          type: array
          items:
            type: object
            additionalProperties: false
            required:
              - date
              - data
            properties:
              date:
                type: string
                format: date
              data:
                $ref: '#/components/schemas/UsageAggregate'
        providers:
          type: array
          items:
            $ref: '#/components/schemas/UsageProvider'
        models:
          type: array
          items:
            $ref: '#/components/schemas/UsageModel'
        status_codes:
          type: array
          items:
            $ref: '#/components/schemas/UsageStatus'
    AdminTenant:
      type: object
      additionalProperties: false
      required:
        - id
        - name
        - has_secret
        - created_at
        - updated_at
        - usage
      properties:
        id:
          type: string
        name:
          type: string
        has_secret:
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        usage:
          $ref: '#/components/schemas/AdminUsageSummary'
    AdminUser:
      type: object
      additionalProperties: false
      required:
        - user
        - tenant_count
        - tenants
      properties:
        user:
          $ref: '#/components/schemas/ManagementUser'
        tenant_count:
          type: integer
          minimum: 0
        tenants:
          type: array
          items:
            $ref: '#/components/schemas/AdminTenant'
    AdminUsersSummary:
      type: object
      additionalProperties: false
      required:
        - period_days
        - users
      properties:
        period_days:
          type: integer
          minimum: 1
        users:
          type: array
          items:
            $ref: '#/components/schemas/AdminUser'
