openapi: 3.0.3
info:
  title: naturali.ai — Models API
  version: 1.0.0
  description: >
    The model catalog every agent resolves against (API.md §4 — Models). Each
    entry maps a naturali model id to the runtime target that runs it (a
    provider slug plus the exact model string the runtime sends), with
    capability metadata (M1). The catalog carries no price: pricing lives on the
    runtime and only for managed providers; BYOK usage carries no LLM cost.
  contact:
    name: naturali.ai
    url: https://naturali.ai
servers:
  - url: '{baseUrl}'
    description: Host of your naturali.ai deployment; every path carries the /v1 prefix.
    variables:
      baseUrl:
        description: Base host URL.
        default: https://api.naturali.ai
tags:
  - name: Models
    description: Browse the catalog of models an agent can resolve against.
security:
  - bearerAuth: []
paths:
  /v1/models:
    get:
      tags: [Models]
      summary: List models
      description: >
        Lists catalog models, newest sources merged and sorted by id. Filter by
        vendor, provider, output/input modality, status, or `managed` — the last
        being the axis that decides whether a model is usable without BYOK
        credentials, so `?managed=true&status=available` is the set an agent can
        run on today.
      operationId: listModels
      parameters:
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Cursor'
        - name: vendor
          in: query
          required: false
          description: Filter by model maker (e.g. anthropic, amazon, meta).
          schema:
            type: string
            example: anthropic
        - name: provider
          in: query
          required: false
          description: Filter by the provider slug that serves the model.
          schema:
            type: string
            example: bedrock
        - name: modality
          in: query
          required: false
          description: >
            Filter to models whose input or output modalities include this value
            (e.g. text, image, embedding, speech).
          schema:
            type: string
            example: text
        - name: status
          in: query
          required: false
          description: Filter by lifecycle status.
          schema:
            type: string
            enum: [available, deprecated]
            example: available
        - name: managed
          in: query
          required: false
          description: >
            Filter by whether the model can back a managed provider —
            `managed=true` is the set you can pass to
            `POST /v1/projects/{project_id}/providers` with `kind: managed`.
            Omit to leave the catalog unfiltered on this axis; `false` returns
            only the BYOK-only models. Any other value is a 400.
          schema:
            type: boolean
            example: true
      responses:
        '200':
          description: A page of models.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ModelList'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/models/{model_id}:
    parameters:
      - name: model_id
        in: path
        required: true
        description: Public model id.
        schema:
          type: string
          example: anthropic.claude-haiku-4-5-20251001-v1:0
    get:
      tags: [Models]
      summary: Get a model
      operationId: getModel
      responses:
        '200':
          description: Model details.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Model'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: A naturali API key (nat_sk_…) or a session JWT.
  parameters:
    Limit:
      name: limit
      in: query
      required: false
      description: Maximum items per page — an integer from 1 to 100 (default 20).
      schema:
        type: integer
        minimum: 1
        maximum: 100
        default: 20
    Cursor:
      name: cursor
      in: query
      required: false
      description: Opaque pagination cursor from a previous response's next_cursor.
      schema:
        type: string
  responses:
    Unauthorized:
      description: Missing or invalid credentials.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    BadRequest:
      description: The request was malformed or failed validation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    NotFound:
      description: The resource does not exist (existence is not leaked).
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  schemas:
    Model:
      type: object
      properties:
        id:
          type: string
          description: Public, stable model id used in manifests and API calls.
          example: anthropic.claude-haiku-4-5-20251001-v1:0
        display_name:
          type: string
          example: Claude Haiku 4.5
        provider:
          type: string
          description: The provider slug that serves the model.
          example: bedrock
        vendor:
          type: string
          description: The model maker.
          example: anthropic
        provider_model:
          type: string
          description: >
            The exact model string the runtime sends to the provider — a
            cross-region inference-profile id (us.…) when the model is
            profile-only.
          example: us.anthropic.claude-haiku-4-5-20251001-v1:0
        input_modalities:
          type: array
          items:
            type: string
          example: [text, image]
          description: Accepted input modalities.
        output_modalities:
          type: array
          items:
            type: string
          example: [text]
        streaming:
          type: boolean
          example: true
        inference_types:
          type: array
          items:
            type: string
          description: Bedrock inference types (on_demand, inference_profile, provisioned).
          example: [on_demand]
        status:
          type: string
          enum: [available, deprecated]
          example: available
        managed:
          type: boolean
          description: >
            Whether this model can back a managed provider (`kind: managed`).

            Independent of `status`: `status: available` means the model is in
            the catalog, not that it is offerable as managed. A managed provider
            is priced at naturali's own cost, so only models with an
            authoritative published price qualify — the Anthropic Claude family
            has none today and is therefore BYOK-only. Creating a managed
            provider on a model where this is `false` returns 400.
          example: true
      required:
        - id
        - display_name
        - provider
        - vendor
        - provider_model
        - input_modalities
        - output_modalities
        - streaming
        - inference_types
        - status
        - managed
    ModelList:
      type: object
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Model'
        next_cursor:
          type: string
          nullable: true
          description: Cursor for the next page, or null at the end.
          example: null
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              example: not_found
            message:
              type: string
              example: Model not found.
            details:
              type: object
              additionalProperties: true
              description: Optional structured context for the error.
