openapi: 3.0.3
info:
  title: SOAT Actors API
  version: 1.0.0
  description: API for managing actors (e.g. WhatsApp contacts) associated with projects
  contact:
    name: SOAT Team
    url: https://github.com/ttoss/soat
servers:
  - url: '{baseUrl}'
    description: Base URL of your SOAT deployment (e.g. https://your-soat.com or http://localhost:5047)
    variables:
      baseUrl:
        description: The base URL of your SOAT deployment
        default: http://localhost:5047
tags:
  - name: Actors
    description: Manage actors associated with projects
security:
  - bearerAuth: []
paths:
  /api/v1/actors:
    get:
      tags:
        - Actors
      summary: List actors
      description: Returns all actors the caller has access to. If projectId is provided, returns only actors in that project. project keys are scoped to a single project automatically. JWT users without projectId receive actors across all their accessible projects.
      operationId: listActors
      parameters:
        - name: project_id
          in: query
          required: false
          description: Project ID (optional)
          schema:
            type: string
            example: 'proj_V1StGXR8Z5jdHi6B'
        - name: external_id
          in: query
          required: false
          description: External ID to filter by (e.g. WhatsApp phone number)
          schema:
            type: string
            example: '+15551234567'
        - name: limit
          in: query
          required: false
          description: Maximum number of results to return
          schema:
            type: integer
            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. project keys automatically infer the project from the key's scope; JWT callers must supply projectId.
      operationId: createActor
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - name
              properties:
                project_id:
                  type: string
                  description: Project ID. Required for JWT auth; omit when using an project key.
                  example: 'proj_V1StGXR8Z5jdHi6B'
                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'
      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'
  /api/v1/actors/{actor_id}:
    get:
      tags:
        - Actors
      summary: Get an actor by ID
      description: Returns an actor by its ID
      operationId: getActor
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: 'act_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
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: 'act_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
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: 'act_V1StGXR8Z5jdHi6B'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              properties:
                name:
                  type: string
                  example: 'Alice Smith'
                instructions:
                  type: string
                  description: Persona-specific instructions
                tags:
                  type: object
                  additionalProperties:
                    type: string
      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'
  /api/v1/actors/{actor_id}/tags:
    get:
      tags:
        - Actors
      summary: Get actor tags
      description: Returns all tags attached to the actor
      operationId: getActorTags
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: 'act_V1StGXR8Z5jdHi6B'
      responses:
        '200':
          description: Actor tags
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
        '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
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: 'act_V1StGXR8Z5jdHi6B'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties:
                type: string
              example:
                type: customer
                status: active
      responses:
        '200':
          description: Tags replaced
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
        '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 with existing tags (existing tags are preserved unless overridden)
      operationId: mergeActorTags
      parameters:
        - name: actor_id
          in: path
          required: true
          description: Actor ID
          schema:
            type: string
            example: 'act_V1StGXR8Z5jdHi6B'
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties:
                type: string
              example:
                priority: high
      responses:
        '200':
          description: Tags merged
          content:
            application/json:
              schema:
                type: object
                additionalProperties:
                  type: string
        '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'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: JWT token or sk_ api key
  schemas:
    ActorRecord:
      type: object
      properties:
        id:
          type: string
          description: Actor ID
          example: 'act_V1StGXR8Z5jdHi6B'
        project_id:
          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:
          type: string
          nullable: true
          description: Agent this actor is linked to (mutually exclusive with chatId).
        chat_id:
          type: string
          nullable: true
          description: Chat this actor is linked to (mutually exclusive with agentId).
        tags:
          type: object
          additionalProperties:
            type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
    ErrorResponse:
      type: object
      properties:
        error:
          type: string
          example: 'Actor not found'
