# AUTO-GENERATED tier-A mirror spec — do not edit.
# Source: openapi/runtime/actors.yaml (runtime 0.71.2)
#  + policy: openapi/mirror-policies/actors.json
# Regenerate: node scripts/generate-mirror-specs.mjs
openapi: 3.0.3
info:
  title: naturali.ai — Actors API
  version: 1.0.0
  description: >-
    Actors: the identities an agent speaks to and on behalf of, with their tags. A fully
    runtime-backed module — this spec is generated verbatim from the runtime's own, re-rooted under
    /v1/projects/{project_id}. The project in the path is authorized by naturali and enforced
    upstream by the project's scoped credential.


    This module mirrors the upstream runtime verbatim (tier A, #304): paths are the runtime's own
    re-rooted under /v1/projects/{project_id}, and every field, method, status code and error shape
    passes through unchanged. Errors raised by the runtime arrive in its envelope; errors raised by
    naturali itself (authentication, project resolution, an unreachable runtime) use naturali's.
  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: Actors
    description: Manage actors associated with projects
security:
  - bearerAuth: []
  - oauth2:
      - mcp:access
paths:
  /v1/projects/{project_id}/actors:
    get:
      tags:
        - Actors
      summary: List actors
      description: Returns all actors in the project named in the path.
      operationId: listActors
      parameters:
        - name: external_id
          in: query
          required: false
          description: External ID to filter by (e.g. WhatsApp phone number)
          schema:
            type: string
            example: "+15551234567"
        - name: name
          in: query
          required: false
          description: Case-insensitive substring match on the actor name
          schema:
            type: string
            example: Ada
        - name: agent_id
          in: query
          required: false
          description: Return only actors linked to this agent
          schema:
            type: string
            example: agent_V1StGXR8Z5jdHi6B
        - name: chat_id
          in: query
          required: false
          description: Return only actors linked to this chat
          schema:
            type: string
            example: chat_V1StGXR8Z5jdHi6B
        - name: conversation_id
          in: query
          required: false
          description: >
            Return only actors that participate in this conversation (derived from the
            conversation's messages).
          schema:
            type: string
            example: conv_V1StGXR8Z5jdHi6B
        - $ref: "#/components/parameters/TagsQuery"
        - name: limit
          in: query
          required: false
          description: Maximum number of results to return
          schema:
            type: integer
            minimum: 1
            maximum: 100
            default: 50
        - name: offset
          in: query
          required: false
          description: Number of results to skip
          schema:
            type: integer
            default: 0
      responses:
        "200":
          description: List of actors
          content:
            application/json:
              schema:
                type: object
                properties:
                  data:
                    type: array
                    items:
                      $ref: "#/components/schemas/ActorRecord"
                  total:
                    type: integer
                  limit:
                    type: integer
                  offset:
                    type: integer
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    post:
      tags:
        - Actors
      summary: Create an actor
      description: Creates a new actor in the project named in the path.
      operationId: createActor
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              additionalProperties: false
              properties:
                name:
                  type: string
                  example: Alice
                external_id:
                  type: string
                  description: Optional external identifier (e.g. WhatsApp phone number). If provided and an actor
                    with this externalId already exists in the project, the existing actor is
                    returned (idempotent — 200 OK).
                  example: "+15551234567"
                instructions:
                  type: string
                  nullable: true
                  description: Persona-specific instructions composed into the effective system prompt during
                    conversation generation.
                agent_id:
                  x-naturali-ref: agents
                  type: string
                  description: Agent to link this actor to. Mutually exclusive with chat_id.
                  example: agent_V1StGXR8Z5jdHi6B
                chat_id:
                  x-naturali-ref: chats
                  type: string
                  description: Chat to link this actor to. Mutually exclusive with agent_id.
                  example: chat_V1StGXR8Z5jdHi6B
      responses:
        "200":
          description: Actor already exists — returned when externalId matches an existing actor in this
            project (idempotent)
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ActorRecord"
        "201":
          description: Actor created
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ActorRecord"
        "400":
          description: Invalid request body
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/actors/{actor_id}:
    get:
      tags:
        - Actors
      summary: Get an actor by ID
      description: Returns an actor by its ID
      operationId: getActor
      x-naturali-resource:
        kind: actor
        from: actor_id
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: actor_V1StGXR8Z5jdHi6B
      responses:
        "200":
          description: Actor found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ActorRecord"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Actor not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Actors
      summary: Delete an actor
      description: Deletes an actor by its ID
      operationId: deleteActor
      x-naturali-resource:
        kind: actor
        from: actor_id
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: actor_V1StGXR8Z5jdHi6B
      responses:
        "204":
          description: Actor deleted
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Actor not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Actors
      summary: Update an actor
      description: Updates an actor's properties
      operationId: updateActor
      x-naturali-resource:
        kind: actor
        from: actor_id
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: actor_V1StGXR8Z5jdHi6B
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              properties:
                name:
                  type: string
                  example: Alice Smith
                external_id:
                  type: string
                  description: External identifier (e.g. WhatsApp phone number)
                  example: "+15551234567"
                instructions:
                  type: string
                  description: Persona-specific instructions
                agent_id:
                  x-naturali-ref: agents
                  type: string
                  nullable: true
                  description: Agent to link this actor to. Mutually exclusive with chat_id.
                chat_id:
                  x-naturali-ref: chats
                  type: string
                  nullable: true
                  description: Chat to link this actor to. Mutually exclusive with agent_id.
                tags:
                  $ref: "#/components/schemas/TagBag"
      responses:
        "200":
          description: Actor updated
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ActorRecord"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Actor not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
  /v1/projects/{project_id}/actors/{actor_id}/tags:
    get:
      tags:
        - Actors
      summary: Get actor tags
      description: Returns all tags attached to the actor
      operationId: getActorTags
      x-naturali-resource:
        kind: actor
        from: actor_id
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: actor_V1StGXR8Z5jdHi6B
      responses:
        "200":
          description: Actor tags
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagBag"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Actor not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    put:
      tags:
        - Actors
      summary: Replace actor tags
      description: Replaces all tags on the actor with the provided tags (not merged)
      operationId: replaceActorTags
      x-naturali-resource:
        kind: actor
        from: actor_id
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: actor_V1StGXR8Z5jdHi6B
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TagBag"
      responses:
        "200":
          description: Tags replaced
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagBag"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Actor not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Actors
      summary: Merge actor tags
      description: Merges provided tags into the actor's existing tags (existing tags are preserved unless
        overridden)
      operationId: mergeActorTags
      x-naturali-resource:
        kind: actor
        from: actor_id
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: actor_V1StGXR8Z5jdHi6B
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/TagBag"
      responses:
        "200":
          description: Tags merged
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/TagBag"
        "401":
          description: Unauthorized
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "403":
          description: Forbidden
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Actor not found
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    parameters:
      - $ref: "#/components/parameters/ProjectId"
components:
  schemas:
    ActorRecord:
      type: object
      properties:
        id:
          type: string
          description: Actor ID
          example: actor_V1StGXR8Z5jdHi6B
        project_id:
          x-naturali-ref: projects
          type: string
          description: Project ID
          example: proj_V1StGXR8Z5jdHi6B
        name:
          type: string
          example: Alice
        external_id:
          type: string
          nullable: true
          description: External identifier (e.g. WhatsApp phone number)
          example: "+15551234567"
        instructions:
          type: string
          nullable: true
          description: Persona-specific instructions composed into the effective system prompt during
            conversation generation.
        agent_id:
          x-naturali-ref: agents
          type: string
          nullable: true
          description: Agent this actor is linked to (mutually exclusive with chatId).
        chat_id:
          x-naturali-ref: chats
          type: string
          nullable: true
          description: Chat this actor is linked to (mutually exclusive with agentId).
        tags:
          $ref: "#/components/schemas/TagBag"
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    ErrorResponse:
      type: object
      required:
        - error
      properties:
        error:
          type: object
          description: Structured error. Every error response uses this shape, so `code` can be read without
            first checking the type of `error`.
          required:
            - code
            - message
          properties:
            code:
              type: string
              description: "Machine-readable error code: lower_snake for an error naturali raises
                (`access_denied`), UPPER_SNAKE for one the runtime reports (`RESOURCE_NOT_FOUND`)."
              example: access_denied
            message:
              type: string
              description: Human-readable explanation.
              example: Your role in this project does not carry this action.
            details:
              type: object
              additionalProperties: true
              description: Structured context for an error naturali raises, such as the `resource` and `limit` of
                a `plan_limit_reached`.
            meta:
              type: object
              description: Structured context for an error the runtime reports.
    TagBag:
      type: object
      additionalProperties:
        type: string
      x-cli-flag-name: tags
      description: >-
        Key-value labels on a resource. A flat object of string values — an array, a nested object
        or a number is rejected with `400 VALIDATION_FAILED`, never coerced. Keys are opaque and
        stored verbatim, so `cost_center` and `costCenter` are two different tags. Matched by JSONB
        containment wherever tags are read: the `?tags=` filter and knowledge search.


        Keys beginning `system.` are reserved: the platform writes them to record which
        conversation, actor, agent and role a row came from, and a write naming one is refused with
        `400 RESERVED_TAG_KEY`. They are read and filtered like any other tag.


        The bag is bounded, because every pair reaches the IAM context of every access check on the
        resource: at most 50 keys, each key at most 128 characters and each value at most 256. A
        write past a bound — including a merge that would grow the stored bag past the key count —
        is `400 VALIDATION_FAILED` with `meta.limit` naming the bound it crossed. `system.*` keys
        are the platform's and do not count against the 50.
      example:
        team: finance
        env: prod
  parameters:
    ProjectId:
      name: project_id
      in: path
      required: true
      description: Project public ID (proj_ prefix).
      schema:
        type: string
        example: proj_V1StGXR8Z5jdHi6B
    TagsQuery:
      name: tags
      in: query
      required: false
      description: >
        Filter by tag pairs, written `key:value` (split on the first colon, so a value may contain
        colons). Repeat the parameter for several pairs; **all** must be present with exactly that
        value.
      schema:
        type: array
        items:
          type: string
      style: form
      explode: true
      example:
        - env:prod
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: A naturali API key (nat_sk_…) or a session JWT.
    oauth2:
      type: oauth2
      description: "A connected app's OAuth access token, issued by this API's authorization server
        (discovery: /.well-known/oauth-authorization-server). Its one scope carries every operation,
        confined to the projects the user chose when approving the app."
      flows:
        authorizationCode:
          authorizationUrl: https://api.naturali.ai/authorize
          tokenUrl: https://api.naturali.ai/token
          refreshUrl: https://api.naturali.ai/token
          scopes:
            mcp:access: Every operation this API serves, on the projects the grant covers.
