openapi: 3.0.0
info:
  title: Virstack VoiceAI API
  version: 1.0.0
  description: API server for LiveKit Voice AI — manage agents, SIP trunks, phone
    numbers, calls, and webhooks.
servers:
  - url: http://localhost:3000/v1
    description: Local development server
tags:
  - name: Agents / CRUD
    description: Create, read, update, and delete agents.
  - name: Agents / Versioning
    description: Publish and list agent version snapshots.
  - name: Auth
    description: API key management.
  - name: Calls
    description: Initiate, list, get, update, end, and delete calls.
  - name: Health
    description: Server health check.
  - name: Phone Number
    description: Purchase phone numbers from providers.
  - name: SIP / Trunks
    description: Manage SIP trunks.
  - name: SIP / Dispatch Rules
    description: Manage SIP dispatch rules.
  - name: SIP / Phone Numbers
    description: Register, import, list, and manage SIP phone numbers.
  - name: Users
    description: User registration, login, logout, and team management.
  - name: Webhooks
    description: Receive and process LiveKit webhook events.
  - name: Providers
    description: Discover available LLM providers, models, voices, and capabilities.
  - name: Admin / Providers
    description: Manage LLM providers and models (admin).
  - name: TTS
    description: Text-to-Speech generation utilities.
components:
  securitySchemes:
    BearerAuth:
      type: http
      scheme: bearer
      description: "API key prefixed with `vk-`. Pass as `Authorization: Bearer <api_key>`."
  schemas:
    SuccessResponse:
      type: object
      properties:
        success:
          type: boolean
          example: true
        code:
          type: integer
          example: 200
        message:
          type: string
          example: Request successful
        data:
          type: object
    ErrorResponse:
      type: object
      properties:
        success:
          type: boolean
          example: false
        code:
          type: integer
          example: 400
        error:
          type: string
          example: Validation error
        data:
          type: object
          nullable: true
          example: null
    CreateAgentBody:
      type: object
      required:
        - agent_settings
      properties:
        agent_settings:
          type: object
          required:
            - identity
            - engine
            - behavior
          properties:
            identity:
              type: object
              required:
                - agent_name
              properties:
                agent_name:
                  type: string
                  example: Customer Support Agent
            engine:
              type: object
              required:
                - provider
              properties:
                type:
                  type: string
                  enum:
                    - realtime
                    - pipeline
                  default: realtime
                provider:
                  type: string
                  example: gemini
                model:
                  type: string
                  example: gemini-2.0-flash-live
                include_thoughts:
                  type: boolean
                  default: false
                thinking_level:
                  type: string
                  example: minimal
                voice_settings:
                  type: object
                  required:
                    - voice_id
                  properties:
                    voice_id:
                      type: string
                      example: Ara
                    speed:
                      type: number
                      default: 1
                    temperature:
                      type: number
                      default: 1
                    language:
                      type: string
                      default: en
                      example: en
            behavior:
              type: object
              required:
                - system_prompt
              properties:
                system_prompt:
                  type: object
                  required:
                    - persona
                    - task
                  properties:
                    persona:
                      type: string
                      example: You are a helpful customer support agent.
                    task:
                      type: string
                      example: Help users with their orders.
                greeting_message:
                  type: string
                  default: ""
                agent_speaks_first:
                  type: boolean
                  default: true
            call_handling:
              type: object
              properties:
                inbound_enabled:
                  type: boolean
                  default: false
                is_voicemail_handling:
                  type: boolean
                  default: false
                is_ivr_handling:
                  type: boolean
                  default: false
            capabilities:
              type: object
              properties:
                knowledge_base:
                  type: object
                  properties:
                    knowledge_base_ids:
                      type: array
                      items:
                        type: string
                      example:
                        - kb-12345
                    chunks_to_retrieve:
                      type: integer
                      default: 4
                    similarity_threshold:
                      type: number
                      default: 0.3
                tools:
                  type: array
                  items:
                    oneOf:
                      - $ref: "#/components/schemas/BuiltInTool"
                      - $ref: "#/components/schemas/CustomTool"
                    discriminator:
                      propertyName: type
                post_call_analysis_schema:
                  type: array
                  items:
                    type: object
            metadata:
              type: object
              additionalProperties: true
              example:
                department: sales
    UpdateAgentBody:
      type: object
      description: All fields are optional for PATCH semantics. Wrap changes inside
        agent_settings.
      required:
        - agent_settings
      properties:
        agent_settings:
          type: object
          properties:
            identity:
              type: object
              properties:
                agent_name:
                  type: string
            engine:
              type: object
              properties:
                type:
                  type: string
                  enum:
                    - realtime
                    - pipeline
                provider:
                  type: string
                model:
                  type: string
                include_thoughts:
                  type: boolean
                thinking_level:
                  type: string
                voice_settings:
                  type: object
                  properties:
                    voice_id:
                      type: string
                    speed:
                      type: number
                    temperature:
                      type: number
                    language:
                      type: string
            behavior:
              type: object
              properties:
                system_prompt:
                  type: object
                  properties:
                    persona:
                      type: string
                    task:
                      type: string
                greeting_message:
                  type: string
                agent_speaks_first:
                  type: boolean
            call_handling:
              type: object
              properties:
                inbound_enabled:
                  type: boolean
                is_voicemail_handling:
                  type: boolean
                is_ivr_handling:
                  type: boolean
            capabilities:
              type: object
              properties:
                knowledge_base:
                  type: object
                  properties:
                    knowledge_base_ids:
                      type: array
                      items:
                        type: string
                    chunks_to_retrieve:
                      type: integer
                    similarity_threshold:
                      type: number
                tools:
                  type: array
                  items:
                    oneOf:
                      - $ref: "#/components/schemas/BuiltInTool"
                      - $ref: "#/components/schemas/CustomTool"
                post_call_analysis_schema:
                  type: array
                  items:
                    type: object
            metadata:
              type: object
              additionalProperties: true
    PublishAgentBody:
      type: object
      properties:
        version_description:
          type: string
          example: Initial production release
    AgentResponse:
      type: object
      properties:
        agent_id:
          type: string
          example: Vxsbkwe3UsYXMYR2
        agent_settings:
          type: object
          properties:
            identity:
              type: object
              properties:
                agent_name:
                  type: string
                  example: Customer Support Agent
            engine:
              type: object
              properties:
                type:
                  type: string
                  example: realtime
                provider:
                  type: string
                  example: gemini
                model:
                  type: string
                  example: gemini-2.0-flash-live
                include_thoughts:
                  type: boolean
                  example: true
                thinking_level:
                  type: string
                  example: minimal
                voice_settings:
                  type: object
                  properties:
                    voice_id:
                      type: string
                      example: Ara
                    speed:
                      type: number
                      example: 1
                    temperature:
                      type: number
                      example: 1
                    language:
                      type: string
                      example: en
            behavior:
              type: object
              properties:
                system_prompt:
                  type: object
                  properties:
                    persona:
                      type: string
                      example: You are a helpful customer support agent.
                    task:
                      type: string
                      example: Help users with their orders.
                greeting_message:
                  type: string
                  example: Hello! How can I help you today?
                agent_speaks_first:
                  type: boolean
                  example: true
            call_handling:
              type: object
              properties:
                inbound_enabled:
                  type: boolean
                  example: false
                is_voicemail_handling:
                  type: boolean
                  example: false
                is_ivr_handling:
                  type: boolean
                  example: false
            capabilities:
              type: object
              properties:
                knowledge_base:
                  type: object
                  properties:
                    knowledge_base_ids:
                      type: array
                      items:
                        type: string
                      example:
                        - kb-12345
                    chunks_to_retrieve:
                      type: integer
                      example: 4
                    similarity_threshold:
                      type: number
                      example: 0.3
                tools:
                  type: array
                  items:
                    oneOf:
                      - $ref: "#/components/schemas/BuiltInTool"
                      - $ref: "#/components/schemas/CustomTool"
                post_call_analysis_schema:
                  type: array
                  items:
                    type: object
            metadata:
              type: object
              additionalProperties: true
        is_active:
          type: boolean
          example: true
        version:
          type: integer
          example: 0
        is_published:
          type: boolean
          example: false
        last_modification_timestamp:
          type: string
          example: 2026-02-25T22:49:00+05:30
    AgentVersionResponse:
      type: object
      properties:
        agent_id:
          type: string
          example: aBcDeFgHiJkLmNoP
        version:
          type: integer
          example: 1
        agent_settings:
          type: object
          properties:
            identity:
              type: object
              properties:
                agent_name:
                  type: string
                  example: Customer Support Agent
            engine:
              type: object
              properties:
                type:
                  type: string
                  example: realtime
                provider:
                  type: string
                  example: gemini
                model:
                  type: string
                include_thoughts:
                  type: boolean
                thinking_level:
                  type: string
                voice_settings:
                  type: object
                  properties:
                    voice_id:
                      type: string
                      example: Ara
                    speed:
                      type: number
                      example: 1
                    temperature:
                      type: number
                      example: 1
                    language:
                      type: string
                      example: en
            behavior:
              type: object
              properties:
                system_prompt:
                  type: object
                  properties:
                    persona:
                      type: string
                    task:
                      type: string
                greeting_message:
                  type: string
                agent_speaks_first:
                  type: boolean
                  example: true
            call_handling:
              type: object
              properties:
                is_voicemail_handling:
                  type: boolean
                is_ivr_handling:
                  type: boolean
            capabilities:
              type: object
              properties:
                knowledge_base:
                  type: object
                  properties:
                    knowledge_base_ids:
                      type: array
                      items:
                        type: string
                    chunks_to_retrieve:
                      type: integer
                    similarity_threshold:
                      type: number
                tools:
                  type: array
                  items:
                    oneOf:
                      - $ref: "#/components/schemas/BuiltInTool"
                      - $ref: "#/components/schemas/CustomTool"
            metadata:
              type: object
              additionalProperties: true
        version_description:
          type: string
          example: Initial release
        created_timestamp:
          type: string
          example: 2026-02-25T22:49:00+05:30
    TalkWhileWaiting:
      type: object
      properties:
        enabled:
          type: boolean
          default: false
        mode:
          type: string
          enum:
            - static
            - prompt
        texts_or_prompts:
          description: Container for up to 5 prompt/static entries. In prompt mode, the
            sum of all variants_count values MUST be <= 5. In static mode, each
            entry is treated as one static transcript.
          type: object
          properties:
            entries:
              type: array
              minItems: 1
              maxItems: 5
              items:
                type: object
                required:
                  - id
                  - content
                properties:
                  id:
                    type: string
                    description: Unique ID within this texts_or_prompts.entries object.
                    example: p1
                  content:
                    type: string
                    description: Prompt text (mode=prompt) or static transcript (mode=static).
                    example: Generate ONE very short filler line to say while checking the knowledge
                      base.
                  variants_count:
                    type: integer
                    nullable: true
                    minimum: 1
                    maximum: 5
                    description: "Prompt mode only: number of variants to generate for this prompt.
                      The sum across all entries must be <= 5. Static mode: null
                      or omitted."
                    example: 1
              example:
                - id: p1
                  content: Generate a short filler line for checking the knowledge base.
                  variants_count: 1
                - id: p2
                  content: Generate a different short filler line.
                  variants_count: 2
        generated_speech_texts:
          type: array
          items:
            type: string
          description: The final texts generated from prompts (mode=prompt) or the static
            texts used (mode=static).
    BuiltInTool:
      type: object
      required:
        - type
        - tool_name
      properties:
        type:
          type: string
          enum:
            - built_in
          description: Identifies this as a built-in tool.
        tool_name:
          type: string
          example: transfer_call
          description: Name of the built-in tool (e.g. transfer_call, send_sms, end_call).
        description:
          type: string
          example: Transfer the call to another number
        parameters:
          type: object
          additionalProperties: true
          description: Key-value configuration for the tool.
          example:
            transfer_to: "+14155551234"
            transfer_from: "+14155551234"
        config:
          type: object
          additionalProperties: true
          description: Key-value internal configuration for the tool.
          example:
            extra_description: Only end the call after confirming the issue is resolved.
            delete_room: true
            end_instructions: Thank the caller for their time and wish them a good day.
        talk_while_waiting:
          $ref: "#/components/schemas/TalkWhileWaiting"
        filler_audio_urls:
          type: array
          items:
            type: string
            format: uri
          description: Array of S3/CloudFront URLs for the pre-generated filler audio
            variants.
    CustomTool:
      type: object
      required:
        - type
        - tool_name
        - description
        - webhook_url
        - schema
      properties:
        type:
          type: string
          enum:
            - custom
          description: Identifies this as a custom function tool.
        tool_name:
          type: string
          example: user_data
          description: Unique tool name.
        description:
          type: string
          example: Get user data
          description: Human-readable description for the LLM.
        webhook_url:
          type: string
          format: uri
          example: https://example.com/webhook
          description: URL to call when the tool is invoked.
        schema:
          type: object
          required:
            - name
            - schema
          description: Function schema definition.
          properties:
            name:
              type: string
              example: user_data
              description: Schema identifier name.
            strict:
              type: boolean
              example: true
              description: Whether to enforce strict schema validation.
            schema:
              type: object
              required:
                - type
                - properties
              description: JSON Schema definition of the function parameters.
              properties:
                type:
                  type: string
                  enum:
                    - object
                properties:
                  type: object
                  additionalProperties: true
                  description: Map of parameter names to their JSON Schema definitions.
                required:
                  type: array
                  items:
                    type: string
                  description: List of required parameter names.
                additionalProperties:
                  type: boolean
              example:
                type: object
                properties:
                  name:
                    type: string
                    description: The name of the user
                  username:
                    type: string
                    description: The username of the user. Must start with @
                    pattern: ^@[a-zA-Z0-9_]+$
                  email:
                    type: string
                    description: The email of the user
                    format: email
                required:
                  - name
                  - username
                  - email
                additionalProperties: false
        talk_while_waiting:
          $ref: "#/components/schemas/TalkWhileWaiting"
        filler_audio_urls:
          type: array
          items:
            type: string
            format: uri
          description: Array of S3/CloudFront URLs for the pre-generated filler audio
            variants.
    ProviderResponse:
      type: object
      properties:
        provider_id:
          type: string
          example: gemini
        display_name:
          type: string
          example: Google Gemini
        is_active:
          type: boolean
          example: true
    ProviderDetailResponse:
      type: object
      properties:
        provider_id:
          type: string
          example: gemini
        display_name:
          type: string
          example: Google Gemini
        is_active:
          type: boolean
          example: true
        models:
          type: array
          items:
            type: object
            properties:
              model_id:
                type: string
                example: gemini-2.0-flash-live
              display_name:
                type: string
                example: Gemini 2.0 Flash Live
              is_default:
                type: boolean
                example: true
              voice_count:
                type: integer
                example: 30
    ProviderModelResponse:
      type: object
      properties:
        model_id:
          type: string
          example: gemini-2.0-flash-live
        provider_id:
          type: string
          example: gemini
        display_name:
          type: string
          example: Gemini 2.0 Flash Live
        is_active:
          type: boolean
          example: true
        is_default:
          type: boolean
          example: true
        capabilities:
          type: object
          properties:
            supports_thinking:
              type: boolean
              example: true
            thinking_levels:
              type: array
              items:
                type: string
              example:
                - minimal
                - low
                - medium
                - high
            supported_languages:
              type: array
              items:
                type: object
                properties:
                  code:
                    type: string
                  display_name:
                    type: string
              example:
                - code: en
                  display_name: English
                - code: es
                  display_name: Spanish
            supports_voice_config:
              type: boolean
              example: true
            supports_knowledge_base:
              type: boolean
              example: true
            supports_tools:
              type: boolean
              example: true
        voices:
          type: array
          items:
            type: object
            properties:
              voice_id:
                type: string
                example: Zephyr
              display_name:
                type: string
                example: Zephyr
              gender:
                type: string
                example: female
              description:
                type: string
                example: Bright
              is_active:
                type: boolean
                example: true
        validation_rules:
          type: object
          properties:
            required_fields:
              type: array
              items:
                type: string
              example:
                - include_thoughts
                - thinking_level
            exclusive_languages:
              type: array
              items:
                type: string
              example:
                - si
    CreateProviderBody:
      type: object
      required:
        - provider_id
        - display_name
      properties:
        provider_id:
          type: string
          example: openai
          description: Unique slug (lowercase, alphanumeric, hyphens).
        display_name:
          type: string
          example: OpenAI
        is_active:
          type: boolean
          default: true
    UpdateProviderBody:
      type: object
      properties:
        display_name:
          type: string
          example: OpenAI GPT
        is_active:
          type: boolean
    CreateProviderModelBody:
      type: object
      required:
        - model_id
        - display_name
      properties:
        model_id:
          type: string
          example: gpt-4o-realtime
        display_name:
          type: string
          example: GPT-4o Realtime
        is_active:
          type: boolean
          default: true
        is_default:
          type: boolean
          default: false
        capabilities:
          $ref: "#/components/schemas/ProviderModelResponse/properties/capabilities"
        voices:
          type: array
          items:
            type: object
        validation_rules:
          $ref: "#/components/schemas/ProviderModelResponse/properties/validation_rules"
    UpdateProviderModelBody:
      type: object
      properties:
        display_name:
          type: string
        is_active:
          type: boolean
        is_default:
          type: boolean
        capabilities:
          type: object
        voices:
          type: array
          items:
            type: object
        validation_rules:
          type: object
    CreateApiKeyBody:
      type: object
      properties:
        name:
          type: string
          example: Production Key
          description: Optional human-readable label.
    ApiKeyResponse:
      type: object
      properties:
        key_id:
          type: string
          example: 550e8400-e29b-41d4
        api_key:
          type: string
          example: vk-5b9d3aad0ace4f09b415b392bc276bd1
          description: Returned only once on creation.
    InitiateWebCallBody:
      type: object
      required:
        - agent_id
      properties:
        agent_id:
          type: string
          example: aBcDeFgHiJkLmNoP
          description: Agent to handle the call.
        participant_identity:
          type: string
          example: user-john-doe
          description: Unique caller identity. Auto-generated if not provided.
        metadata:
          type: object
          additionalProperties: true
          example:
            source: web_widget
        dynamic_variables:
          type: object
          additionalProperties: true
          example:
            customer_name: John Doe
          description: Variables injected into the agent prompt.
    WebCallResponse:
      type: object
      properties:
        call_id:
          type: string
          example: 5e2ecf24-9d3b-4114-86ec-645e5dead568
        agent_id:
          type: string
          example: aBcDeFgHiJkLmNoP
        channel:
          type: string
          example: web
        direction:
          type: string
          example: inbound
        status:
          type: string
          example: initiated
        room_token:
          type: string
          description: LiveKit participant token for connecting to the room
        room_name:
          type: string
          example: call-1708900000-aBcDeFgHiJkLmNoP
        livekit_url:
          type: string
          example: wss://my-project.livekit.cloud
    InitiateOutboundCallBody:
      type: object
      required:
        - from_number
        - to_number
      properties:
        from_number:
          type: string
          example: "+14155551234"
          description: E.164 phone number making the call.
        to_number:
          type: string
          example: "+14155559876"
          description: E.164 destination phone number.
        override_agent_id:
          type: string
          example: aBcDeFgHiJkLmNoP
          description: Override the default agent for this call.
        metadata:
          type: object
          additionalProperties: true
          example:
            campaign_id: camp_123
        dynamic_variables:
          type: object
          additionalProperties: true
          example:
            customer_name: John Doe
          description: Variables injected into the agent prompt.
    OutboundCallResponse:
      type: object
      properties:
        call_id:
          type: string
          example: 40ebfa68-1d06-4dff-9a34-cb3e34a933e7
        agent_id:
          type: string
          example: aBcDeFgHiJkLmNoP
        channel:
          type: string
          example: sip
        direction:
          type: string
          example: outbound
        status:
          type: string
          example: registered
        telephony:
          type: object
          properties:
            from_number:
              type: string
              example: "+19499930676"
            to_number:
              type: string
              example: "+19494276394"
    CallResponse:
      type: object
      properties:
        call_id:
          type: string
          example: e9f91a27-db03-4f96-8575-b3a1a97d7c6d
        agent_id:
          type: string
          example: aBcDeFgHiJkLmNoP
        channel:
          type: string
          example: web
        direction:
          type: string
          example: inbound
        status:
          type: string
          example: ended
        room_name:
          type: string
          example: call-1710900000-aBcD
        metadata:
          type: object
          additionalProperties: true
          example:
            source: web_widget
        transcripts:
          type: object
          properties:
            transcript:
              type: string
            transcript_object:
              type: array
              items:
                type: object
            transcript_with_tool_calls:
              type: array
              items:
                type: object
        session_report_url:
          type: string
          format: uri
          description: CloudFront URL for downloading the raw session report JSON.
        recordings:
          type: object
          properties:
            recording_url:
              type: string
            recording_multi_channel_url:
              type: string
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        start_timestamp:
          type: string
          format: date-time
        end_timestamp:
          type: string
          format: date-time
    UpdateCallBody:
      type: object
      properties:
        metadata:
          type: object
          additionalProperties: true
          example:
            resolved: true
    CreateTrunkBody:
      type: object
      properties:
        name:
          type: string
          example: Twilio Trunk
        numbers:
          type: array
          items:
            type: string
          example:
            - "+14155551234"
          description: E.164 numbers associated with this trunk.
        auth_username:
          type: string
          example: trunk_user
        auth_password:
          type: string
          example: s3cret
    CreateDispatchRuleBody:
      type: object
      properties:
        name:
          type: string
          example: Default Inbound Rule
        trunk_ids:
          type: array
          items:
            type: string
          example:
            - ST_xxxx
        room_prefix:
          type: string
          example: inbound-
          description: Prefix for auto-generated LiveKit room names.
        metadata:
          type: object
          additionalProperties: true
          example: {}
    CreatePhoneNumberBody:
      type: object
      required:
        - number
        - trunk_id
        - dispatch_rule_id
        - inbound_agent_id
      properties:
        number:
          type: string
          example: "+14155551234"
          description: E.164 phone number.
        trunk_id:
          type: string
          example: ST_xxxx
          description: SIP trunk ID.
        dispatch_rule_id:
          type: string
          example: SDR_xxxx
          description: Dispatch rule ID.
        inbound_agent_id:
          type: string
          example: 665a1b2c3d4e5f6a7b8c9d0e
          description: Agent ObjectId to handle inbound calls.
        outbound_agent_id:
          type: string
          example: 665a1b2c3d4e5f6a7b8c9d0f
          description: Agent ObjectId for outbound calls (optional).
        provider:
          type: string
          default: twilio
          example: twilio
          description: Telephony provider.
        nickname:
          type: string
          example: Sales Line
          description: Human-friendly label for this number.
    UpdatePhoneNumberBody:
      type: object
      properties:
        inbound_agent_id:
          type: string
          example: 665a1b2c3d4e5f6a7b8c9d0e
          description: New inbound agent ObjectId.
        outbound_agent_id:
          type: string
          example: 665a1b2c3d4e5f6a7b8c9d0f
          description: New outbound agent ObjectId.
        nickname:
          type: string
          example: Support Line
          description: Human-friendly label.
        is_active:
          type: boolean
          example: true
    PhoneNumberResponse:
      type: object
      properties:
        _id:
          type: string
          example: 64f1a...
        number:
          type: string
          example: "+14155551234"
        phone_number_pretty:
          type: string
          example: (415) 555-1234
        trunk_id:
          type: string
          example: ST_xxxx
        dispatch_rule_id:
          type: string
          example: SDR_xxxx
        inbound_agent_id:
          type: string
          example: 665a1b2c3d4e5f6a7b8c9d0e
        outbound_agent_id:
          type: string
          nullable: true
          example: null
        provider:
          type: string
          example: twilio
        nickname:
          type: string
          example: Sales Line
        is_active:
          type: boolean
          example: true
        created_at:
          type: string
          format: date-time
          example: 2024-02-25T10:00:00.000Z
        updated_at:
          type: string
          format: date-time
          example: 2024-02-25T10:00:00.000Z
    WebhookResponse:
      type: object
      properties:
        received:
          type: boolean
          example: true
        event_type:
          type: string
          example: room_started
        processed:
          type: boolean
          example: true
security:
  - BearerAuth: []
paths:
  /agent/list:
    get:
      tags:
        - Agents / CRUD
      summary: List all agents
      description: Returns a paginated list of all agents.
      security:
        - BearerAuth: []
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            default: 10
          description: Max agents per page.
        - in: query
          name: offset
          schema:
            type: integer
            default: 0
          description: Number of agents to skip.
      responses:
        "200":
          description: List of agents.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/AgentResponse"
  /agent:
    post:
      tags:
        - Agents / CRUD
      summary: Create a new agent
      description: Creates a new AI voice agent with the specified configuration.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateAgentBody"
      responses:
        "201":
          description: Agent created successfully.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/AgentResponse"
        "400":
          description: Validation error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /agent/{agent_id}:
    get:
      tags:
        - Agents / CRUD
      summary: Get agent by ID
      description: Retrieves a single agent by its public ID.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: agent_id
          required: true
          schema:
            type: string
          description: Agent's public nanoid.
      responses:
        "200":
          description: Agent found.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/AgentResponse"
        "404":
          description: Agent not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Agents / CRUD
      summary: Update an agent
      description: Partially updates an agent configuration. Increments version and
        resets is_published to false.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: agent_id
          required: true
          schema:
            type: string
          description: Agent's public nanoid.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateAgentBody"
      responses:
        "200":
          description: Agent updated.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/AgentResponse"
        "400":
          description: Validation error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Agent not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Agents / CRUD
      summary: Delete an agent
      description: Deletes an agent and cascades cleanup to related resources,
        including cancelling active calls.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: agent_id
          required: true
          schema:
            type: string
          description: Agent's public nanoid.
      responses:
        "200":
          description: Agent deleted.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: object
                        properties:
                          agent_id:
                            type: string
                            example: aBcDeFgHiJkLmNoP
        "404":
          description: Agent not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /agent/{agent_id}/publish:
    post:
      tags:
        - Agents / Versioning
      summary: Publish an agent version
      description: Publishes the current agent config as an immutable version
        snapshot. Idempotent — returns existing snapshot if already published.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: agent_id
          required: true
          schema:
            type: string
          description: Agent's public nanoid.
      requestBody:
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/PublishAgentBody"
      responses:
        "201":
          description: Version snapshot created.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/AgentVersionResponse"
        "400":
          description: Validation error.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
        "404":
          description: Agent not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /agent/{agent_id}/versions:
    get:
      tags:
        - Agents / Versioning
      summary: List agent versions
      description: Lists all published version snapshots for an agent.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: agent_id
          required: true
          schema:
            type: string
          description: Agent's public nanoid.
        - in: query
          name: limit
          schema:
            type: integer
            default: 10
          description: Max versions per page.
        - in: query
          name: offset
          schema:
            type: integer
            default: 0
          description: Number of versions to skip.
      responses:
        "200":
          description: List of version snapshots.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/AgentVersionResponse"
        "404":
          description: Agent not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /auth/api-keys:
    post:
      tags:
        - Auth
      summary: Create an API key
      description: Creates a new API key for an organization. The raw key is returned
        once and cannot be retrieved again.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateApiKeyBody"
      responses:
        "201":
          description: API key created. The `api_key` field is only shown once.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/ApiKeyResponse"
        "400":
          description: Invalid request body.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /auth/api-keys/{key_id}:
    delete:
      tags:
        - Auth
      summary: Revoke an API key
      description: Permanently deletes an API key by its key_id.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: key_id
          required: true
          schema:
            type: string
          description: The key_id returned when the key was created.
      responses:
        "200":
          description: API key revoked.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: object
                        nullable: true
                        example: null
        "404":
          description: Key not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /call/phone:
    post:
      tags:
        - Calls
      summary: Initiate an outbound phone call
      description: Creates an outbound SIP call based on source and destination phone
        numbers.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InitiateOutboundCallBody"
      responses:
        "201":
          description: Outbound call initiated.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/OutboundCallResponse"
        "400":
          description: Validation error or missing fields.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /call/web:
    post:
      tags:
        - Calls
      summary: Initiate a web call
      description: Creates a LiveKit room and returns an access token for the
        participant to join a browser-based call.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/InitiateWebCallBody"
      responses:
        "201":
          description: Web call initiated.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/WebCallResponse"
        "400":
          description: Missing agent_id or participant_identity.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /call/list:
    get:
      tags:
        - Calls
      summary: List calls
      description: Retrieve a paginated list of all calls.
      security:
        - BearerAuth: []
      parameters:
        - in: query
          name: limit
          schema:
            type: integer
            default: 10
          description: Max calls per page.
        - in: query
          name: offset
          schema:
            type: integer
            default: 0
          description: Number of calls to skip.
      responses:
        "200":
          description: List of calls.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/CallResponse"
    post:
      tags:
        - Calls
      summary: List calls via POST
      description: Retrieve a paginated list of calls (allows passing complex filters
        in body).
      security:
        - BearerAuth: []
      requestBody:
        required: false
        content:
          application/json:
            schema:
              type: object
              properties:
                limit:
                  type: integer
                  default: 10
                offset:
                  type: integer
                  default: 0
                filters:
                  type: object
                  additionalProperties: true
      responses:
        "200":
          description: List of calls matching the filter.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/CallResponse"
  /call/{call_id}:
    get:
      tags:
        - Calls
      summary: Get call details
      description: Retrieve detailed information for a specific call.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: call_id
          required: true
          schema:
            type: string
          description: Call ID.
      responses:
        "200":
          description: Call details.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/CallResponse"
        "404":
          description: Call not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    patch:
      tags:
        - Calls
      summary: Update call metadata
      description: Partially update a call's metadata.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: call_id
          required: true
          schema:
            type: string
          description: Call ID.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateCallBody"
      responses:
        "200":
          description: Call updated.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/CallResponse"
        "404":
          description: Call not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - Calls
      summary: Delete a call record
      description: Delete a call document from the database. Note that active calls
        should be ended first.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: call_id
          required: true
          schema:
            type: string
          description: Call ID.
      responses:
        "200":
          description: Call deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
        "404":
          description: Call not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /call/{call_id}/end:
    post:
      tags:
        - Calls
      summary: End a call
      description: Ends an active call by destroying the LiveKit room. Idempotent if
        already ended.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: call_id
          required: true
          schema:
            type: string
          description: Call ID.
      responses:
        "200":
          description: Call ended.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
        "404":
          description: Call not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /call/{roomName}/transcript:
    post:
      tags:
        - Calls
      summary: Store transcript from LiveKit session report
      description: >
        Receives the raw LiveKit SessionReport JSON from the Python agent on
        shutdown.

        Parses it into plain-text, structured, and tool-call-interleaved
        transcript

        formats and persists all three on the matching Call document.
      parameters:
        - in: path
          name: roomName
          required: true
          schema:
            type: string
          description: LiveKit room name (e.g. `call-<uuid>`).
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Raw LiveKit SessionReport payload.
      responses:
        "200":
          description: Transcript processed and stored successfully.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
        "404":
          description: No call found for the given room name.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /call/{call_id}/analyze:
    post:
      tags:
        - Calls
      summary: Test post-call analysis
      description: Manually triggers the LLM post-call analysis for a specific call.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: call_id
          required: true
          schema:
            type: string
          description: Call ID.
      responses:
        "200":
          description: Call analysis completed.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
        "404":
          description: Call not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /organizations/worker-name:
    get:
      tags:
        - Organizations
      summary: Get organization agent server name
      description: Returns the unique agent_server_name of the authenticated organization.
      security:
        - bearerAuth: []
      responses:
        "200":
          description: Agent server name retrieved successfully.
          content:
            application/json:
              schema:
                type: object
                properties:
                  success:
                    type: boolean
                    example: true
                  data:
                    type: object
                    properties:
                      worker_name:
                        type: string
                        example: agent-server-a1b2c3d4e5f6g7h8
                  message:
                    type: string
                    example: Agent server name retrieved successfully
  /providers:
    get:
      tags:
        - Providers
      summary: List all active providers
      description: Returns all active LLM providers. No authentication required.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of active providers.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/ProviderResponse"
  /providers/{provider_id}:
    get:
      tags:
        - Providers
      summary: Get provider details
      description: Returns a provider with a summary of its models.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
          description: Provider slug (e.g. "grok", "gemini").
      responses:
        "200":
          description: Provider details with models.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/ProviderDetailResponse"
        "404":
          description: Provider not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /providers/{provider_id}/models:
    get:
      tags:
        - Providers
      summary: List models for a provider
      description: Returns all active models for the specified provider, including
        capabilities and voices.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
          description: Provider slug.
      responses:
        "200":
          description: List of models with capabilities and voices.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/ProviderModelResponse"
        "404":
          description: Provider not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /providers/{provider_id}/models/{model_id}:
    get:
      tags:
        - Providers
      summary: Get model details
      description: Returns a single model with full capabilities, voices, and
        validation rules.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
        - in: path
          name: model_id
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Model details.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/ProviderModelResponse"
        "404":
          description: Model not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /admin/providers:
    get:
      tags:
        - Admin / Providers
      summary: List all providers (including inactive)
      security:
        - BearerAuth: []
      responses:
        "200":
          description: List of all providers.
    post:
      tags:
        - Admin / Providers
      summary: Create a new provider
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateProviderBody"
      responses:
        "201":
          description: Provider created.
        "400":
          description: Validation error.
        "409":
          description: Provider already exists.
  /admin/providers/{provider_id}:
    patch:
      tags:
        - Admin / Providers
      summary: Update a provider
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateProviderBody"
      responses:
        "200":
          description: Provider updated.
        "404":
          description: Provider not found.
    delete:
      tags:
        - Admin / Providers
      summary: Delete a provider and all its models
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Provider deleted.
        "404":
          description: Provider not found.
  /admin/providers/{provider_id}/models:
    get:
      tags:
        - Admin / Providers
      summary: List all models for a provider (including inactive)
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
      responses:
        "200":
          description: List of all models.
    post:
      tags:
        - Admin / Providers
      summary: Create a new model under a provider
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateProviderModelBody"
      responses:
        "201":
          description: Model created.
        "400":
          description: Validation error.
        "404":
          description: Provider not found.
        "409":
          description: Model already exists.
  /admin/providers/{provider_id}/models/{model_id}:
    patch:
      tags:
        - Admin / Providers
      summary: Update a model
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
        - in: path
          name: model_id
          required: true
          schema:
            type: string
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdateProviderModelBody"
      responses:
        "200":
          description: Model updated.
        "404":
          description: Model not found.
    delete:
      tags:
        - Admin / Providers
      summary: Delete a model
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: provider_id
          required: true
          schema:
            type: string
        - in: path
          name: model_id
          required: true
          schema:
            type: string
      responses:
        "200":
          description: Model deleted.
        "404":
          description: Model not found.
  /sip/trunks:
    post:
      tags:
        - SIP / Trunks
      summary: Create a SIP trunk
      description: Creates a new inbound SIP trunk on LiveKit.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateTrunkBody"
      responses:
        "201":
          description: Trunk created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
    get:
      tags:
        - SIP / Trunks
      summary: List SIP trunks
      description: Returns all inbound SIP trunks.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Trunks retrieved.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
  /sip/trunks/{id}:
    delete:
      tags:
        - SIP / Trunks
      summary: Delete a SIP trunk
      description: Deletes an inbound SIP trunk by its LiveKit ID.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
          description: LiveKit SIP trunk ID.
      responses:
        "200":
          description: Trunk deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
  /sip/dispatch-rules:
    post:
      tags:
        - SIP / Dispatch Rules
      summary: Create a dispatch rule
      description: Creates a SIP dispatch rule for routing incoming calls to LiveKit rooms.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreateDispatchRuleBody"
      responses:
        "201":
          description: Dispatch rule created.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
    get:
      tags:
        - SIP / Dispatch Rules
      summary: List dispatch rules
      description: Returns all SIP dispatch rules.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Dispatch rules retrieved.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
  /sip/dispatch-rules/{id}:
    delete:
      tags:
        - SIP / Dispatch Rules
      summary: Delete a dispatch rule
      description: Deletes a SIP dispatch rule by its LiveKit ID.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
          description: LiveKit dispatch rule ID.
      responses:
        "200":
          description: Dispatch rule deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
  /sip/phone-numbers:
    post:
      tags:
        - Phone Number
      summary: Purchase a phone number
      description: >
        Purchases a phone number from Twilio or Telnyx and automatically
        provisions it

        with a LiveKit SIP trunk and dispatch rule. The number is then saved to
        MongoDB

        bound to the specified agent.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/CreatePhoneNumberBody"
              type: object
              required:
                - area_code
                - inbound_agent_id
                - provider
              properties:
                area_code:
                  type: string
                  description: US area code to search (e.g. "415").
                  example: "415"
                inbound_agent_id:
                  type: string
                  description: Agent ObjectId to handle inbound calls.
                  example: 665a1b2c3d4e5f6a7b8c9d0e
                provider:
                  type: string
                  enum:
                    - twilio
                    - telnyx
                  description: Telephony provider to purchase from.
                  example: twilio
      responses:
        "201":
          description: Phone number purchased and provisioned.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/PhoneNumberResponse"
                        type: object
                        properties:
                          phone_number:
                            type: string
                          phone_number_pretty:
                            type: string
                          inbound_agent_id:
                            type: string
                          outbound_agent_id:
                            type: string
                            nullable: true
                          nickname:
                            type: string
                          provider:
                            type: string
                          trunk_id:
                            type: string
                          dispatch_rule_id:
                            type: string
        "400":
          description: Missing or invalid fields / provider not configured.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    get:
      tags:
        - SIP / Phone Numbers
      summary: List phone numbers
      description: Returns phone numbers with optional active/agent filters.
      security:
        - BearerAuth: []
      parameters:
        - in: query
          name: active
          schema:
            type: string
            enum:
              - "true"
              - "false"
          description: Filter by active status.
        - in: query
          name: inbound_agent_id
          schema:
            type: string
          description: Filter by inbound agent ObjectId.
      responses:
        "200":
          description: Phone numbers retrieved.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        type: array
                        items:
                          $ref: "#/components/schemas/PhoneNumberResponse"
  /sip/phone-numbers/import:
    post:
      tags:
        - SIP / Phone Numbers
      summary: Import external phone number
      description: Imports a phone number from an external SIP provider (Custom PBX).
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - phone_number
                - termination_uri
                - inbound_agent_id
              properties:
                phone_number:
                  type: string
                  description: E.164 formatted phone number.
                termination_uri:
                  type: string
                  description: SIP termination URI.
                sip_username:
                  type: string
                  description: Optional SIP auth username.
                sip_password:
                  type: string
                  description: Optional SIP auth password (stored encrypted).
                inbound_agent_id:
                  type: string
                  description: Agent ObjectId for inbound calls.
                outbound_agent_id:
                  type: string
                  description: Optional agent ObjectId for outbound calls.
                nickname:
                  type: string
                  description: Optional human-friendly label.
      responses:
        "201":
          description: Phone number imported and provisioned.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
        "400":
          description: Missing required fields.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /sip/phone-numbers/{id}:
    get:
      tags:
        - SIP / Phone Numbers
      summary: Get a phone number
      description: Retrieves a single phone number by ID with populated agent details.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
          description: Phone number document ID.
      responses:
        "200":
          description: Phone number retrieved.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/PhoneNumberResponse"
        "404":
          description: Phone number not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    put:
      tags:
        - SIP / Phone Numbers
      summary: Update a phone number
      description: Updates a phone number's agent bindings, nickname, or active status.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
          description: Phone number document ID.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: "#/components/schemas/UpdatePhoneNumberBody"
      responses:
        "200":
          description: Phone number updated.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/PhoneNumberResponse"
        "404":
          description: Phone number not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
    delete:
      tags:
        - SIP / Phone Numbers
      summary: Delete a phone number
      description: Deletes a phone number registration.
      security:
        - BearerAuth: []
      parameters:
        - in: path
          name: id
          required: true
          schema:
            type: string
          description: Phone number document ID.
      responses:
        "200":
          description: Phone number deleted.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
        "404":
          description: Phone number not found.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
  /tts/generate-transcript:
    post:
      summary: Generate a filler transcript from a prompt
      tags:
        - TTS
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - prompt
                - language_code
                - agent_persona
                - tool_name
              properties:
                prompt:
                  type: string
                  example: Acknowledge enthusiastically
                language_code:
                  type: string
                  example: en
                agent_persona:
                  type: string
                  example: You are a helpful customer support agent.
                tool_name:
                  type: string
                  example: transfer_call
                provider:
                  type: string
                  enum:
                    - gemini
                    - grok
                  default: gemini
                  example: gemini
                  description: TTS provider to use (gemini or grok/xAI)
      responses:
        "200":
          description: Successfully generated transcript
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/SuccessResponse"
  /tts/generate-audio:
    post:
      summary: Generate TTS audio for a transcript
      tags:
        - TTS
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - agent_name
                - system_prompt
                - voice_id
                - transcript
              properties:
                agent_name:
                  type: string
                  example: Support Agent
                system_prompt:
                  type: string
                  example: You are a helpful customer support agent.
                voice_id:
                  type: string
                  example: Aoede
                transcript:
                  type: string
                  example: Let me check that for you right away!
                provider:
                  type: string
                  enum:
                    - gemini
                    - grok
                  default: gemini
                  example: gemini
                  description: TTS provider to use (gemini or grok/xAI)
      responses:
        "200":
          description: Raw WAV audio buffer
          content:
            audio/wav:
              schema:
                type: string
                format: binary
  /tts/generate-audio-full-prompt:
    post:
      summary: Generate TTS audio with a fully customized prompt
      tags:
        - TTS
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - audio_profile
                - the_scene
                - directors_note
                - pacing
                - transcript
                - voice_id
              properties:
                audio_profile:
                  type: string
                  example: Support Agent
                the_scene:
                  type: string
                  example: You are a helpful customer support agent.
                directors_note:
                  type: string
                  example: The character is thinking out loud.
                pacing:
                  type: string
                  example: Fast, energetic
                transcript:
                  type: string
                  example: Let me check that for you right away!
                voice_id:
                  type: string
                  example: Aoede
                provider:
                  type: string
                  enum:
                    - gemini
                    - grok
                  default: gemini
                  example: gemini
                  description: TTS provider to use (gemini or grok/xAI)
      responses:
        "200":
          description: Raw WAV audio buffer
          content:
            audio/wav:
              schema:
                type: string
                format: binary
  /users/register:
    post:
      tags:
        - Users
      summary: Register a new user and organization
      description: Creates a new organization and an admin user account. No
        authentication required.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - organization_name
                - first_name
                - last_name
                - email
                - password
              properties:
                organization_name:
                  type: string
                  example: Acme Corp
                first_name:
                  type: string
                  example: John
                last_name:
                  type: string
                  example: Doe
                email:
                  type: string
                  format: email
                  example: john@acme.com
                password:
                  type: string
                  minLength: 6
                  example: password123
      responses:
        "201":
          description: Registration successful.
        "400":
          description: Validation error or email already in use.
  /users/login:
    post:
      tags:
        - Users
      summary: Login with email and password
      description: Authenticates a user and returns a JWT token. Use this token as a
        Bearer token for all protected endpoints.
      security: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - email
                - password
              properties:
                email:
                  type: string
                  format: email
                  example: john@acme.com
                password:
                  type: string
                  example: password123
      responses:
        "200":
          description: Login successful. Returns a JWT token.
        "401":
          description: Invalid credentials.
  /users/logout:
    post:
      tags:
        - Users
      summary: Logout
      description: For stateless JWTs, the frontend simply deletes the token. This
        endpoint returns a success acknowledgment.
      security: []
      responses:
        "200":
          description: Logged out successfully.
  /users/member:
    post:
      tags:
        - Users
      summary: Add a team member to your organization
      description: Creates a new user account linked to the admin's organization.
        Requires admin role.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              required:
                - first_name
                - last_name
                - email
                - password
              properties:
                first_name:
                  type: string
                  example: Jane
                last_name:
                  type: string
                  example: Smith
                email:
                  type: string
                  format: email
                  example: jane@acme.com
                password:
                  type: string
                  minLength: 6
                  example: password123
                role:
                  type: string
                  enum:
                    - admin
                    - member
                  default: member
                  example: member
      responses:
        "201":
          description: Team member added successfully.
        "400":
          description: Validation error or email already in use.
        "403":
          description: Forbidden. Admin access required.
  /users/members:
    get:
      tags:
        - Users
      summary: List all members in your organization
      description: Returns all users belonging to the authenticated user's
        organization. Requires login.
      security:
        - BearerAuth: []
      responses:
        "200":
          description: Members retrieved successfully.
  /webhooks/livekit:
    post:
      tags:
        - Webhooks
      summary: LiveKit webhook receiver
      description: Receives signed webhook events from LiveKit. Validates signature,
        stores the event, and processes it.
      security:
        - BearerAuth: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              description: Raw LiveKit webhook payload (varies by event type).
              additionalProperties: true
      responses:
        "200":
          description: Webhook received and processed.
          content:
            application/json:
              schema:
                allOf:
                  - $ref: "#/components/schemas/SuccessResponse"
                  - type: object
                    properties:
                      data:
                        $ref: "#/components/schemas/WebhookResponse"
        "401":
          description: Invalid webhook signature.
          content:
            application/json:
              schema:
                $ref: "#/components/schemas/ErrorResponse"
