openapi: 3.0.3
info:
  title: naturali.ai — Agents API
  version: 1.0.0
  description: >
    Agents, scoped to a project (API.md §5 — Agents). An agent is created from a
    provider (§4) plus its runtime config — model, instructions, sampling and
    step limits — and is a thin surface onto a runtime agent. Everything an
    agent *is* lives on the runtime (the source of truth) and is read from there
    when shaping responses; naturali stores nothing of its own about it.
  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: Agents
    description: Create and manage a project's agents.
security:
  - bearerAuth: []
paths:
  /v1/projects/{project_id}/agents:
    parameters:
      - $ref: '#/components/parameters/ProjectId'
    get:
      tags: [Agents]
      summary: List agents
      description: Lists the agents in the project.
      operationId: listAgents
      parameters:
        - $ref: '#/components/parameters/Limit'
        - $ref: '#/components/parameters/Cursor'
      responses:
        '200':
          description: A page of agents.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AgentList'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    post:
      tags: [Agents]
      summary: Create an agent
      description: >
        Create an agent bound to one of the project's providers (provider_id),
        optionally attaching tools (tool_bindings). See AgentCreate for the
        runtime config fields.
      operationId: createAgent
      parameters:
        - $ref: '#/components/parameters/IdempotencyKey'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentCreate'
      responses:
        '201':
          description: Agent created.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '502':
          $ref: '#/components/responses/UpstreamUnavailable'
  /v1/projects/{project_id}/agents/{agent_id}:
    parameters:
      - $ref: '#/components/parameters/ProjectId'
      - $ref: '#/components/parameters/AgentId'
    get:
      tags: [Agents]
      summary: Get an agent
      operationId: getAgent
      responses:
        '200':
          description: Agent details.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      tags: [Agents]
      summary: Update an agent
      description: >
        Change the bound provider, name, model, instructions, sampling/step
        config, attached tools (tool_bindings/tool_choice/step_rules), or the
        structured-output schema (output_schema). At least one field is
        required.
      operationId: updateAgent
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentUpdate'
      responses:
        '200':
          description: Agent updated.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Agent'
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '502':
          $ref: '#/components/responses/UpstreamUnavailable'
    delete:
      tags: [Agents]
      summary: Delete an agent
      description: >
        Deletes the backing runtime agent. Returns 409 if the agent still has
        dependent generations or traces — pass `force=true` to delete those
        along with the agent (destructive and irreversible).
      operationId: deleteAgent
      parameters:
        - $ref: '#/components/parameters/Force'
      responses:
        '204':
          description: Agent deleted.
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '409':
          $ref: '#/components/responses/Conflict'
        '502':
          $ref: '#/components/responses/UpstreamUnavailable'
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
    IdempotencyKey:
      name: Idempotency-Key
      in: header
      required: false
      description: Client-supplied key to make this mutating POST idempotent.
      schema:
        type: string
    Force:
      name: force
      in: query
      required: false
      description: >
        When true, delete the agent together with its dependent generations and
        traces instead of returning 409. Destructive and irreversible.
      schema:
        type: boolean
        default: false
    ProjectId:
      name: project_id
      in: path
      required: true
      description: Project public ID (proj_ prefix).
      schema:
        type: string
        example: proj_V1StGXR8Z5jdHi6B
    AgentId:
      name: agent_id
      in: path
      required: true
      description: Agent public ID (agent_ prefix).
      schema:
        type: string
        example: agent_V1StGXR8Z5jdHi6B
  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'
    Conflict:
      description: The request conflicts with the resource's current state.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
    UpstreamUnavailable:
      description: The upstream runtime could not complete the operation.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/ErrorResponse'
  schemas:
    Agent:
      type: object
      properties:
        id:
          type: string
          description: Public agent ID (agent_ prefix) — the runtime agent id.
          example: agent_V1StGXR8Z5jdHi6B
        project_id:
          type: string
          example: proj_V1StGXR8Z5jdHi6B
        provider_id:
          type: string
          description: The provider the agent is bound to (aip_ prefix).
          example: aip_V1StGXR8Z5jdHi6B
        name:
          type: string
          example: support-triage
        model:
          type: string
          nullable: true
          description: Model the agent generates with; null falls back to the provider default.
          example: us.anthropic.claude-haiku-4-5-20251001-v1:0
        instructions:
          type: string
          nullable: true
          description: System instructions guiding the agent's behavior.
          example: You are a helpful support triage assistant.
        temperature:
          type: number
          nullable: true
          minimum: 0
          maximum: 2
          example: 0.7
        max_steps:
          type: integer
          nullable: true
          minimum: 1
          description: Maximum agent loop steps before stopping.
          example: 8
        max_context_messages:
          type: integer
          nullable: true
          minimum: 1
          description: Maximum recent messages included in the context window.
          example: 20
        tool_bindings:
          type: array
          items:
            $ref: '#/components/schemas/ToolBinding'
          description: The tools bound to this agent.
          example: [{ tool_id: tool_V1StGXR8Z5jdHi6B }]
        tool_choice:
          $ref: '#/components/schemas/ToolChoice'
        step_rules:
          $ref: '#/components/schemas/StepRules'
        output_schema:
          type: object
          additionalProperties: true
          nullable: true
          description: >
            JSON Schema describing the structured object the model must return.
            When set, a non-streaming generation is constrained to it and the
            parsed value comes back as `object` on the generation result. Null
            (the default) leaves the output unconstrained. Streaming generations
            are unaffected.
          example:
            type: object
            properties:
              approved:
                type: boolean
            required: [approved]
        trace_content_mode:
          type: string
          nullable: true
          enum: [full, none, null]
          description: >
            Agent-scope zero-retention setting. `null` (the default) inherits
            the project's `trace_content_mode`; `none` means this agent's trace
            and generation content is never written. An agent may tighten a
            storing project to `none`, but cannot loosen a zero-retention
            project back to `full`.
          example: null
        created_at:
          type: string
          format: date-time
          example: '2026-07-18T00:00:00.000Z'
        updated_at:
          type: string
          format: date-time
          example: '2026-07-18T00:00:00.000Z'
      required:
        - id
        - project_id
        - provider_id
        - name
        - model
        - instructions
        - temperature
        - max_steps
        - max_context_messages
        - tool_bindings
        - tool_choice
        - step_rules
        - output_schema
        - trace_content_mode
        - created_at
        - updated_at
    AgentCreate:
      type: object
      description: >
        Create an agent bound to a provider. Only `provider_id` is required;
        everything else falls back to the provider/platform defaults.
      required:
        - provider_id
      properties:
        provider_id:
          type: string
          description: A provider registered in this project (aip_ prefix).
          example: aip_V1StGXR8Z5jdHi6B
        name:
          type: string
          description: Human-readable label.
          example: support-triage
        model:
          type: string
          description: Model string the runtime sends (see /v1/models provider_model). Defaults to the provider's default model.
          example: us.anthropic.claude-haiku-4-5-20251001-v1:0
        instructions:
          type: string
          description: System instructions guiding the agent's behavior.
          example: You are a helpful support triage assistant.
        temperature:
          type: number
          minimum: 0
          maximum: 2
          example: 0.7
        max_steps:
          type: integer
          minimum: 1
          example: 8
        max_context_messages:
          type: integer
          minimum: 1
          example: 20
        tool_bindings:
          type: array
          items:
            $ref: '#/components/schemas/ToolBinding'
          description: >
            Tools to bind to the agent — each naming a tool_ id registered in
            this project. Replaces the whole binding set; [] clears it.
          example: [{ tool_id: tool_V1StGXR8Z5jdHi6B }]
        tool_choice:
          $ref: '#/components/schemas/ToolChoice'
        step_rules:
          $ref: '#/components/schemas/StepRules'
        output_schema:
          type: object
          additionalProperties: true
          description: >
            JSON Schema describing the structured object the model must return.
            When set, a non-streaming generation is constrained to it and the
            parsed value comes back as `object` on the generation result. Omit
            (the default) to leave the output unconstrained. Streaming
            generations are unaffected.
          example:
            type: object
            properties:
              approved:
                type: boolean
            required: [approved]
        trace_content_mode:
          type: string
          nullable: true
          enum: [full, none, null]
          description: >
            Zero-retention opt-in for this agent. Omit or send `null` to
            inherit the project's setting; `none` means this agent's trace and
            generation content is never written. `full` under a zero-retention
            project is refused with `400 invalid_trace_content_mode` — an agent
            may tighten the project's floor but never loosen it.
          example: none
    AgentUpdate:
      type: object
      description: At least one field must be present.
      minProperties: 1
      properties:
        provider_id:
          type: string
          description: Rebind the agent to a different provider in this project.
          example: aip_V1StGXR8Z5jdHi6B
        name:
          type: string
          example: renamed
        model:
          type: string
          example: us.anthropic.claude-opus-4-5-20251101-v1:0
        instructions:
          type: string
          example: Updated instructions.
        temperature:
          type: number
          minimum: 0
          maximum: 2
          example: 0.5
        max_steps:
          type: integer
          minimum: 1
          example: 12
        max_context_messages:
          type: integer
          minimum: 1
          example: 40
        tool_bindings:
          type: array
          items:
            $ref: '#/components/schemas/ToolBinding'
          description: >
            Replace the agent's bound tools with exactly this set (each naming
            a tool_ id in this project); [] detaches all tools.
          example: [{ tool_id: tool_V1StGXR8Z5jdHi6B }]
        tool_choice:
          $ref: '#/components/schemas/ToolChoice'
        step_rules:
          $ref: '#/components/schemas/StepRules'
        output_schema:
          type: object
          additionalProperties: true
          nullable: true
          description: >
            Replace the agent's structured-output schema. An object constrains
            non-streaming generations to it; `null` clears it and leaves the
            output unconstrained.
          example:
            type: object
            properties:
              approved:
                type: boolean
            required: [approved]
        trace_content_mode:
          type: string
          nullable: true
          enum: [full, none, null]
          description: >
            Change this agent's zero-retention setting. `null` falls back to
            inheriting the project's mode; `none` means content is never
            written. `full` under a zero-retention project is refused with
            `400 invalid_trace_content_mode`.

            Tightening to `none` stops future writes; it does not erase content
            already recorded — purge that explicitly.
          example: none
    AgentList:
      type: object
      required: [data, next_cursor]
      properties:
        data:
          type: array
          items:
            $ref: '#/components/schemas/Agent'
        next_cursor:
          type: string
          nullable: true
          description: Cursor for the next page, or null at the end.
          example: null
    ToolBinding:
      type: object
      description: >
        One tool attached to an agent, named by reference. `tool_id` is the only
        field: an unknown one is a `400`, so a misspelling cannot be stored as a
        binding that never resolves.
      required: [tool_id]
      additionalProperties: false
      properties:
        tool_id:
          type: string
          description: A tool registered in this project.
          example: tool_V1StGXR8Z5jdHi6B
          x-naturali-ref: tool
    ToolChoice:
      description: >
        Tool choice strategy — a string (`auto`, `required`, `none`) or an
        object naming one tool (`{ "type": "tool", "name": "…" }`). Null (the
        default) leaves it unset.


        The shape is validated on write: an unrecognized string, an unknown
        field on the object form, or a `type` other than `tool` is a `400`
        rather than a value that is accepted and then ignored. There is exactly
        one spelling of each field — camelCase variants such as `toolName` are
        refused, not translated.
      oneOf:
        - type: string
          enum: [auto, required, none]
        - type: object
          required: [type, name]
          additionalProperties: false
          properties:
            type:
              type: string
              enum: [tool]
              example: tool
            name:
              type: string
              description: The name of a tool bound to this agent.
              example: get_weather
      example: auto
    StepRules:
      type: array
      nullable: true
      description: >
        Per-step overrides of `tool_choice` (and, implicitly, which tools are
        active), applied on top of the agent's own `tool_choice` for the step
        number they name. The overall `tool_choice` otherwise governs every
        step of the run, with no relaxation once a tool has been called — the
        way to force a tool call on the first step without forcing one on
        every later step too (which runs the full `max_steps` before it can
        stop) is a rule for `step: 1` only. Null (the default) leaves it unset.


        A rule carries `step` and `tool_choice` and nothing else. An unknown
        field is a `400` naming it, because a rule the runtime does not
        recognize is dropped rather than corrected — the agent would keep
        running with the rule silently not applied.
      items:
        type: object
        required: [step]
        additionalProperties: false
        properties:
          step:
            type: integer
            minimum: 1
            description: The 1-indexed step this rule applies to.
            example: 1
          tool_choice:
            $ref: '#/components/schemas/ToolChoice'
      example: [{ step: 1, tool_choice: required }]
    ErrorResponse:
      type: object
      required: [error]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code:
              type: string
              example: upstream_unavailable
            message:
              type: string
              example: Could not create the agent on the upstream runtime.
            details:
              type: object
              additionalProperties: true
              description: Optional structured context for the error.
