> ## Documentation Index
> Fetch the complete documentation index at: https://cadenya.com/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# List models

> What your workspace can run, how much context each model holds, and what it costs per million tokens.

Models are workspace resources, not free-text strings. Before you set `modelConfig.modelId` on a [variation](/docs/api-reference/agentvariationservice/create-a-new-variation), this is where you find out what exists and what it costs.

<CodeGroup>
  ```typescript TypeScript theme={null}
  const models = await client.models.list({ workspaceId });

  for await (const model of models) {
    const { provider, maxInputTokens, inputPricePerMillionTokens } = model.spec;
    console.log(model.metadata.externalId, provider, maxInputTokens, inputPricePerMillionTokens);
  }
  // claude-opus-4-8    anthropic  1000000  500
  // claude-sonnet-4-6  anthropic  1000000  300
  // gpt-5-5            openai     1050000  500
  ```

  ```go Go theme={null}
  models := client.Models.ListAutoPaging(ctx, cadenya.ModelListParams{
  	WorkspaceID: cadenya.String(workspaceID),
  })

  for models.Next() {
  	m := models.Current()
  	fmt.Println(m.Metadata.ExternalID, m.Spec.Provider, m.Spec.MaxInputTokens, m.Spec.InputPricePerMillionTokens)
  }
  // claude-opus-4-8    anthropic  1000000  500
  // claude-sonnet-4-6  anthropic  1000000  300
  // gpt-5-5            openai     1050000  500
  ```

  ```ruby Ruby theme={null}
  models = cadenya.models.list(workspace_id: workspace_id)

  models.auto_paging_each do |model|
    spec = model.spec
    puts "#{model.metadata.external_id}  #{spec.provider}  #{spec.max_input_tokens}  #{spec.input_price_per_million_tokens}"
  end
  # claude-opus-4-8    anthropic  1000000  500
  # claude-sonnet-4-6  anthropic  1000000  300
  # gpt-5-5            openai     1050000  500
  ```

  ```bash cURL theme={null}
  curl "https://api.cadenya.com/v1/workspaces/${WORKSPACE_ID}/models" \
    -H "Authorization: Bearer ${CADENYA_API_KEY}"
  ```
</CodeGroup>

## Prices are cents, as strings

`inputPricePerMillionTokens` and `outputPricePerMillionTokens` are **cents per million tokens**, serialized as strings because they are 64-bit integers.

```
claude-opus-4-8    in=500   out=2500    → $5.00 / $25.00 per Mtok
claude-sonnet-4-6  in=300   out=1500    → $3.00 / $15.00 per Mtok
claude-opus-4-1    in=1500  out=7500    → $15.00 / $75.00 per Mtok
```

Parse them as integers, not floats, and divide by 100 only at the point you render a currency. Pair them with the token counts from [context windows](/docs/api-reference/objectiveservice/list-objective-context-windows) to price a run:

```typescript theme={null}
const model = await client.models.retrieve('external_id:claude-sonnet-4-6', { workspaceId });
const cents =
  (promptTokens / 1e6) * Number(model.spec.inputPricePerMillionTokens) +
  (completionTokens / 1e6) * Number(model.spec.outputPricePerMillionTokens);
```

## `maxInputTokens` drives compaction

A variation's `compactionConfig.triggerThreshold` is a **fraction of this number**, not an absolute token count. The same `0.75` threshold means 750,000 tokens on a million-token model and 150,000 on a 200,000-token one.

That is the trap when you [swap models](/docs/api-reference/modelservice/swap-models-on-agent-variations): the threshold moves with the model, and nothing warns you.

```
claude-opus-4-8    maxInputTokens: 1000000
claude-opus-4-5    maxInputTokens:  200000
```

A model with no `maxInputTokens` never triggers compaction at all, so a long objective on it grows until it fails.

## The `prefix` filter matches names, not IDs

<Warning>
  `prefix` is documented as "Filter by ID prefix." It filters by the model's **display name**, case-insensitively, and matches nothing that looks like an ID.

  ```
  ?prefix=model_                     -> 0    (every model ID starts with model_)
  ?prefix=claude-opus-4-8            -> 0    (an exact, existing externalId)
  ?prefix=claude-opus                -> 0    (a real externalId prefix)

  ?prefix=claude                     -> 11   (names "Claude Opus 4.8", ...)
  ?prefix=GPT-5.5                    -> 2    (names "GPT-5.5", "GPT-5.5 Pro")
  ```

  It also cannot span a space, so `prefix=Claude Opus` returns nothing even though every Claude model's name begins with it. Only single-word prefixes work.
</Warning>

When you already know which model you want, skip the filter and fetch it directly. `GET /models/{id}` takes the `external_id:` form:

```typescript theme={null}
const model = await client.models.retrieve('external_id:claude-sonnet-4-6', { workspaceId });
```

That is also the form to use in `modelConfig.modelId`. Cadenya resolves it and stores the canonical `model_...` ID, so a variation reads back with the canonical one.

## What a model record holds

| Field                              | Meaning                                         |
| ---------------------------------- | ----------------------------------------------- |
| `metadata.externalId`              | The stable slug, `claude-sonnet-4-6`. Use this. |
| `spec.provider`                    | `anthropic`, `openai`.                          |
| `spec.family`                      | `claude-opus`, `gpt`.                           |
| `spec.maxInputTokens`              | Context window. Drives compaction.              |
| `spec.maxOutputTokens`             | Per-response ceiling.                           |
| `spec.inputPricePerMillionTokens`  | Cents, as a string.                             |
| `spec.outputPricePerMillionTokens` | Cents, as a string.                             |
| `state`                            | `STATE_ENABLED` or `STATE_DISABLED`.            |

## Enabled and disabled

A model must be `STATE_ENABLED` for a variation to reference it, and the two guards hold each other up:

* Creating or updating a variation onto a disabled model is a `400` on `spec.model_id`.
* [Disabling a model](/docs/api-reference/modelservice/disable-a-model) while any variation references it is a `400`.

So a running objective can never find its model disabled underneath it. To retire a model, [swap the variations off it first](/docs/api-reference/modelservice/swap-models-on-agent-variations), then disable it.

## Related

<CardGroup cols={2}>
  <Card title="Create a variation" icon="sliders" href="/docs/api-reference/agentvariationservice/create-a-new-variation">
    Where `modelConfig.modelId` and `temperature` are set.
  </Card>

  <Card title="Swap models on variations" icon="right-left" href="/docs/api-reference/modelservice/swap-models-on-agent-variations">
    Migrate a whole workspace off a deprecated model.
  </Card>

  <Card title="List context windows" icon="layer-group" href="/docs/api-reference/objectiveservice/list-objective-context-windows">
    The token counts you multiply by these prices.
  </Card>

  <Card title="Get objective diagnostics" icon="magnifying-glass-chart" href="/docs/api-reference/objectiveservice/get-objective-context-diagnostics">
    Where a live objective's context window is going.
  </Card>
</CardGroup>


## OpenAPI

````yaml get /v1/workspaces/{workspaceId}/models
openapi: 3.1.0
info:
  title: Cadenya API
  description: API for the Cadenya Agent Runtime platform.
  version: '1.0'
servers:
  - url: https://api.cadenya.com
    description: Production server
security:
  - bearerAuth: []
tags:
  - name: AIProviderKeyService
  - name: APIKeyService
    description: |-
      Issue, rotate, disable, and revoke a workspace's API keys. Every key
       belongs to exactly one workspace; the system-managed global account key is
       managed via GlobalAPIKeyService instead.
  - name: AccountService
    description: >-
      Manage the authenticated account. Accounts are the top-level
      organizational
       unit and contain one or more workspaces.
  - name: AgentScheduleService
    description: >-
      Manage recurring schedules attached to agents. Schedules trigger
      objectives
       on a cadence defined by AgentScheduleSpec.Schedule.
  - name: AgentService
    description: >-
      Manage AI agents within a workspace. Agents define AI behavior and tool
      access.
  - name: AgentVariationService
    description: >-
      Manage variations of an agent and their tool, sub-agent, and memory layer
      assignments.
  - name: GlobalAPIKeyService
    description: |-
      Manage the account's system-provisioned global API key. The global key is
       the only key that spans every workspace; it is created by the system and
       cannot be deleted, so the surface is retrieve, rotate, and the
       disable/enable kill switch.
  - name: MemoryService
    description: >-
      Manage memory layers and their entries. Layers are named containers that
      can
       be composed into an objective's memory cascade; entries are the keyed values
       within a layer. System-managed layers (e.g., episodic layers created by the
       runtime) cannot be mutated through this API.
  - name: ModelService
    description: |-
      Manage LLM models available to a workspace. Models represent provider and
       family pairs (e.g., "anthropic/claude-sonnet-4.6"). Workspaces are seeded
       with the supported models and you can enable or disable each one.
  - name: ObjectiveEventStreamsService
  - name: ObjectiveService
  - name: ProfilesService
    description: |-
      Operations on profiles, the account-level principals (users, API keys,
       system) that authenticate against the API.
  - name: SearchService
  - name: TenantService
    description: >-
      Read and erase tenants and the subjects under them. Tenants and subjects
      are
       created by assertion — on objective creation or widget session mint — never
       directly, so this service has no create or update: it exists to enumerate what
       assertions have produced, and to destroy it on request.
  - name: ToolService
    description: >-
      Manage tool sets and the tools they contain. Tool sets group related
      tools,
       and tools define specific capabilities available to agents.

       When a tool set is managed, only API key actors can modify its tools; human
       (profile) actors cannot.
  - name: UploadService
    description: |-
      Issue short-lived presigned URLs for direct client-to-object-storage
       uploads. Created uploads can be referenced by id when creating or updating
       resources that accept binary content (e.g., MemoryEntry).
  - name: WidgetService
    description: |-
      Manage embeddable chat widgets. A widget binds an agent to a globally
       unique hostname with a per-widget origin allowlist; browsers reach it with
       session tokens minted via WidgetSessionService.
  - name: WidgetSessionService
    description: >-
      Mint and manage widget sessions. Session creation is server-to-server
      only:
       the customer's backend authenticates its visitor, asserts tenant/subject
       context, attaches any per-visitor secrets, and receives a short-lived
       bearer token the browser uses against the widget host.
  - name: WorkspaceAdminService
    description: >-
      Administer workspaces across the account: create and archive workspaces
      and
       manage their membership. These operations are account-scoped and require the
       admin role (a token whose profile holds the WorkOS admin role); they live
       under /v1/account/workspaces rather than the workspace-scoped /v1/workspaces
       tree so an admin can manage any workspace in the account, including ones they
       are not themselves a member of.
  - name: WorkspaceSecretService
  - name: WorkspaceService
    description: |-
      Manage workspaces within an account. Workspaces provide organizational
       grouping and isolation for resources such as agents, tools, and API keys.

       This is the workspace-scoped, end-user surface. Administrative operations
       (create / archive workspaces, manage members) live in WorkspaceAdminService
       under /v1/account/workspaces and require the admin role.
paths:
  /v1/workspaces/{workspaceId}/models:
    get:
      tags:
        - ModelService
        - Models
      summary: List models
      description: Lists all models in the workspace
      operationId: ModelService_ListModels
      parameters:
        - name: workspaceId
          in: path
          description: Workspace ID.
          required: true
          schema:
            type: string
            example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
        - name: limit
          in: query
          description: Maximum number of results to return
          schema:
            type: integer
            format: int32
        - name: cursor
          in: query
          description: Pagination cursor from previous response
          schema:
            type: string
        - name: prefix
          in: query
          description: |-
            Filter by a prefix of the model's display name, external id, or id
             (case-insensitive). A model's external id is the form used in
             modelConfig.modelId, so a caller holding that can narrow the list by it.
          schema:
            type: string
        - name: query
          in: query
          description: Free-form search query
          schema:
            type: string
        - name: state
          in: query
          description: Filter by model state
          schema:
            enum:
              - STATE_UNSPECIFIED
              - STATE_ENABLED
              - STATE_DISABLED
            type: string
            format: enum
        - name: aiProviderKeyId
          in: query
          description: >-
            Filter to models provisioned on a specific AI provider key. Accepts
            the
             key's id or an "external_id:"-prefixed slug.
          schema:
            type: string
        - name: isAssigned
          in: query
          description: >-
            Filter models to only ones assigned to an active agent
            variation/agent.
             Draft agents count as assigned; archived agents do not. Assignment does not
             imply recent traffic — see ModelInfo.last_used_at for that.
          schema:
            type: boolean
        - name: labels
          in: query
          description: |-
            Filters by metadata labels. Comma-separated key=value pairs,
             e.g. "env=prod,team=ai". A resource matches only if every pair
             matches exactly (AND semantics).
          schema:
            type: string
        - name: sortOrder
          in: query
          description: Sort order for results (asc or desc by creation time)
          schema:
            type: string
        - name: includeInfo
          in: query
          description: >-
            When true, populate each item's info (e.g. the AI provider), at the
            cost of
             extra lookups.
          schema:
            type: boolean
      responses:
        '200':
          description: OK
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListModelsResponse'
        default:
          description: Default error response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Status'
      x-codeSamples:
        - lang: JavaScript
          source: |-
            import Cadenya from '@cadenya/cadenya';

            const client = new Cadenya({
              apiKey: process.env['CADENYA_API_KEY'], // This is the default and can be omitted
            });

            // Automatically fetches more pages as needed.
            for await (const model of client.models.list({
              workspaceId: 'workspace_01HXKD2E5NQM3T9AYWCF133E3Q',
            })) {
              console.log(model.metadata);
            }
        - lang: Python
          source: |-
            import os
            from cadenya import Cadenya

            client = Cadenya(
                api_key=os.environ.get("CADENYA_API_KEY"),  # This is the default and can be omitted
            )
            page = client.models.list(
                workspace_id="workspace_01HXKD2E5NQM3T9AYWCF133E3Q",
            )
            page = page.items[0]
            print(page.metadata)
        - lang: Go
          source: "package main\n\nimport (\n\t\"context\"\n\t\"fmt\"\n\t\"go.cadenya.com/cadenya-go\"\n\t\"go.cadenya.com/cadenya-go/option\"\n)\n\nfunc main() {\n\tclient := cadenya.NewClient(\n\t\toption.WithAPIKey(\"My API Key\"),\n\t)\n\tpage, err := client.Models.List(context.TODO(), cadenya.ModelListParams{\n\t\tWorkspaceID: cadenya.String(\"workspace_01HXKD2E5NQM3T9AYWCF133E3Q\"),\n\t})\n\tif err != nil {\n\t\tpanic(err.Error())\n\t}\n\tfmt.Printf(\"%+v\\n\", page)\n}\n"
        - lang: Ruby
          source: >-
            require "cadenya"


            cadenya = Cadenya::Client.new(api_key: "My API Key")


            page = cadenya.models.list(workspace_id:
            "workspace_01HXKD2E5NQM3T9AYWCF133E3Q")


            puts(page)
        - lang: CLI
          source: |-
            cadenya models list \
              --api-key 'My API Key' \
              --workspace-id workspace_01HXKD2E5NQM3T9AYWCF133E3Q
components:
  schemas:
    ListModelsResponse:
      type: object
      properties:
        items:
          type: array
          items:
            $ref: '#/components/schemas/Model'
        pagination:
          $ref: '#/components/schemas/Page'
      description: List models response
    Status:
      type: object
      properties:
        code:
          type: integer
          description: >-
            The status code, which should be an enum value of
            [google.rpc.Code][google.rpc.Code].
          format: int32
        message:
          type: string
          description: >-
            A developer-facing error message, which should be in English. Any
            user-facing error message should be localized and sent in the
            [google.rpc.Status.details][google.rpc.Status.details] field, or
            localized by the client.
        details:
          type: array
          items:
            $ref: '#/components/schemas/GoogleProtobufAny'
          description: >-
            A list of messages that carry the error details.  There is a common
            set of message types for APIs to use.
      description: >-
        The `Status` type defines a logical error model that is suitable for
        different programming environments, including REST APIs and RPC APIs. It
        is used by [gRPC](https://github.com/grpc). Each `Status` message
        contains three pieces of data: error code, error message, and error
        details. You can find out more about this error model and how to work
        with it in the [API Design
        Guide](https://cloud.google.com/apis/design/errors).
    Model:
      required:
        - metadata
        - spec
        - state
      type: object
      properties:
        metadata:
          allOf:
            - $ref: '#/components/schemas/ResourceMetadata'
          description: Resource metadata
        spec:
          allOf:
            - $ref: '#/components/schemas/ModelSpec'
          description: Model specification
        info:
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/ModelInfo'
          description: >-
            Server-populated info (e.g. the AI provider this model routes
            through).
             Populated on reads when requested; see ListModelsRequest.include_info.
        state:
          readOnly: true
          enum:
            - STATE_UNSPECIFIED
            - STATE_ENABLED
            - STATE_DISABLED
          type: string
          description: |-
            Whether the model is usable in this workspace. Output only. Use the
             :enable and :disable actions to transition.
          format: enum
    Page:
      type: object
      properties:
        nextCursor:
          type: string
      description: >-
        Page carries cursor-based pagination state. There is no total: the
        cursor
         walks the result set without ever counting it, and a count would cost a second
         query on every list.
    GoogleProtobufAny:
      type: object
      properties:
        '@type':
          type: string
          description: The type of the serialized message.
      additionalProperties: true
      description: >-
        Contains an arbitrary serialized message along with a @type that
        describes the type of the serialized message.
    ResourceMetadata:
      required:
        - id
        - accountId
        - workspaceId
        - name
        - profileId
        - createdAt
      type: object
      properties:
        id:
          readOnly: true
          type: string
          description: >-
            Unique identifier for the resource (prefixed ULID, e.g.,
            "agent_01HXK...")
        accountId:
          readOnly: true
          example: account_01HXKD2E5NQM3T9AYWCFTJHJVF
          type: string
          description: >-
            Account this resource belongs to for multi-tenant isolation
            (prefixed ULID)
        workspaceId:
          readOnly: true
          example: workspace_01HXKD2E5NQM3T9AYWCF133E3Q
          type: string
          description: >-
            Workspace this resource belongs to for organizational grouping
            (prefixed ULID)
        name:
          type: string
          description: >-
            Human-readable name for the resource (e.g., "Customer Support
            Agent", "Email Tool")
             Required for resources that users interact with directly
        externalId:
          type: string
          description: >-
            External ID for the resource (e.g., a workflow ID from an external
            system)
        labels:
          type: object
          additionalProperties:
            type: string
          description: |-
            Key-value pairs for categorization and filtering. Values are 0-63
             alphanumeric characters with "-", "_", or "." allowed between; keys
             follow the same shape and additionally accept an optional DNS-subdomain
             prefix (e.g. "cadenya.com/") of at most 253 characters.
             Examples: {"environment": "production", "team": "platform", "version": "v2"}
        profileId:
          readOnly: true
          example: profile_01HXKD2E5NQM3T9AYWCFS0AP08
          type: string
          description: ID of the actor (user or service account) that created this resource
        createdAt:
          readOnly: true
          type: string
          description: Timestamp when this resource was created
          format: date-time
        updatedAt:
          readOnly: true
          type: string
          description: Timestamp when this resource was last updated
          format: date-time
      description: >-
        Standard metadata for persistent, named resources (e.g., agents, tools,
        prompts)
    ModelSpec:
      required:
        - provider
        - family
      type: object
      properties:
        provider:
          type: string
          description: The model provider (e.g., "anthropic", "openai", "google")
        family:
          type: string
          description: >-
            The model family (e.g., "claude-sonnet-4.6", "gpt-5.4",
            "gemini-2.5-flash")
        maxInputTokens:
          type: integer
          description: Maximum number of input tokens the model supports
          format: int32
        maxOutputTokens:
          type: integer
          description: Maximum number of output tokens the model can generate
          format: int32
        inputPricePerMillionTokens:
          type: string
          description: Cost per million input tokens in cents (e.g., 300 = $3.00)
        outputPricePerMillionTokens:
          type: string
          description: Cost per million output tokens in cents (e.g., 1500 = $15.00)
    ModelInfo:
      type: object
      properties:
        aiProviderKey:
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/AIProviderKey'
          description: >-
            The AI provider key powering this model, embedded so clients can
            read the
             provider, key name, and promotional status (info.is_promotional) without a
             second lookup. The key's model counts are not populated here; use the AI
             provider key endpoints for those.
        agentVariationCount:
          readOnly: true
          type: integer
          description: >-
            Number of agent variations currently provisioned on this model.
            Useful for
             previewing how many variations a swap would affect.
          format: int32
        lastUsedAt:
          readOnly: true
          type: string
          description: Represents the last time this model was used in an agent objective
          format: date-time
      description: ModelInfo carries server-derived, read-only details about a model.
    AIProviderKey:
      required:
        - metadata
        - spec
      type: object
      properties:
        metadata:
          $ref: '#/components/schemas/ResourceMetadata'
        spec:
          $ref: '#/components/schemas/AIProviderKeySpec'
        info:
          readOnly: true
          allOf:
            - $ref: '#/components/schemas/AIProviderKeyInfo'
          description: |-
            Server-populated info (e.g. how many models route through this key).
             Populated on reads when requested; see ListAIProviderKeysRequest.include_info.
      description: |-
        AIProviderKey is a credential for an AI provider, scoped to a workspace.
         Most keys are customer-provided (BYOK); Cadenya also provisions promotional
         keys (see AIProviderKeyInfo.is_promotional), which cannot be modified or
         deleted by account administrators. The secret value is never returned in
         responses.
    AIProviderKeySpec:
      type: object
      properties:
        provider:
          enum:
            - AI_PROVIDER_UNSPECIFIED
            - AI_PROVIDER_OPENROUTER
            - AI_PROVIDER_OPENAI
            - AI_PROVIDER_ANTHROPIC
            - AI_PROVIDER_GEMINI
            - AI_PROVIDER_OPENAI_COMPATIBLE
          type: string
          description: The AI provider this key authenticates against.
          format: enum
        credentials:
          allOf:
            - $ref: '#/components/schemas/AIProviderCredential'
          description: >-
            The provider credential. Accepted on create/update; never populated
            in
             responses (the server returns an empty value to avoid leaking the secret).
        config:
          allOf:
            - $ref: '#/components/schemas/AIProviderConfig'
          description: >-
            Non-secret, provider-specific settings (OpenAI org/project,
            OpenRouter
             region, OpenAI-compatible base URL). The set case must correspond to
             `provider`. Returned on reads. Optional: omit to accept provider defaults.
    AIProviderKeyInfo:
      type: object
      properties:
        enabledModelCount:
          readOnly: true
          type: integer
          description: Number of enabled models provisioned on this key.
          format: int32
        disabledModelCount:
          readOnly: true
          type: integer
          description: Number of disabled models provisioned on this key.
          format: int32
        isPromotional:
          readOnly: true
          type: boolean
          description: >-
            Cadenya includes promotional keys (one for onboarding, and
            potentially more in the future).
             These are not added or maintained by account administrators.
      description: >-
        AIProviderKeyInfo carries server-derived, read-only details about a key,
        for
         AI provider management UIs.
    AIProviderCredential:
      oneOf:
        - $ref: '#/components/schemas/AIProviderCredential_ApiKey'
        - $ref: '#/components/schemas/AIProviderCredential_Headers'
      discriminator:
        propertyName: type
        mapping:
          apiKey:
            $ref: '#/components/schemas/AIProviderCredential_ApiKey'
          headers:
            $ref: '#/components/schemas/AIProviderCredential_Headers'
      description: |-
        AIProviderCredential is the secret material used to authenticate with a
         provider. The set case must correspond to AIProviderKeySpec.provider. The
         server encrypts the serialized message at rest and never returns it on reads.
    AIProviderConfig:
      oneOf:
        - $ref: '#/components/schemas/AIProviderConfig_Openrouter'
        - $ref: '#/components/schemas/AIProviderConfig_Openai'
        - $ref: '#/components/schemas/AIProviderConfig_OpenaiCompatible'
      discriminator:
        propertyName: type
        mapping:
          openrouter:
            $ref: '#/components/schemas/AIProviderConfig_Openrouter'
          openai:
            $ref: '#/components/schemas/AIProviderConfig_Openai'
          openaiCompatible:
            $ref: '#/components/schemas/AIProviderConfig_OpenaiCompatible'
      description: >-
        AIProviderConfig holds non-secret, provider-specific settings. The set
        case
         must correspond to AIProviderKeySpec.provider. Providers with no settings
         (Anthropic, Gemini) simply leave this unset. The endpoint of a named provider
         is fixed and intentionally not overridable here; use the OpenAI-compatible
         provider to target a custom endpoint.
    AIProviderCredential_ApiKey:
      type: object
      required:
        - type
        - apiKey
      properties:
        type:
          type: string
          enum:
            - apiKey
        apiKey:
          allOf:
            - $ref: '#/components/schemas/CredentialAPIKey'
          description: >-
            Single API key (OpenRouter, OpenAI, Anthropic, Gemini, and most
            others).
    AIProviderCredential_Headers:
      type: object
      required:
        - type
        - headers
      properties:
        type:
          type: string
          enum:
            - headers
        headers:
          allOf:
            - $ref: '#/components/schemas/CredentialHeaders'
          description: >-
            Arbitrary auth headers, for generic endpoints that authenticate with
            a
             custom header rather than a bearer key (pairs with the OpenAI-compatible
             provider).
    AIProviderConfig_Openrouter:
      type: object
      required:
        - type
        - openrouter
      properties:
        type:
          type: string
          enum:
            - openrouter
        openrouter:
          $ref: '#/components/schemas/OpenRouterConfig'
    AIProviderConfig_Openai:
      type: object
      required:
        - type
        - openai
      properties:
        type:
          type: string
          enum:
            - openai
        openai:
          $ref: '#/components/schemas/OpenAIConfig'
    AIProviderConfig_OpenaiCompatible:
      type: object
      required:
        - type
        - openaiCompatible
      properties:
        type:
          type: string
          enum:
            - openaiCompatible
        openaiCompatible:
          $ref: '#/components/schemas/OpenAICompatibleConfig'
    CredentialAPIKey:
      type: object
      properties:
        apiKey:
          type: string
      description: CredentialAPIKey carries a single bearer/header API key.
    CredentialHeaders:
      type: object
      properties:
        headers:
          type: object
          additionalProperties:
            type: string
      description: >-
        CredentialHeaders carries arbitrary HTTP headers sent with every request
        to
         the provider (e.g. {"Authorization": "Bearer ...", "X-Api-Key": "..."}).
    OpenRouterConfig:
      type: object
      properties:
        region:
          type: string
          description: >-
            Data-residency region (e.g. "us", "eu"). Empty uses the provider
            default.
      description: OpenRouterConfig holds OpenRouter-specific settings.
    OpenAIConfig:
      type: object
      properties:
        organizationId:
          type: string
          description: Sent as the OpenAI-Organization header when set.
        projectId:
          type: string
          description: Sent as the OpenAI-Project header when set.
      description: OpenAIConfig holds OpenAI-specific settings.
    OpenAICompatibleConfig:
      required:
        - baseUrl
      type: object
      properties:
        baseUrl:
          type: string
      description: >-
        OpenAICompatibleConfig configures a generic endpoint that speaks the
        OpenAI
         Chat Completions API. The base URL is required and its model catalog is
         discovered live via GET {base_url}/models.
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: JWT

````