> ## Documentation Index
> Fetch the complete documentation index at: https://docs.vocily.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Create an agent

> Build a fully configured agent in one request.

<Note>
  A new agent is created as an **unpublished draft (V0)**. It answers no calls until you
  [publish a version](/developers/agents/publish) and [make it live](/developers/agents/make-live) —
  both explicit, both deliberate.
</Note>

## The smallest useful request

Everything you leave out takes the platform default: Hindi with English alongside it, a Vocily voice,
`gpt-5.4-nano`, Sarvam speech recognition, the eleven system messages, and the Default Analysis group.

```json theme={"dark"}
{
  "name": "Acme COD Confirmation",
  "system_prompt": "## Agent Purpose\nYou confirm cash-on-delivery orders for Acme.\n\n## Response Style\nWarm, brief, one question at a time.\n\n## Call Flow\n1. Greet {{callee_name}}.\n2. Read back the order.\n3. Ask whether they will accept delivery.",
  "greeting": { "message": "Namaste {{callee_name}}, main Acme Store se bol rahi hoon." },
  "language": { "default": "hi-IN", "additional": ["en-IN"] }
}
```

## Writing the prompt

Three headings structure it, and they are the same three boxes the dashboard shows:
`## Agent Purpose`, `## Response Style`, `## Call Flow`. A prompt with no headings is treated as
Agent Purpose.

Four kinds of token do work inside it:

| Token                          | Meaning                                                                                                                                                                        |
| ------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `{{order_id}}`                 | A variable. Keys you use here are added to the agent automatically; supply values per call in `POST /v1/calls`. `{{callee_name}}` and `{{callee_number}}` are always available |
| `<confirm_order>`              | **Arms a tool.** A tool exists but cannot be called until the prompt names it this way                                                                                         |
| `\|\|confirm_order.status\|\|` | A value a during-call tool returned                                                                                                                                            |
| `((fetch_order.amount))`       | A value a pre-call tool fetched before the call connected                                                                                                                      |

<Warning>
  **Tools are built in the dashboard, not here.** This body neither accepts nor returns them.
  Naming one the agent does not have is rejected with `prompt_tool_reference_invalid`, so create
  the tool on the agent's Tools tab first, then write a prompt that arms it.
</Warning>

## Picking values you cannot guess

| Field                      | Where its values come from                                                                     |
| -------------------------- | ---------------------------------------------------------------------------------------------- |
| `voice.voice_id`           | [List voices](/developers/catalogues/voices)                                                   |
| `voice.model`              | Only for a provider with more than one. The Vocily voice has one, `v2`, filled in when omitted |
| `model.model`              | [List models](/developers/catalogues/models)                                                   |
| `transcriber.model`        | [List transcribers](/developers/catalogues/transcribers)                                       |
| `language.default`         | [List languages](/developers/catalogues/languages)                                             |
| `numbers.inbound_phone`    | [List phone numbers](/developers/numbers/list)                                                 |
| `numbers.inbound_whatsapp` | [List WhatsApp numbers](/developers/integrations/whatsapp-numbers)                             |
| `knowledge_base_ids`       | [List knowledge bases](/developers/knowledge-bases/list)                                       |
| `analysis_group_ids`       | [The analysis library](/developers/custom-analysis/list)                                       |

<Tip>
  A voice provider must be able to speak `language.default`, or the agent is refused with
  `voice_config_invalid` — an agent that saved but could not speak would fail every call.
  [TTS capabilities](/developers/catalogues/tts-capabilities) says which provider covers which language.
</Tip>


## OpenAPI

````yaml developers/openapi.json POST /v1/agents
openapi: 3.1.0
info:
  title: Vocily API
  description: >-
    Public REST API for Vocily. Build and configure an agent, publish a version
    and put it live, place outbound calls, and read back calls, chats and what
    the agent remembered. Authenticate with a workspace API key as a Bearer
    token.


    Some things stay in the dashboard, by design: creating an API key, buying or
    connecting a phone number, setting an agent's webhook URL, connecting
    WhatsApp and its templates, building HTTP tools, and running batch
    campaigns.
  version: v1
servers:
  - url: https://api.vocily.ai
    description: Production
security: []
paths:
  /v1/agents:
    post:
      tags:
        - agents
      summary: Create Agent
      description: >-
        Create an agent, fully configured, in one request — prompt, voice,
        model, built-in tools, transfer numbers, variables, memory and numbers.


        The agent is created as an unpublished **draft, version 0**. It answers
        no call until you publish a version and make it live.


        Custom tools are built in the dashboard, not here: this body neither
        accepts nor returns them, and a prompt that arms one the agent does not
        have is refused.
      operationId: create_agent_v1_agents_post
      parameters: []
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/PublicAgentCreate'
            example:
              name: Acme COD Confirmation
              system_prompt: |-
                ## Agent Purpose
                You confirm cash-on-delivery orders for Acme Store.

                ## Response Style
                Warm, brief, one question at a time.

                ## Call Flow
                1. Greet {{callee_name}}.
                2. Read back the order.
                3. Ask whether they will accept delivery.
              greeting:
                message: Namaste {{callee_name}}, main Acme Store se bol rahi hoon.
              language:
                default: hi-IN
                additional:
                  - en-IN
              voice:
                provider: vocily
                voice_id: hi-IN-aman
                speed: 1
              model:
                model: gpt-5.4-nano
                temperature: 0.4
              transcriber:
                provider: sarvam
                model: saaras:v4
                keywords:
                  - Acme
                  - COD
              call:
                max_duration_minutes: 5
                recording_enabled: true
              builtin_tools:
                transfer_call:
                  enabled: true
                  numbers:
                    - number: '+919876543210'
                      priority: 1
                      start_hour: 9
                      end_hour: 20
                      timezone: Asia/Kolkata
              variables:
                - key: order_id
                  default_value: null
      responses:
        '201':
          description: >-
            The created agent, at its V0 draft. It answers no calls until a
            version is published and made live.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/PublicAgentDetail'
              example:
                id: 00000005-0000-4000-8000-000000000005
                name: Support line
                version: 0
                version_id: 00000006-0000-4000-8000-000000000006
                is_published: false
                is_live: false
                live_version: null
                latest_version: 0
                document_revision: 1
                label: null
                notes: null
                blocked_reasons: []
                created_at: '2026-09-16T19:38:03.767024Z'
                updated_at: '2026-09-16T19:38:03.767024Z'
                system_prompt: |-
                  ## Agent Purpose
                  You confirm cash-on-delivery orders for Acme Store.

                  ## Response Style
                  Warm, brief, one question at a time.

                  ## Call Flow
                  1. Greet {{callee_name}}.
                  2. Read back order {{order_id}}.
                  3. Ask whether they accept delivery.
                  4. Close politely.
                greeting: {}
                language:
                  default: hi-IN
                  additional:
                    - en-IN
                  switch_trigger: requested_or_auto
                transcriber:
                  provider: sarvam
                  model: saaras:v4
                  keywords:
                    - Acme
                    - COD
                  fallback:
                    provider: deepgram
                    model: nova-3-general
                model:
                  provider: openai
                  model: gpt-5.4-nano
                  temperature: 0.4
                  max_tokens: 128
                  fallback:
                    provider: gemini
                    model: gemini-3.5-flash-lite
                voice:
                  provider: vocily
                  model: v2
                  voice_id: hi-IN-aman
                  speed: 1
                  emotion: null
                  fallback:
                    provider: sarvam
                    model: bulbul:v3
                    voice_id: shubh
                conversation:
                  interruption_sensitivity: 0.5
                  response_eagerness: 0.75
                  noise_handling:
                    mode: standard
                    level: 50
                  silence_reminder:
                    enabled: true
                    seconds: 15
                call:
                  max_duration_minutes: 5
                  end_on_silence_seconds: 25
                  recording_enabled: true
                  custom_analysis_enabled: true
                  max_duration_message:
                    mode: default
                    prompt: >-
                      The call has reached its maximum allowed duration and must
                      end now. Generate a brief, natural closing in the same
                      language and tone as the conversation above. The message
                      must clearly preserve this intent: the maximum call time
                      has been reached, so the call is ending now. Keep it to
                      one short sentence, with an optional brief thank-you. Do
                      not ask a question. Do not offer more help, a callback,
                      next steps, or reopen the conversation.
                    text: ''
                  end_on_silence_message:
                    mode: default
                    prompt: >-
                      The caller has been silent for too long and the call is
                      ending now. Generate a brief, natural closing in the same
                      language and tone as the conversation above. The message
                      must clearly preserve this intent: you could not hear
                      anything on the line, so you are ending the call now. Keep
                      it to one short sentence, with an optional brief
                      thank-you. Do not ask a question. Do not offer more help,
                      a callback, next steps, or reopen the conversation.
                    text: ''
                builtin_tools:
                  end_call:
                    enabled: true
                  hold_call:
                    enabled: true
                    max_seconds: 90
                    follow_up_seconds: 45
                    acknowledgement_message:
                      mode: default
                      prompt: >-
                        Write one short sentence to say to the caller as you
                        start waiting, in the language you have been speaking —
                        confirming you heard them and will wait. Do not ask a
                        question and do not guess why they need the moment.
                      text: ''
                    follow_up_message:
                      mode: default
                      prompt: >-
                        You agreed to wait while the caller stepped away for a
                        moment (they may be fetching a card, a document, or
                        checking something). Generate one very short, gentle
                        check-in in the same language and tone as the
                        conversation above. Keep it to one short sentence, e.g.
                        asking if they are back or reassuring them you are still
                        on the line. Do not say goodbye. Do not say the call is
                        ending. Do not repeat earlier content or ask new
                        questions.
                      text: ''
                    timeout_message:
                      mode: default
                      prompt: >-
                        You agreed to wait while the caller stepped away, but
                        they have not returned and the call is ending now.
                        Generate a brief, natural closing in the same language
                        and tone as the conversation above. The message must
                        clearly preserve this intent: you waited but could not
                        reach them, so you are ending the call; they are welcome
                        to call back. Keep it to one short sentence. Do not ask
                        a question.
                      text: ''
                  transfer_call:
                    enabled: true
                    numbers:
                      - number: '+919876543210'
                        priority: 1
                        start_hour: 9
                        end_hour: 20
                        timezone: Asia/Kolkata
                    busy_message:
                      mode: default
                      prompt: >-
                        You tried to transfer the caller to a human teammate,
                        but nobody is available. Generate one short line in the
                        same language and tone as the conversation above, saying
                        the team is busy and someone will call them back on this
                        number. Do not ask a question and do not promise a
                        specific callback time.
                      text: ''
                    intro_message:
                      mode: custom
                      prompt: >-
                        You are about to transfer the caller to a human
                        teammate. Generate one short line in the same language
                        and tone as the conversation above, telling them to hold
                        while you connect them, and that we will call back if
                        the call drops. Do not ask a question and do not promise
                        a specific person or wait time.
                      text: Ek minute, main aapko connect karti hoon.
                  send_whatsapp_template:
                    enabled: false
                    allowed_templates: []
                    phone_number_id: ''
                variables:
                  - key: callee_name
                    default_value: null
                    system_defined: true
                    deletable: false
                  - key: callee_number
                    default_value: null
                    system_defined: true
                    deletable: false
                knowledge_base_ids: []
                analysis_group_ids:
                  - 00000007-0000-4000-8000-000000000007
                memory:
                  enabled: true
                  channels:
                    - outbound
                    - whatsapp
                  allow_ai_labels: true
                  label_instructions: >-
                    Record anything about the caller worth knowing next time,
                    even when it is not one of the fields above: who they are,
                    other ways to reach them, how they prefer to be dealt with,
                    their standing with the business, or anything situational.
                    Only what will still be true later; nothing said in passing.
                  max_facts: 150
                  transcript_turns: 12
                  fields:
                    - key: delivery_pincode
                      label: Delivery PIN code
                      type: string
                      enum_values: null
                      description: The PIN code the caller wants deliveries sent to.
                      category: contact
                numbers: null
                dashboard_url: >-
                  https://app.vocily.ai/agents/00000005-0000-4000-8000-000000000005
                inbound:
                  business_hours_closed_message:
                    mode: default
                    prompt: >-
                      This inbound call arrived outside business hours. Generate
                      one short line telling the caller we are closed right now
                      and inviting them to call back during business hours. Keep
                      it to one sentence. Do not ask a question and do not
                      invent the opening hours.
                    text: ''
                  fallback_message:
                    mode: default
                    prompt: >-
                      This inbound call cannot be handled right now. Generate
                      one short, apologetic line asking the caller to try again
                      later. Keep it to one sentence. Do not ask a question and
                      do not explain the technical reason.
                    text: ''
        '400':
          description: >-
            The configuration cannot work as sent, and nothing is created or
            changed. `voice_not_found`: `voice.voice_id` — or a backup's — is
            not a voice that provider offers for the agent's language; `GET
            /v1/voices` lists them. `voice_config_invalid`: the voice block
            itself cannot work — an unknown or withdrawn provider, a provider
            that cannot speak a configured language, or a backup that could
            never be used. `document_invalid`: the field is real and the value
            well-formed, and the agent still cannot use it — a number in
            `numbers` this workspace does not hold (`GET /v1/numbers` and `GET
            /v1/whatsapp/numbers` list them), a hold check-in that lands after
            the hold ends, an emotion no provider speaks. `invalid_request`: the
            request itself is malformed — a `?version=` that is neither `live`
            nor a number, or an `If-Match` that is not a `document_revision`.
            Every message names the field.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              examples:
                voice_not_found:
                  value:
                    detail:
                      code: voice_not_found
                      message: >-
                        `no-such-voice` is not a voice `vocily` offers for
                        `hi-IN`. GET /v1/voices?provider=vocily&language=hi-IN
                        lists the ones that are.
                      param: voice.voice_id
                    code: BAD_REQUEST
                number_not_held:
                  value:
                    detail:
                      code: document_invalid
                      message: >-
                        +919876543210 is not a number in this workspace. Choose
                        one of the workspace's own numbers (GET /v1/numbers
                        lists them).
                    code: BAD_REQUEST
              example:
                detail:
                  code: voice_config_invalid
                code: BAD_REQUEST
        '401':
          description: Missing or invalid API key.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              example:
                detail: Invalid API key
                code: UNAUTHORIZED
        '422':
          description: Validation Error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/HTTPValidationError'
        '429':
          description: Rate limit exceeded — honor `Retry-After`.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ApiError'
              example:
                code: rate_limited
      security:
        - bearerAuth: []
components:
  schemas:
    PublicAgentCreate:
      additionalProperties: false
      description: >-
        Create an agent, fully configured, in one request.


        `name` is the only required field — everything else takes the platform
        default, so the

        smallest useful body is a name, a prompt and a greeting. The agent is
        created as an

        **unpublished draft (V0)**: it answers nothing until you publish a
        version and make it

        live, which stays two explicit calls.
      properties:
        name:
          description: >-
            What the agent is called. The one required field. Never spoken to a
            caller.
          maxLength: 255
          minLength: 1
          title: Name
          type: string
        system_prompt:
          anyOf:
            - maxLength: 65536
              minLength: 1
              type: string
            - type: 'null'
          default: null
          description: >-
            The agent's instructions. Naming a tool as `<tool_name>` here is
            what ARMS it: a tool the prompt never names is never called, and
            naming one the version does not have is refused on save.
          title: System Prompt
        greeting:
          anyOf:
            - $ref: '#/components/schemas/Greeting'
            - type: 'null'
          default: null
          description: What the agent says first.
        language:
          anyOf:
            - $ref: '#/components/schemas/LanguageConfig'
            - type: 'null'
          default: null
          description: >-
            The language it opens in, which others it may switch to, and what
            triggers a switch.
        transcriber:
          anyOf:
            - $ref: '#/components/schemas/Transcriber'
            - type: 'null'
          default: null
          description: >-
            Speech recognition. `GET /v1/transcribers` lists valid `model`
            values.
        model:
          anyOf:
            - $ref: '#/components/schemas/Model'
            - type: 'null'
          default: null
          description: The LLM. `GET /v1/models` lists valid `model` and `provider` values.
        voice:
          anyOf:
            - $ref: '#/components/schemas/Voice'
            - type: 'null'
          default: null
          description: >-
            Text to speech. `GET /v1/voices` lists valid `voice_id` values, and
            a voice that cannot speak `language.default` is refused on save.
        conversation:
          anyOf:
            - $ref: '#/components/schemas/Conversation'
            - type: 'null'
          default: null
          description: >-
            Turn-taking, interruption and noise handling — how it behaves in the
            back-and-forth.
        call:
          anyOf:
            - $ref: '#/components/schemas/CallSettings'
            - type: 'null'
          default: null
          description: >-
            Limits on the call itself: maximum duration, silence timeout, and
            what ends it.
        inbound:
          anyOf:
            - $ref: '#/components/schemas/Inbound'
            - type: 'null'
          default: null
          description: Lines for inbound calls that cannot be handled normally.
        builtin_tools:
          anyOf:
            - $ref: '#/components/schemas/BuiltinTools'
            - type: 'null'
          default: null
          description: >-
            The tools Vocily ships: end the call, hold, transfer, send a
            WhatsApp template. Each still has to be armed from the prompt.
        variables:
          anyOf:
            - items:
                $ref: '#/components/schemas/RuntimeVariable'
              type: array
            - type: 'null'
          default: null
          description: >-
            The `{{placeholders}}` the prompt and tools can use. Reference them
            namespaced as `{{custom.your_key}}`, never bare. Sending this list
            replaces the whole set.
          title: Variables
        knowledge_base_ids:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          description: >-
            Which knowledge bases this agent can search, from `GET
            /v1/knowledge-bases`. **This list IS the attachment** — there is no
            separate attach endpoint, and sending it replaces the whole set. An
            id this workspace does not hold is refused, not ignored.
          title: Knowledge Base Ids
        analysis_group_ids:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          description: >-
            Which custom-analysis groups run after each call, from `GET
            /v1/custom-analysis`. The list is the attachment, and an id this
            workspace does not hold is refused, not ignored.
          title: Analysis Group Ids
        memory:
          anyOf:
            - $ref: '#/components/schemas/Memory'
            - type: 'null'
          default: null
          description: >-
            Whether the agent remembers callers between calls, and what it is
            allowed to remember.
        numbers:
          anyOf:
            - $ref: '#/components/schemas/Numbers'
            - type: 'null'
          default: null
          description: >-
            Which phone and WhatsApp numbers this agent answers on. `GET
            /v1/numbers` and `GET /v1/whatsapp/numbers` list what you may use.
      required:
        - name
      title: PublicAgentCreate
      type: object
    PublicAgentDetail:
      additionalProperties: false
      description: >-
        One agent at one version — the response of every agent read, create and
        update.


        A request body is this same object minus the read-only fields, so what
        you send is what you read back.
      properties:
        id:
          description: The agent's id. Stable across every version.
          title: Id
          type: string
        name:
          description: What the agent is called. Yours to choose; never spoken to a caller.
          title: Name
          type: string
        version:
          description: >-
            Which version this body describes. 0-based, and the identity you use
            in `/versions/{n}` and `?version=`.
          title: Version
          type: integer
        version_id:
          description: >-
            This version's uuid. Pass it as `agent_version_id` on `POST
            /v1/calls` to pin a call to this exact version — that field takes a
            uuid, not a number.
          title: Version Id
          type: string
        is_published:
          description: >-
            True once frozen. A published version's configuration can never be
            edited again; branch a draft instead.
          title: Is Published
          type: boolean
        is_live:
          description: True if this is the version answering calls right now.
          title: Is Live
          type: boolean
        live_version:
          anyOf:
            - type: integer
            - type: 'null'
          default: null
          description: >-
            Which version is live, if any. `null` means the agent is off air and
            answers nothing.
          title: Live Version
        latest_version:
          description: The highest version number this agent has.
          title: Latest Version
          type: integer
        document_revision:
          description: >-
            This version's edit counter. Echo it back as `If-Match` on your next
            write and the write becomes a compare-and-set, so you cannot
            silently overwrite an edit made between your read and your write.
          title: Document Revision
          type: integer
        label:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Short name for this version, e.g. `Shorter greeting`. Editable even
            after publishing — it is metadata, not configuration.
          title: Label
        notes:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Longer free text about this version.
          title: Notes
        blocked_reasons:
          description: >-
            Why this version cannot be made live, if it cannot — e.g. it pins a
            model that has since been retired. Empty means it can go live.
          items:
            type: string
          title: Blocked Reasons
          type: array
        created_at:
          description: When this version was created (UTC, ISO 8601).
          format: date-time
          title: Created At
          type: string
        updated_at:
          description: When this version was last edited (UTC, ISO 8601).
          format: date-time
          title: Updated At
          type: string
        system_prompt:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            The agent's instructions. Naming a tool as `<tool_name>` here is
            what ARMS it: a tool the prompt never names is never called, and
            naming one the version does not have is refused on save.
          title: System Prompt
        greeting:
          anyOf:
            - $ref: '#/components/schemas/Greeting'
            - type: 'null'
          default: null
          description: What the agent says first.
        language:
          anyOf:
            - $ref: '#/components/schemas/LanguageConfig'
            - type: 'null'
          default: null
          description: >-
            The language it opens in, which others it may switch to, and what
            triggers a switch.
        transcriber:
          anyOf:
            - $ref: '#/components/schemas/Transcriber'
            - type: 'null'
          default: null
          description: >-
            Speech recognition. `GET /v1/transcribers` lists valid `model`
            values.
        model:
          anyOf:
            - $ref: '#/components/schemas/Model'
            - type: 'null'
          default: null
          description: The LLM. `GET /v1/models` lists valid `model` and `provider` values.
        voice:
          anyOf:
            - $ref: '#/components/schemas/Voice'
            - type: 'null'
          default: null
          description: >-
            Text to speech. `GET /v1/voices` lists valid `voice_id` values, and
            a voice that cannot speak `language.default` is refused on save.
        conversation:
          anyOf:
            - $ref: '#/components/schemas/Conversation'
            - type: 'null'
          default: null
          description: >-
            Turn-taking, interruption and noise handling — how it behaves in the
            back-and-forth.
        call:
          anyOf:
            - $ref: '#/components/schemas/CallSettings'
            - type: 'null'
          default: null
          description: >-
            Limits on the call itself: maximum duration, silence timeout, and
            what ends it.
        inbound:
          anyOf:
            - $ref: '#/components/schemas/Inbound'
            - type: 'null'
          default: null
          description: Lines for inbound calls that cannot be handled normally.
        builtin_tools:
          anyOf:
            - $ref: '#/components/schemas/BuiltinTools'
            - type: 'null'
          default: null
          description: >-
            The tools Vocily ships: end the call, hold, transfer, send a
            WhatsApp template. Each still has to be armed from the prompt.
        variables:
          description: >-
            The `{{placeholders}}` the prompt and tools can use. Reference them
            namespaced as `{{custom.your_key}}`, never bare.
          items:
            $ref: '#/components/schemas/RuntimeVariable'
          title: Variables
          type: array
        knowledge_base_ids:
          description: >-
            Which knowledge bases this agent can search, from `GET
            /v1/knowledge-bases`. **This list IS the attachment** — there is no
            separate attach endpoint, and sending it replaces the whole set. An
            id this workspace does not hold is refused, not ignored.
          items:
            type: string
          title: Knowledge Base Ids
          type: array
        analysis_group_ids:
          description: >-
            Which custom-analysis groups run after each call, from `GET
            /v1/custom-analysis`. Same rule as `knowledge_base_ids`: the list is
            the attachment, and an id this workspace does not hold is refused,
            not ignored.
          items:
            type: string
          title: Analysis Group Ids
          type: array
        memory:
          anyOf:
            - $ref: '#/components/schemas/Memory'
            - type: 'null'
          default: null
          description: >-
            Whether the agent remembers callers between calls, and what it is
            allowed to remember.
        numbers:
          anyOf:
            - $ref: '#/components/schemas/Numbers'
            - type: 'null'
          default: null
          description: >-
            Which phone and WhatsApp numbers this agent answers on. `GET
            /v1/numbers` and `GET /v1/whatsapp/numbers` list what you may use.
        dashboard_url:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Deep link to this agent in the Vocily dashboard, for your own UI to
            link out to.
          title: Dashboard Url
      required:
        - id
        - name
        - version
        - version_id
        - is_published
        - is_live
        - latest_version
        - document_revision
        - created_at
        - updated_at
      title: PublicAgentDetail
      type: object
    ApiError:
      type: object
      description: >-
        Error envelope. `code` is derived from the HTTP status, so branch on it
        for the CLASS of failure; the specific reason is `detail.code`. Every
        public refusal carries both.
      properties:
        detail:
          type: object
          description: >-
            The reason. `code` is the domain reason (e.g. `call_not_found`) and
            `message` is a sentence safe to log. On a `422` it also carries
            `errors[]`, one entry per rejected field — see
            `HTTPValidationError`.
          properties:
            code:
              type: string
              example: call_not_found
            message:
              type: string
              example: Call not found
          required:
            - code
            - message
        code:
          type: string
          description: Derived from the HTTP status, not the domain reason.
          example: NOT_FOUND
    HTTPValidationError:
      type: object
      title: HTTPValidationError
      description: >-
        A request the API could not read: a field of the wrong type, out of
        range, missing, or one we do not accept. Same envelope as every other
        error.
      properties:
        detail:
          type: object
          description: >-
            What was wrong, as `code`, a one-line `message`, and every offending
            field in `errors`.
          required:
            - code
            - message
            - errors
          properties:
            code:
              type: string
              enum:
                - validation_error
            message:
              type: string
              description: >-
                The first problem in one line, with a count of the rest — e.g.
                `model.temperature: Input should be less than or equal to 2 (and
                1 more)`.
            errors:
              type: array
              items:
                $ref: '#/components/schemas/ValidationError'
              description: >-
                One entry per offending field. **Every problem is reported at
                once**, not just the first, so a malformed body needs one round
                trip to fix rather than one per field.
        code:
          type: string
          enum:
            - VALIDATION_ERROR
          description: Derived from the HTTP status, as on every error.
    Greeting:
      additionalProperties: false
      description: The first thing the agent says. May use `{{variables}}`.
      properties:
        message:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            The first thing the agent says. Leave empty and the agent waits for
            the caller to speak first. Spoken aloud, so it is capped at 2000
            characters.
          title: Message
      title: Greeting
      type: object
    LanguageConfig:
      additionalProperties: false
      description: The language the call starts in, plus the set it may switch into.
      properties:
        default:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            The language the call opens in, e.g. `hi-IN`. The voice must be
            certified for it or the agent is refused on save.
          title: Default
        additional:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          description: >-
            Other languages it may switch to mid-call. A language cannot be both
            the default and an additional one.
          title: Additional
        switch_trigger:
          anyOf:
            - enum:
                - requested_or_auto
                - requested_only
              type: string
            - type: 'null'
          default: null
          description: >-
            `requested_or_auto` also switches when it hears a different
            language; `requested_only` switches only when asked.
          title: Switch Trigger
      title: LanguageConfig
      type: object
    Transcriber:
      additionalProperties: false
      description: Speech recognition. `GET /v1/transcribers` lists what `model` accepts.
      properties:
        provider:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Read-only. Derived from `model` — each speech model belongs to
            exactly one provider, so a value sent here is replaced by the one
            the catalogue names.
          title: Provider
        model:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Model id, from `GET /v1/transcribers`. It must cover every language
            in the agent's set or the agent is refused on save.
          title: Model
        keywords:
          description: >-
            Words to bias recognition towards — brand names, product names,
            anything it mishears. How strongly they apply depends on the speech
            model: some take them as a recognition boost, and one is told to
            expect them, which is weaker. Send the same list either way.
          items:
            type: string
          title: Keywords
          type: array
        fallback:
          anyOf:
            - $ref: '#/components/schemas/TranscriberFallback'
            - type: 'null'
          default: null
          description: >-
            Backup speech model, used for the rest of the call if this one's
            provider stops responding. Send `{"model": "nova-3-general"}` — the
            provider is filled in. Must be from a different provider — one on
            the main engine's own provider is refused. See
            [Backups](/developers/agents/backups).
      title: Transcriber
      type: object
    Model:
      additionalProperties: false
      description: The LLM. `GET /v1/models` is the catalogue.
      properties:
        provider:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Read-only. Derived from `model` — the catalogue decides routing, so
            a value sent here is replaced by the one the catalogue names.
          title: Provider
        model:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Model id, from `GET /v1/models`. Every model that catalogue lists
            can be used.
          title: Model
        temperature:
          anyOf:
            - maximum: 2
              minimum: 0
              type: number
            - type: 'null'
          default: null
          description: Randomness. Lower is more repeatable; higher is more varied.
          title: Temperature
        max_tokens:
          anyOf:
            - maximum: 256
              minimum: 10
              type: integer
            - type: 'null'
          default: null
          description: Cap on the length of a single reply.
          title: Max Tokens
        fallback:
          anyOf:
            - $ref: '#/components/schemas/ModelFallback'
            - type: 'null'
          default: null
          description: >-
            Backup model, used for the rest of the call if this one's provider
            stops responding. Send `{"model": "gemini-3.5-flash-lite"}` — the
            provider is filled in. Must be from a different provider — one on
            the main engine's own provider is refused. See
            [Backups](/developers/agents/backups).
      title: Model
      type: object
    Voice:
      additionalProperties: false
      description: >-
        Text to speech. `GET /v1/voices?provider=` lists voices; `GET
        /v1/tts-capabilities`

        says which languages each provider can be handed at all.
      properties:
        provider:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: TTS provider, from `GET /v1/voices`.
          title: Provider
        model:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Read-only. Each voice provider ships exactly one model and it is
            filled in from `provider`; `GET /v1/tts-capabilities` names which.
          title: Model
        voice_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Which voice, from `GET /v1/voices`. It must be certified for
            `language.default` or the agent is refused on save — a provider
            handed a language it cannot speak fails while the call is being set
            up, before the caller hears anything.
          title: Voice Id
        speed:
          anyOf:
            - maximum: 2
              minimum: 0.5
              type: number
            - type: 'null'
          default: null
          description: Speaking rate. 1.0 is the voice's natural pace.
          title: Speed
        emotion:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Emotional colour: `neutral` `curious` `excited` `enthusiastic`
            `happy` `content` `calm` `confident` `sad` `apologetic`
            `frustrated`. **Cartesia only** — sent for any other provider it is
            refused, because nothing else would speak it.
          title: Emotion
        fallback:
          anyOf:
            - $ref: '#/components/schemas/VoiceFallback'
            - type: 'null'
          default: null
          description: >-
            Backup voice, used for the rest of the call if this one's provider
            stops responding. Send `{"provider": "sarvam", "voice_id": "shubh"}`
            — both are required; the model is filled in. Must be from a
            different provider — one on the main engine's own provider is
            refused. See [Backups](/developers/agents/backups).
      title: Voice
      type: object
    Conversation:
      additionalProperties: false
      properties:
        interruption_sensitivity:
          anyOf:
            - maximum: 1
              minimum: 0
              type: number
            - type: 'null'
          default: null
          description: >-
            How readily the agent stops talking when the caller speaks. 0 =
            never yields, 1 = yields at any sound.
          title: Interruption Sensitivity
        response_eagerness:
          anyOf:
            - enum:
                - 1
                - 0.75
                - 0.5
                - 0
            - type: 'null'
          default: null
          description: >-
            How long the transcriber is given to decide the caller has finished.
            One of four presets, sent as the number it is stored as: `1` Fast,
            `0.75` Responsive, `0.5` Balanced (the default), `0` Patient. Any
            other value is rejected. `GET /v1/transcribers` reports, per speech
            model, how many seconds each preset typically costs.
          title: Response Eagerness
        noise_handling:
          anyOf:
            - $ref: '#/components/schemas/NoiseHandling'
            - type: 'null'
          default: null
          description: How aggressively background noise is filtered out.
        silence_reminder:
          anyOf:
            - $ref: '#/components/schemas/SilenceReminder'
            - type: 'null'
          default: null
          description: A nudge when the caller goes quiet, before the call is given up on.
      title: Conversation
      type: object
    CallSettings:
      additionalProperties: false
      properties:
        max_duration_minutes:
          anyOf:
            - maximum: 30
              minimum: 1
              type: integer
            - type: 'null'
          default: null
          description: Hard cap on call length. The call ends when it is reached.
          title: Max Duration Minutes
        end_on_silence_seconds:
          anyOf:
            - minimum: 1
              type: integer
            - type: 'null'
          default: null
          description: >-
            How long the caller may be silent before the call is ended. 5-120
            seconds; the silence reminder must land before it.
          title: End On Silence Seconds
        recording_enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether the call is recorded. Recordings are read back through `GET
            /v1/calls/{id}/recording`, never a raw storage link.
          title: Recording Enabled
        custom_analysis_enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether the analysis groups in `analysis_group_ids` run after the
            call. Turning it off stops future runs for this agent and **leaves
            the groups attached**, so switching it back on needs no
            re-selection.
          title: Custom Analysis Enabled
        end_on_silence_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: What it says before ending a call the caller went silent on.
        max_duration_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: What it says as `max_duration_minutes` is reached.
      title: CallSettings
      type: object
    Inbound:
      additionalProperties: false
      description: >-
        Lines for calls that arrive and cannot be handled normally.


        `business_hours_closed` is recorded but never spoken today: the platform
        has no business

        hours to compare a call against, so nothing can decide a call arrived
        outside them.
      properties:
        business_hours_closed_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: >-
            Reserved. Stored, and not spoken today — the platform has no
            business-hours schedule to judge a call against.
        fallback_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: What an inbound caller hears when the call cannot be handled.
      title: Inbound
      type: object
    BuiltinTools:
      additionalProperties: false
      properties:
        end_call:
          anyOf:
            - $ref: '#/components/schemas/EndCallTool'
            - type: 'null'
          default: null
          description: Let the agent hang up by itself.
        hold_call:
          anyOf:
            - $ref: '#/components/schemas/HoldCallTool'
            - type: 'null'
          default: null
          description: Let it put the caller on hold.
        transfer_call:
          anyOf:
            - $ref: '#/components/schemas/TransferCallTool'
            - type: 'null'
          default: null
          description: Let it transfer to a human.
        send_whatsapp_template:
          anyOf:
            - $ref: '#/components/schemas/WhatsAppTemplateTool'
            - type: 'null'
          default: null
          description: Let it send a WhatsApp template mid-call.
      title: BuiltinTools
      type: object
    RuntimeVariable:
      additionalProperties: false
      description: >-
        A `{{placeholder}}` the prompt and tools can use.


        Keys found in the prompt are added automatically on save. `callee_name`
        and

        `callee_number` are on every agent; `callee_number` cannot be removed,
        `callee_name` can (a

        campaign with no names drops it so the batch builder stops asking for
        one).
      properties:
        key:
          description: >-
            The placeholder name. Reference it in a prompt or tool as
            `{{custom.key}}`, never bare.
          maxLength: 128
          pattern: ^[A-Za-z_][A-Za-z0-9_]*$
          title: Key
          type: string
        default_value:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: What it resolves to when a call does not supply one.
          title: Default Value
        system_defined:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            **Read-only.** True for the variables every agent has. The platform
            sets it, on a new variable as on an existing one; a value that
            disagrees with what you read is refused. Echoing back the value
            unchanged is fine.
          title: System Defined
        deletable:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            **Read-only.** False for `callee_number`, which is on every agent
            and cannot be removed — sending a list without it does not delete
            it. `callee_name` is system-defined but deletable. The platform sets
            it; a value that disagrees with what you read is refused.
          title: Deletable
      required:
        - key
      title: RuntimeVariable
      type: object
    Memory:
      additionalProperties: false
      description: >-
        What the agent remembers about the people it talks to.


        These SETTINGS are versioned like the prompt. The remembered people are
        keyed to the

        agent and survive every publish and rollback — read and erase them
        through

        `/v1/agents/{id}/memory/*`.
      properties:
        enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: Whether this agent remembers callers between calls at all.
          title: Enabled
        channels:
          anyOf:
            - items:
                enum:
                  - inbound
                  - outbound
                  - whatsapp
                type: string
              type: array
            - type: 'null'
          default: null
          description: Which kinds of conversation contribute to memory.
          title: Channels
        allow_ai_labels:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether the model may invent its own labels for what it remembers,
            beyond the fields you defined.
          title: Allow Ai Labels
        label_instructions:
          anyOf:
            - maxLength: 500
              type: string
            - type: 'null'
          default: null
          description: >-
            Guidance the model reads when inventing labels, if `allow_ai_labels`
            is on.
          title: Label Instructions
        max_facts:
          anyOf:
            - maximum: 1000
              minimum: 10
              type: integer
            - type: 'null'
          default: null
          description: Most facts kept per person. The oldest are dropped past this.
          title: Max Facts
        transcript_turns:
          anyOf:
            - maximum: 30
              minimum: 4
              type: integer
            - type: 'null'
          default: null
          description: How many recent turns are considered when deciding what to remember.
          title: Transcript Turns
        fields:
          anyOf:
            - items:
                $ref: '#/components/schemas/MemoryField'
              type: array
            - type: 'null'
          default: null
          description: >-
            The specific things to remember, each with its own type and
            category. Sending this list replaces the whole set, and a `key`
            declared twice in it is refused. These are the STRUCTURE; the facts
            themselves are written by the model after a call and read through
            the memory endpoints.
          title: Fields
      title: Memory
      type: object
    Numbers:
      additionalProperties: false
      description: >-
        Where the agent answers, and what it dials out from.


        `inbound_phone` and `inbound_whatsapp` are RECORDED on the version and
        applied when it

        is made live — a number written here routes nothing until then, which is
        what lets a

        rollback restore routing along with behaviour.
      properties:
        inbound_phone:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            The phone number this agent answers on. Must be a number `GET
            /v1/numbers` lists for your workspace.
          title: Inbound Phone
        inbound_whatsapp:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            The WhatsApp number it answers on, from `GET /v1/whatsapp/numbers`.
            Any spelling of it is accepted and read back in E.164, e.g.
            `+15513745854`. Recorded on this version; it starts answering when
            the version is made live.
          title: Inbound Whatsapp
        default_outbound:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            The number outbound calls are placed from when `POST /v1/calls`
            omits `from_number`.
          title: Default Outbound
      title: Numbers
      type: object
    ValidationError:
      type: object
      title: ValidationError
      required:
        - field
        - message
        - type
      properties:
        field:
          type: string
          description: >-
            The offending field as a path from the root of your request —
            `voice.speed`, `variables[0].key`, or `query.limit` for a query
            parameter. **This is the field to read.**
        message:
          type: string
          description: What is wrong with it, in plain language.
        type:
          type: string
          description: >-
            A stable machine code for the kind of failure, e.g.
            `extra_forbidden` for a field we do not accept, `missing` for a
            required one, or `less_than_equal` for a number out of range. Switch
            on this rather than on `message`, which may be reworded.
    TranscriberFallback:
      additionalProperties: false
      description: >-
        A backup speech model on a DIFFERENT provider, used for the rest of the
        call if the

        main one stops responding.


        Name the model; the provider comes with it. A backup on the main model's
        own provider is

        refused: what fails is almost never one model — the vendor is
        unreachable, the key is

        rejected, the region is down — and every model behind that provider
        fails with it.
      properties:
        provider:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Read-only. Derived from `model` — each speech model belongs to one
            provider, so a value sent here is ignored.
          title: Provider
        model:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Model id, from `GET /v1/transcribers`. A model not listed there is
            refused.
          title: Model
      title: TranscriberFallback
      type: object
    ModelFallback:
      additionalProperties: false
      description: >-
        A backup model on a DIFFERENT provider, used for the rest of the call if
        the main

        model's provider stops responding.


        Name the model; the provider comes with it. A backup on the main model's
        own provider is

        refused: what fails is almost never one model — the vendor is
        unreachable, the key is

        rejected, the region is down — and every model behind that provider
        fails with it.
      properties:
        provider:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Read-only. Derived from `model` — the catalogue decides routing, so
            a value sent here is ignored.
          title: Provider
        model:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Model id, from `GET /v1/models`. It must be on a different provider
            than the main model — one on the same provider is refused, because
            an outage takes every model behind that provider down together.
          title: Model
      title: ModelFallback
      type: object
    VoiceFallback:
      additionalProperties: false
      description: >-
        A backup voice on a DIFFERENT provider, used for the rest of the call if
        the main

        voice's provider stops responding. Name both the provider and one of its
        voices.
      properties:
        provider:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Required. The provider to fall back to, from `GET
            /v1/tts-capabilities`. A voice id alone does not say whose voice it
            is.
          title: Provider
        model:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: The provider's model. Filled in when the provider has only one.
          title: Model
        voice_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: Required. The voice to use there, from `GET /v1/voices?provider=`.
          title: Voice Id
      title: VoiceFallback
      type: object
    NoiseHandling:
      additionalProperties: false
      description: '`level` is derived from `mode` when omitted (0 / 50 / 75 / 90).'
      properties:
        mode:
          anyOf:
            - enum:
                - 'off'
                - standard
                - high
                - background_voice
              type: string
            - type: 'null'
          default: null
          description: >-
            How aggressively to filter background noise. `background_voice` is
            for a caller with other people talking nearby.
          title: Mode
        level:
          anyOf:
            - maximum: 100
              minimum: 0
              type: integer
            - type: 'null'
          default: null
          description: >-
            Filter strength 0-100. Derived from `mode` when omitted: off 0,
            standard 50, high 75, background_voice 90.
          title: Level
      title: NoiseHandling
      type: object
    SilenceReminder:
      additionalProperties: false
      description: >-
        `seconds` must be less than `call.end_on_silence_seconds` — a reminder
        that fires

        after the call has already ended is not a reminder.
      properties:
        enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: Whether the agent nudges a silent caller.
          title: Enabled
        message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: >-
            What it says when it nudges. `default` generates the line per call;
            `custom` says `text` verbatim.
        seconds:
          anyOf:
            - minimum: 1
              type: integer
            - type: 'null'
          default: null
          description: >-
            How long the caller may be silent before the agent nudges them.
            3-119 seconds, and it must be less than
            `call.end_on_silence_seconds` — a reminder after the call has ended
            is nothing.
          title: Seconds
      title: SilenceReminder
      type: object
    SystemMessage:
      additionalProperties: false
      description: >-
        One platform-spoken line.


        `default` generates it per call from `prompt`, in the language being
        spoken; `custom`

        says `text` verbatim. A `default` entry needs a non-blank `prompt` — a
        message with

        nothing steering it means the agent goes quiet for no reason anyone
        stated.
      properties:
        mode:
          anyOf:
            - enum:
                - default
                - custom
              type: string
            - type: 'null'
          default: null
          description: >-
            `default` generates the line per call from `prompt`, in the language
            being spoken; `custom` says `text` verbatim.
          title: Mode
        prompt:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            The instruction used to generate the line, for `default` mode.
            Required and non-blank when `mode` is `default`.
          title: Prompt
        text:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: The exact words, for `custom` mode.
          title: Text
      title: SystemMessage
      type: object
    EndCallTool:
      additionalProperties: false
      properties:
        enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether the agent may hang up by itself. Still has to be armed with
            `<end_call>` in the prompt.
          title: Enabled
        message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: The goodbye it says before hanging up.
      title: EndCallTool
      type: object
    HoldCallTool:
      additionalProperties: false
      properties:
        enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether the agent may put the caller on hold. Armed with
            `<hold_call>` in the prompt.
          title: Enabled
        max_seconds:
          anyOf:
            - maximum: 600
              minimum: 10
              type: integer
            - type: 'null'
          default: null
          description: >-
            Longest a single hold may last before the agent must come back. The
            call ends politely if the caller is not back by then.
          title: Max Seconds
        follow_up_seconds:
          anyOf:
            - minimum: 1
              type: integer
            - type: 'null'
          default: null
          description: >-
            When the agent checks back in while holding. Must be less than
            `max_seconds` — a check-in after the hold has ended is silence — and
            the pair is refused if it is not, whichever half you send.
          title: Follow Up Seconds
        acknowledgement_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: >-
            What it says the moment the caller asks for a moment, before it goes
            quiet.
        follow_up_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: The check-in spoken at `follow_up_seconds`.
        timeout_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: What it says when `max_seconds` runs out and the hold ends.
      title: HoldCallTool
      type: object
    TransferCallTool:
      additionalProperties: false
      properties:
        enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether the agent may transfer the call. Armed with
            `<transfer_call>` in the prompt.
          title: Enabled
        numbers:
          anyOf:
            - items:
                $ref: '#/components/schemas/TransferNumber'
              type: array
            - type: 'null'
          default: null
          description: >-
            Where it may transfer to, in priority order. Sending this list
            replaces the whole set.
          title: Numbers
        intro_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: What it says to the caller as it hands the call over.
        busy_message:
          anyOf:
            - $ref: '#/components/schemas/SystemMessage'
            - type: 'null'
          default: null
          description: What it says when no destination is free.
      title: TransferCallTool
      type: object
    WhatsAppTemplateTool:
      additionalProperties: false
      description: >-
        Off by default, and opt-in: every send spends a template and reaches a
        real person.


        `allowed_templates` is a security boundary — the agent can only send a
        template named here. Add the templates themselves in your Vocily
        workspace first.
      properties:
        enabled:
          anyOf:
            - type: boolean
            - type: 'null'
          default: null
          description: >-
            Whether the agent may send a WhatsApp template. Armed with
            `<send_whatsapp_template>` in the prompt.
          title: Enabled
        allowed_templates:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          description: >-
            **A security boundary, not a convenience**: the model can only send
            a template named here.
          title: Allowed Templates
        phone_number_id:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            Which WhatsApp sender it goes out from — a `phone_number_id` from
            `GET /v1/whatsapp/numbers`. One this workspace has not connected is
            refused.
          title: Phone Number Id
      title: WhatsAppTemplateTool
      type: object
    MemoryField:
      additionalProperties: false
      description: >-
        One structured thing to remember about a caller. `description` is the
        extractor's

        instruction and goes into the prompt verbatim — it is not a tooltip.
      properties:
        key:
          description: Machine name for this fact, used when reading memory back.
          maxLength: 64
          pattern: ^[a-z][a-z0-9_]*$
          title: Key
          type: string
        label:
          description: A human-readable name for this field.
          maxLength: 120
          title: Label
          type: string
        type:
          default: string
          description: The JSON type this fact is stored as.
          enum:
            - string
            - number
            - integer
            - boolean
            - array
          title: Type
          type: string
        enum_values:
          anyOf:
            - items:
                type: string
              type: array
            - type: 'null'
          default: null
          description: >-
            The allowed values, when the fact is one of a fixed set. `string`
            fields only — the extractor ignores a list on any other type, so one
            sent there is refused.
          title: Enum Values
        description:
          description: >-
            The instruction the model reads when deciding what to record here. A
            direction, not a label.
          title: Description
          type: string
        category:
          default: context
          description: How this field is grouped when the agent's memory is shown.
          enum:
            - identity
            - contact
            - preference
            - account
            - context
          title: Category
          type: string
      required:
        - key
        - label
        - description
      title: MemoryField
      type: object
    TransferNumber:
      additionalProperties: false
      description: >-
        A human to hand the call to. `start_hour`/`end_hour` null = always
        available.
      properties:
        number:
          description: Destination in E.164, e.g. `+919876543210`.
          title: Number
          type: string
        priority:
          default: 0
          description: Order to try. Lower is tried first.
          title: Priority
          type: integer
        start_hour:
          anyOf:
            - maximum: 23
              minimum: 0
              type: integer
            - type: 'null'
          default: null
          description: >-
            Earliest hour of the day this destination accepts transfers, 0-23 in
            its own `timezone`.
          title: Start Hour
        end_hour:
          anyOf:
            - maximum: 23
              minimum: 0
              type: integer
            - type: 'null'
          default: null
          description: Latest hour, 0-23 in its own `timezone`.
          title: End Hour
        timezone:
          anyOf:
            - type: string
            - type: 'null'
          default: null
          description: >-
            IANA zone the hours are read in, e.g. `Asia/Kolkata`. A name that is
            not one is refused: at call time an unknown zone would make this
            destination look always-available, silently ignoring the hours
            above.
          title: Timezone
      required:
        - number
      title: TransferNumber
      type: object
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: 'Your API key as a Bearer token, e.g. `Authorization: Bearer vk_…`.'

````