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

# Create an agent

> Creates a new AI agent. Provide as much of the structured shape as you can in one call — a fully-formed agent at creation time has dramatically better runtime behavior than a thin agent that gets configured incrementally. A high-quality agent typically includes: (1) identity (name, company_name, role, language); (2) prompt fields that shape the runtime AI (objective, tone, behavior_guidelines, negative_response, length_detail); (3) the relevant settings block (settings.voice for phone agents, settings.text for messaging agents) populated with at minimum the interaction first/end messages and voice_profile or working_hours; (4) reference knowledge (notes, training Q&A pairs); (5) operational rules (guidelines for short do/don'ts, procedures for multi-step workflows); (6) capabilities the agent should perform (appointments + schedule_assignments with name/description filled, routing_rules with ai_prompt + phrases for IVR, guard_rules with when_condition + example_phrases for compliance escalations). Skipping prompt/description fields produces hollow agents that respond generically and ignore the operational rules at runtime — see each sub-schema's description for the AI-prompt fields that must not be left empty.



## OpenAPI

````yaml https://app.mihu.ai/docs/api-docs.json post /api/v1/agents
openapi: 3.0.0
info:
  title: Mihu API Documentation
  description: >-
    Welcome to Mihu API Documentation for developers.Here you can find all the
    information about the API endpoints and how to use them.If you have any
    questions or need help, please contact us at support@mihu.ai
  version: 1.0.0
servers:
  - url: https://{subdomain}.mihu.ai
    description: Your subdomain
    variables:
      subdomain:
        default: demo
        description: Subdomain name
  - url: /docs
security: []
tags:
  - name: Agents
    description: >-
      Manage AI agents, settings, knowledge sections, rules, appointments, and
      channel provisioning
  - name: Contact Analyzers
    description: >-
      Configure what information should be extracted from conversations and how
      extracted values should update contacts, custom contact fields, or
      pipeline stages. Analyzer IDs use prefixes: `b_` means a built-in contact
      field, `f_` means a custom contact field, and `p_` means a pipeline stage
      rule.
  - name: Appointments
    description: Appointment management endpoints
  - name: Appointment Requests
    description: Appointment request endpoints
  - name: Assistant Channels
    description: >-
      Configure how a tenant user's Mihu Assistant is reached from outside the
      app — assign an inbox/WhatsApp number, set 'Your email'/'Your number', and
      optional PIN-based 2FA. This API is tenant-token authenticated but the
      resources it manages are per-user, so every request identifies the target
      user by their login email.
  - name: Availability Types
    description: Availability type endpoints
  - name: Builders
    description: >-
      Build and run apps on isolated cloud sandboxes (mihu Builders). Two ways
      in:


      **1. Describe it (Builder Agent):** POST /api/v1/builder-agents with a
      one-sentence prompt. The agent replies with questions (credentials, size,
      schedule); answer until it generates the code and deploys a running app
      with a public URL.


      **2. Ship your own code (Builders):** POST /api/v1/builders with your
      files + entrypoint. Returns a running app on a public HTTPS URL.


      ---


      **Which endpoint to call, by conversation `status` (the build-agent flow
      is async — always poll after a write):**


      | You have… | Call | Then |

      |---|---|---|

      | nothing yet | `POST /builder-agents` (prompt) | poll the conversation |

      | `status: processing` | nothing — it's working | keep polling `GET
      /builder-agents/{uuid}` (~2-3s) |

      | `status: gathering` (questions) | `POST /builder-agents/{uuid}/answers`
      | poll again |

      | `status: deployed` and want changes | `POST
      /builder-agents/{uuid}/rebuild` | poll again |

      | `status: deployed`, happy with it | operate it via
      `/api/v1/builders/{uuid}` (start/stop/logs/exec/files) | — |

      | `status: failed` | `POST /builder-agents/{uuid}/rebuild` with a fix, or
      start a new conversation | poll again |


      Rule of thumb: **write → then poll `GET /builder-agents/{uuid}` until
      status leaves `processing`.** Use `/answers` only while `gathering`; use
      `/rebuild` once `deployed`/`failed`.


      Once running, a builder exposes lifecycle controls (start/stop/auto-stop),
      live logs, a command terminal (exec), and direct file access. A preview
      URL only resolves while the builder is running.


      ---


      ### Connect via the standalone Builder MCP server


      Besides this REST API, the builder can be driven from your own AI client
      over the Model Context Protocol. The Builder MCP server lets a customer
      **build their own business integrations and apps** — CRMs, connectors,
      data migrations, webhooks, automation agents — by describing them in plain
      language from Claude Desktop, Claude Code, or Cursor. It is the
      integration and app builder for the customer, delivered over MCP. Each
      connection is bound to one tenant and scoped to it; no other tenant is
      reachable.


      **Get your connection details.** You get everything you need from the app:
      go to the **Builders** page and open the **Credentials** tab — the
      **Builder connection** panel there shows your three values. Server (for
      example https://builder.mihu.ai), Tenant (your workspace's builder tenant
      name), and Token (masked by default — click the eye icon there to reveal
      and copy it; it is your tenant key). Everything below comes from that
      panel.


      **Run the server (stdio).** Install with `pip install mcp`, then run it
      with your three values as environment variables: `MIHU_API_URL=Server
      MIHU_TENANT=Tenant MIHU_TENANT_KEY=Token python mcp_server.py`.


      **Register it with your MCP client.** In Claude Desktop's config, add an
      MCP server named mihu-builder whose command is `python`, whose argument is
      the path to `mcp_server.py`, and whose env sets MIHU_API_URL, MIHU_TENANT
      and MIHU_TENANT_KEY to your three values. In Claude Code, use `claude mcp
      add` with the same three env vars and the script path.


      **Tools the client gets:** create_agent, answer_agent, approve_agent,
      get_agent, list_agents, deploy_code, list_deployments, review_deployment,
      test_deployment, get_qa_report, get_logs, exec_command, start, stop,
      set_auto_stop, get_spending, store_credentials, and more.


      **Build flow (asynchronous — poll after each write):** create_agent, then
      poll get_agent; while gathering, call answer_agent and poll; when
      awaiting_approval, call approve_agent and poll; once deployed it is live
      with a preview URL. Keep your token secret — it authorizes everything for
      your tenant; rotate it from the Credentials tab if it leaks.
  - name: Call Actions
    description: >-
      Real-time control actions for an active call: say, forward, hangup, mute,
      and unmute. Each action targets a live call by its conversation UUID,
      returned as `conversation_uuid` from POST /api/v1/call. Requires a bearer
      token and a live (non-ended) call.
  - name: Campaigns
    description: Campaign management endpoints
  - name: Coaching Agents
    description: >-
      Coaching Agents turn evaluation results into coaching feedback for your
      agents — what went well, what to improve, and which resources to study.
      Each coaching agent is identified by its `uuid`.


      Quick start:

      1. `POST /api/v1/coaching-agents` with a name — you get a ready-to-use
      coaching agent with sample templates and a training example.

      2. Tune the style: `coaching_tone` (supportive, direct, constructive,
      motivational, or your own wording), `auto_trigger_threshold` (coach when
      the score drops below this %), and content options.

      3. Make it the active coach with `POST
      /api/v1/coaching-agents/{uuid}/set-default`.


      Good to know:

      - One coaching agent is always the default; the first one you create
      becomes the default automatically.

      - Train the AI on your style with `training_examples` (an issue + your
      ideal coaching response) — 5-10 diverse examples work best.

      - Feedback is written in the `language` you set, e.g. "English".


      Recipe — recommend a resource when something is missing from the
      conversation:

      1. Add the resource to `resource_library` with matching `topics`, e.g.
      `{"title": "Pricing Conversation Tutorial", "type": "video", "url":
      "https://example.com/pricing-video", "topics": "pricing, price objections,
      sales"}`.

      2. Add the trigger rule to `general_guidelines`, e.g. "If the price was
      not mentioned during the conversation, point this out, explain why
      discussing price matters, and recommend the pricing video from the
      resource library.".

      3. Keep `include_resources` on. The coaching feedback will now flag the
      gap and link the resource.
  - name: Contacts
    description: Contact management endpoints
  - name: Contact Approvals
    description: >-
      Manage AI-suggested contact field updates pending human review. Each
      approval is identified by its `uuid`.
  - name: Contact Fields
    description: >-
      Manage custom contact fields for your account. Each field is identified by
      its `key` (unique and immutable once created).
  - name: Contact Settings
    description: >-
      Toggle contact-list display preferences such as masking phone numbers or
      email addresses. Each setting is identified by its `key`.
  - name: Conversations
    description: Conversation management endpoints
  - name: Sessions
    description: Conversation session endpoints
  - name: Tables
    description: >-
      Tables are user-defined datasets that AI agents use as a knowledge base
      (semantic search over text) or as a real-time lookup (structured rows the
      agent queries during conversations).


      **When to create a table.** Create one whenever an agent needs to ground
      its answers in your data: product catalog, FAQ, pricing list, internal
      policies, customer records, business rules, etc. One table = one dataset
      on one topic.


      **How to create + populate.** Pick one of:

      - `POST /api/v1/data/tables` — create an empty table with a typed column
      schema (text/number/date/boolean/json/url). Use this when you have
      structured data and want to add rows yourself via the records endpoints.

      - `POST /api/v1/data/import/copypaste` — paste raw text. Best for FAQs,
      policy docs, or any unstructured knowledge content.

      - `POST /api/v1/data/import/file` — upload CSV/Excel/JSON/PDF/XML/audio.
      Best for spreadsheets, documents, transcripts.

      - `POST /api/v1/data/import/website` — crawl a URL. Best for public
      knowledge bases, marketing sites.


      **Records.** Once a table exists, add/update/delete rows via
      `POST|PUT|DELETE /api/v1/data/{uuid}/records[/{record}]`. Inspect the
      schema with `GET /api/v1/data/{uuid}/fields`.


      **Connecting to an agent.** Call `POST /api/v1/data/{uuid}/assign` to make
      a table available to an agent. After bulk changes, call `POST
      /api/v1/data/{uuid}/sync` to refresh the agent's index.


      **Lifecycle.** create → populate (records or import) → assign to agent →
      agent uses it at runtime → update/sync as data changes → delete when no
      longer needed.
  - name: Logs
    description: >-
      Read-only audit feeds covering three kinds of activity. **Actions** is a
      chronological stream of every task, workflow run, and AI action taken
      during a call — what your agents actually did, when, and how long it took.
      **API** records inbound requests made against this tenant's API (method,
      path, status, calling token, request/response bodies) — useful for
      debugging integrations and auditing access. **Webhooks** records outbound
      webhook deliveries sent to your registered endpoints (event, destination,
      status, payload, headers, response). Across all three, tokens, passwords,
      signatures and other secrets are masked before being returned.
  - name: Email Addresses
    description: >-
      Manage the mihu email addresses agents send and receive from. Create an
      address on the shared sending domain (instant) or connect your own domain
      (DNS or single-email verification), assign or unassign the handling agent,
      enable or disable an address, and check domain verification status.
  - name: Email Messages
    description: >-
      Send email through the mihu Connect channel: start a new email from one of
      your addresses, reply within an existing email conversation, or forward a
      conversation to a third party. Inbound email is received automatically and
      surfaced as conversations.
  - name: Evaluate
    description: >-
      Per-agent and global settings that control how conversations are
      sessionized and analyzed.


      WHAT EVALUATION DOES:

      At runtime, every conversation is grouped into 'sessions' (continuous
      bursts of messages). When a session ends — either because the customer
      goes idle for sessionization.timeout_minutes, or the conversation closes —
      the runtime fires SessionSummaryService and runs each enabled analyzer
      feature against the full session transcript. Outputs are persisted as
      'evaluation' records.


      WHEN IT RUNS:

      - Voice calls and WhatsApp Call: at end of call (or after silence_timeout)

      - SMS, WhatsApp text, Instagram, FB Messenger: when the session creator
      job (SmsSessionCreatorJob / WhatsappSessionCreatorJob / equivalents)
      closes the session

      - Triggered automatically; not on demand


      WHICH CHANNEL'S CONFIG RUNS:

      - text.* features run for sessions on text channels (SMS, WhatsApp text,
      Instagram, FB Messenger, chat)

      - voice.* features run for sessions on voice channels (phone calls,
      WhatsApp Call)

      - Both blocks live on the same settings row; only the relevant one fires
      per session


      WHAT THE FEATURES PRODUCE:

      Each enabled feature emits a classification (one label per session, per
      feature) using its 'description' field as the LLM prompt.
      success_evaluation_prompt is special: it returns true/false based on the
      'prompt' field — leave 'prompt' empty and the result is meaningless.
      summary_prompt is consumed by SessionSummaryService to produce the
      human-readable session summary in report_language.


      WHERE TO READ RESULTS:

      - GET /api/v1/sessions/{uuid}/evaluation — single session result

      - GET /api/v1/evaluations — list, filterable

      - GET /api/v1/analytics/evaluations — aggregated dashboard data


      COST CONSIDERATIONS:

      Each enabled feature is one extra LLM call per session. Disable features
      you don't read. is_active=false disables every analyzer for that agent
      (and skips the summary).


      WORKFLOW:

      1. GET /default to see the workspace-wide config every agent inherits

      2. POST /agents/{uuid}/evaluate/assign to give one agent its own override

      3. PUT /agents/{uuid}/evaluate (or /default) for partial updates

      4. DELETE /agents/{uuid}/evaluate to revert that agent to the default
  - name: Language
    description: Languages available for agent configuration.
  - name: Listings
    description: Listing management endpoints
  - name: Memorize
    description: >-
      Manage what your agents remember from contacts and conversations. There is
      one global default; each agent can optionally override it with its own
      settings.
  - name: Call
    description: Voice call endpoints
  - name: WhatsApp
    description: WhatsApp messaging endpoints
  - name: WhatsApp Calling
    description: WhatsApp voice call endpoints
  - name: SMS
    description: SMS messaging endpoints
  - name: Evaluations
    description: >-
      Evaluations are AI-generated analysis records for conversation sessions.
      Use these endpoints to list or retrieve scores, labels, reasons, and
      linked conversation/contact identifiers for quality review and reporting.
  - name: Schedules
    description: >-
      Schedules are bookable calendars used by agents and appointment flows. A
      schedule links to an availability type, stores assignment metadata, and
      can include custom questions for appointment collection.
  - name: Tasks
    description: >-
      Tasks are scheduled units of work for agents, such as outbound calls and
      WhatsApp template messages. Use task endpoints when you need to inspect
      campaign-generated work, create one-off outreach, queue a task, cancel it,
      or retry a failed attempt.
  - name: Transcriptions
    description: >-
      Transcriptions turn audio files or audio URLs into conversation text,
      session records, and optional AI evaluations. Use these endpoints to
      submit recorded calls, receive asynchronous completion webhooks, fetch
      transcription status, and retrieve the final transcript with analysis.
  - name: Analytics
    description: >-
      Aggregated analytics across calls, conversations, sessions, evaluations,
      intents, appointments, and messages
  - name: Flows
    description: >-
      Studio automation flows — list, create, read, update, delete. A flow is a
      trigger step + N action steps that fire on real events (e.g. inbound call
      → post to Slack → create CRM contact). Flows live in draft until POST
      /deploy makes them live.
  - name: Flow Steps
    description: >-
      Add / update / delete steps inside a flow. The first step is always a
      trigger; subsequent steps are actions. Step IDs and their ordering
      (`step_number`) are managed by the server — adding or deleting a step
      automatically renumbers and rewrites `{{stepN.field}}` references in
      downstream steps.
  - name: Flow Catalog
    description: >-
      Read-only discovery of integrations and their capabilities. Lists apps,
      triggers, actions, OAuth connections, agents, and dynamic field options.
      The MCP server uses this to translate natural language ("post to Slack
      #general") into the IDs/keys the action config requires.
  - name: Flow Executions
    description: >-
      Execution history for a deployed flow — every real trigger event that
      fires produces one execution row with per-step
      request/response/duration/status.
  - name: Voice IVR & Guards
    description: >-
      Two related but distinct features that decide when an agent transfers a
      call or ends a conversation.


      WHAT THEY ARE:

      - ROUTING RULES (Voice-Activated IVR): customer-intent-driven transfers.
      When the customer ASKS for something (sales, support, manager), routing
      rules pick the right destination. This is the IVR replacement.

      - GUARD RULES (Guard & Hand Over): situation-driven transfers or
      call-ends. When the runtime detects a sensitive SITUATION (legal
      complaint, profanity, compliance violation, customer in distress), the
      guard fires regardless of what the customer asked for.


      WHEN TO USE WHICH:

      - Customer says 'I want to speak to a manager' -> ROUTING rule (intent:
      customer wants escalation).

      - Customer threatens legal action -> GUARD rule (situation:
      compliance/safety overrides whatever the customer was asking).

      - Customer asks for technical support -> ROUTING rule.

      - Customer becomes abusive -> GUARD rule (then_action: end_conversation or
      forward).

      - Rule of thumb: routing = 'where do they want to go?', guard = 'this
      conversation needs to stop or hand off NOW'.


      PRIORITY AND ORDERING:

      - Routing rules have a numeric `priority` field. Lower number = higher
      priority = evaluated first. Ties resolved by insertion order.

      - Guard rules ALWAYS take precedence over routing rules. If a guard fires,
      routing is bypassed.

      - If multiple guards could fire on the same utterance, only the first
      match wins.


      DETECTION MECHANICS (routing only):

      - detection_mode = exact: the customer must say `trigger_keyword`
      literally. Fast, narrow, language-sensitive.

      - detection_mode = intent: the runtime AI uses `ai_prompt` + `phrases` to
      classify intent semantically. Broader, multilingual, requires good
      ai_prompt wording.

      - detection_mode = both: runs exact first, falls back to intent.
      Recommended for production.


      REQUIRED FIELDS FOR THE AI TO PICK THE RULE:

      - Routing intent/both: `ai_prompt` + `phrases` (3-5 examples).

      - Routing exact: `trigger_keyword`.

      - Guard: `when_condition` + `example_phrases`.

      Without these, the runtime cannot classify utterances and the rule never
      fires.


      CRUD MODES:

      - PUT  /agents/{uuid}/routing-rules  or  /guard-rules  — REPLACE all rules
      in one call. Old rules are deleted first. Use for bulk imports or full
      re-syncs.

      - POST /agents/{uuid}/routing-rules  or  /guard-rules  — ADD one rule,
      leave others intact. Returns 201. Use for incremental builds.

      - PATCH /...{ruleUuid}  — partial UPDATE of one rule. Only sent keys are
      touched.

      - DELETE /...{ruleUuid} — remove one rule.

      Per-rule POST/PATCH/DELETE preserve other rules; PUT replaces everything.
  - name: PBX Extension Connectors
    description: >-
      Voice PBX & Extension Connectors — register a PBX extension against an AI
      voice agent. This is the PBX-side configuration only; it does not
      provision a SIP trunk. Use it when you want to connect a number you've
      purchased from us into your existing PBX extension. If you already have a
      SIP trunk from a provider, use the SIP Trunking endpoints directly
      instead.
  - name: Phone Numbers
    description: Manage phone number inventory, channel bindings, search, and rates
  - name: Contact Pipeline
    description: >-
      Pipeline stages classify where a contact is in your sales, support, or
      onboarding process. Use these endpoints to define the ordered stage list,
      move contacts between stages through contact updates, and keep inactive
      stages out of normal selection while preserving history.
  - name: Pools
    description: >-
      Contact pools — named buckets of contacts that one or more campaigns draw
      from. A pool's `type` (FIFO / LIFO / Parallel) controls dispatch order
      when a campaign is running.


      **Typical workflow (build a pool from scratch):**

      1. POST /api/v1/contacts — create the contacts you want to reach (or use
      existing UUIDs)

      2. POST /api/v1/pools — create a pool

      3. POST /api/v1/pools/{uuid}/contacts — bulk-add contacts by UUID

      4. (attach to campaign — see Campaigns tag)


      **Inspect / manage:**

      - GET /api/v1/pools/{uuid}/contacts — paginated list of pool members with
      status, retries, started_at

      - DELETE /api/v1/pools/{uuid}/contacts/{contact_uuid} — remove one contact
      and cancel only THAT contact's pending tasks (not their tasks in other
      pools)

      - POST /api/v1/pools/{uuid}/duplicate — clone pool config, optionally with
      all members


      **Side effect on a running campaign:** if you POST /pools/{uuid}/contacts
      to a pool already attached to an In Process campaign, tasks are
      auto-created for the new contacts in EVERY running campaign attached to
      that pool. Same call works for draft campaigns too — it just doesn't
      create tasks until publish.


      **Delete guard:** DELETE /api/v1/pools/{uuid} returns 409 if the pool is
      attached to a campaign in In Process or Importing status. Stop or detach
      first.
  - name: QA Agents
    description: >-
      QA Agents score your conversations against a weighted skill scorecard and
      produce evaluation reports and coaching feedback. Each QA agent is
      identified by its `uuid`.


      Quick start:

      1. `POST /api/v1/qa-agents` with a name — you get a ready-to-use scorecard
      (Greeting 15%, Empathy 20%, Compliance 25%, Resolution 25%, Sales 15%).

      2. Adjust the scorecard with `PUT /api/v1/qa-agents/{uuid}/skills` —
      weights must always total 100%.

      3. Make it the active evaluator with `POST
      /api/v1/qa-agents/{uuid}/set-default`.


      Good to know:

      - One QA agent is always the default; it evaluates sessions when no
      specific QA agent is chosen. The first one you create becomes the default
      automatically.

      - `evaluates_agent_type` controls who gets evaluated: `human` agents, `ai`
      agents, or `both`.

      - Reports are written in the `language` you set, e.g. "English".
  - name: Rules
    description: >-
      Campaign contact rules — call cadence, retry intervals, working-hours
      window, and escalation policy. A rule defines HOW often and WHEN a
      campaign reaches a contact; the campaign defines WHO and WHAT.


      **Typical workflow:**

      1. POST /api/v1/rules — create a rule (call or text type)

      2. POST /api/v1/campaigns — create a campaign in Draft status

      3. PUT /api/v1/campaigns/{uuid}/rule — attach the rule (replaces any prior
      rule)

      4. (continue with pool attachment + publish — see Campaigns tag)


      **Type-aware behavior:**

      - type='call' rules honor retry_interval_minutes and end_time
      (working-hours window).

      - type='text' rules force one-shot semantics: max_total_calls=1,
      retry/end_time nulled. Used for SMS and WhatsApp campaigns.


      **Caveat:** changing a rule on a campaign that's already In Process does
      NOT rebuild already-scheduled tasks. New tasks created after the change
      pick up new values; old ones keep the old cadence. To force a hard reset:
      stop campaign → assign new rule → publish again.
  - name: Simulations
    description: >-
      Simulation Studio — test an AI assistant against realistic AI customers
      before it goes live, and get a scored report with a full transcript per
      conversation.
       *
       * **What a simulation is.** One simulation = one assistant under test, on one channel, with a set of customer personas and test cases. A test case has a `title`, a `scenario` (what the simulated customer tries to do), an `expected` outcome, and `criteria` — short, objectively checkable statements the judge verifies from the transcript alone (e.g. 'Confirms date & time', 'Offers escalation', 'Keeps replies under 30 words'). Running the simulation executes `runs_per_case` conversations per test case; each conversation pairs one persona with the assistant, up to `max_turns` customer turns.
       *
       * **How faithful it is.** The assistant answers with its own production brain: its prompt, training rules, knowledge base, and its own configured model. With `with_intents=true` it also uses its real intent/appointment/guard tools — detected intents EXECUTE their events for real (webhooks and connected flows actually fire), so enable it deliberately.
       *
       * **Channels.** `voice`, `sms`, `whatsapp`, `whatsapp_call`, `email` (same set as Start Conversation). Text channels always run simulated (LLM ↔ LLM using the channel-appropriate prompt; nothing is sent externally, no real contacts touched). `voice` and `whatsapp_call` additionally support `call_mode=real`: the `caller_agent_uuid` agent's line (SIP trunk for voice, WhatsApp calling line for whatsapp_call — see `whatsapp_call_lines` in /options) places a REAL call to the assistant's number with its prompt fully overwritten by the persona — two live voice agents talk over real telephony, the assistant is exercised on its production inbound path, and the run carries a `record_url` recording.
       *
       * **State machine.** `draft → queued → running → passed | failed`. `passed` means the average judge score reached `pass_threshold`. A stopped simulation keeps results of finished conversations, or returns to `draft` if none finished. Stuck runs self-heal within minutes.
       *
       * **Billing.** Every assistant message in a simulated conversation is billed at the plan's text-message rate (see `message_rate` in /options; ceiling per run = test_cases × runs_per_case × max_turns × rate). Charges appear in the wallet transaction history as 'Simulation …'. An empty wallet blocks new runs. Real calls are billed as calls, not messages.
       *
       * **Which endpoint to call, by where you are:**
       *
       * | You have / want | Call | Then |
       * |---|---|---|
       * | nothing yet | `GET /simulations/options` | pick channel + assistant (+ caller line for real calls) |
       * | want AI-written config | `POST /simulations/generate-test-cases`, then optionally `/generate-personas` | edit the drafts, pass them into create |
       * | a config | `POST /simulations` (add `run:true` to start immediately) | poll |
       * | `state: queued/running` | `GET /simulations/{uuid}` (~3-5s) — run summaries update live; a run's transcript grows under `/runs/{runUuid}` | keep polling until `passed`/`failed` |
       * | want to abort | `POST /simulations/{uuid}/stop` | finished conversations keep their scores |
       * | `state: passed/failed` | `GET /simulations/{uuid}/report` | drill into `/runs/{runUuid}` for transcripts |
       * | want changes | `PUT /simulations/{uuid}` (409 while running), then `/run` again | previous spend stays in `billed_total` |
       * | a FAILED report, want auto-fix | `POST /simulations/{uuid}/optimize` | poll; then accept/reject the proposed field changes |
       *
       * **Self-improvement (optional).** On a finished report, `POST /{uuid}/optimize` proposes changes to the agent's STRUCTURED FIELDS (role, objective, tone, length, fallback response, company context) plus new Response Guidelines, Notes and Training Data — NOT a raw prompt. It returns a 'proposed' entry in `data.optimizations[]` with a plain-language `summary`, a `changes` object (`{fields:{col:newValue}, guidelines_add:[], notes_add:[], training_add:[]}`), and `before_score` — nothing is tested or applied yet. Then choose: `POST /{uuid}/optimize/accept {attempt_id}` to apply it, or `POST /{uuid}/optimize/trial {attempt_id}` to re-run the simulation with it first (poll `GET /{uuid}` — the attempt becomes 'ready' with `after_score`). Both accept and trial take an OPTIONAL `changes` body — pass an edited/trimmed version of the proposed `changes` to apply or test only what you want (drop a field key or a list item to skip it). Accept writes those fields to the agent, regenerates its prompt (via the same builder the Skills editor uses) and clears any custom_prompt override; `POST /{uuid}/optimize/revert` restores the changed fields. The live assistant is untouched until accept.
       *
       * **Attempt status lifecycle** (`data.optimizations[].status`): `proposed` → (`running` → `ready`, only if you trial it) → `accepted` | `rejected` | `reverted`. Only one attempt can be pending (`proposed`/`running`/`ready`) at a time; a second `optimize` returns 409 while one is pending. 409 reasons on these endpoints: no report yet, an attempt already pending, an empty change set, an empty wallet (trial), or (revert) the agent's prompt changed since it was applied.
       *
       * **Self-improvement worked example** (apply only some of the proposed changes):
       * 1. `POST /{uuid}/optimize` → `{ attempt_id }`.
       * 2. `GET /{uuid}` → find the `data.optimizations[]` entry with `status: proposed`; read its `changes`, e.g. `{ fields: { tone: Concise and factual, negative_response: … }, guidelines_add: [On SMS confirm the email by reading it back in full — never letter by letter], notes_add: [], training_add: [] }`.
       * 3. Drop anything you don't want — remove a key from `fields` or an item from a list.
       * 4. `POST /{uuid}/optimize/accept` with `{ attempt_id, changes: <your edited object> }` (omit `changes` to apply as-is). The agent's fields are written and its prompt rebuilt.
       * 5. Confirm on the agent with `GET /api/v1/agents/{agent_uuid}` (role/objective/tone/guidelines now reflect it). Undo with `POST /{uuid}/optimize/revert { attempt_id }`.
       *
       * **Reading a transcript.** Entries are `{who, text, at}` with `who` one of `customer` (the persona), `assistant` (the agent under test), or `tool` (a real intent/tool execution — carries `name`, `request`, `response`, `success`). A `tool` entry named `call_timeout` marks a call cut by its time budget.
       *
       * **Response envelope.** Every endpoint returns `{success: bool, message: string, data: ...}`; errors use HTTP status + `success:false` with the reason in `message`. A 409 on /run tells you exactly what to fix (already running, incomplete configuration, missing caller line, or empty wallet).
       *
       * **Operational rules (follow them — each prevents a misleading result):**
       * - If a test case's criteria reference the assistant's intents/activities (generate-test-cases often writes such criteria), run with `with_intents: true` — without it the assistant cannot trigger intents and those criteria fail unfairly.
       * - Size `max_turns` to the scenario: 3-4 turns suit a single-question smoke test; discovery/booking scenarios with multi-step criteria need 6-10 turns, or the judge will correctly fail criteria the conversation never had room to reach.
       * - `POST /simulations` with `run: true` can return 201 with 'created, but it could not start: …' in `message` — always check `data.state`: `queued` means running; `draft` means fix the stated reason, then call `/{uuid}/run`.
       * - A real-call run that errors with 'requested sip trunk does not exist' means that CALLER line's telephony is stale — pick a different `caller_agent_uuid` from /options and have the broken line re-provisioned.
       * - A real-call run that errors with 'produced no transcript' may still have connected (check `record_url` for a recording); it means the platform's transcripts never reached the run within 3 minutes.
       * - Judge scores vary between runs of the same configuration; for decisions use `runs_per_case: 3` (criteria resolve by majority) and treat single-run results as smoke signals only.
       *
       * **Minimal end-to-end example** (WhatsApp, auto-generated cases, run immediately):
       * 1. `GET /api/v1/simulations/options` → pick an agent whose `channels` contains `whatsapp`.
       * 2. `POST /api/v1/simulations/generate-test-cases` with body `{ agent_uuid: …, channel: whatsapp }` → returns cases.
       * 3. `POST /api/v1/simulations` with body `{ name: wa-smoke, channel: whatsapp, agent_uuid: …, test_cases: <step 2 result>, runs_per_case: 1, run: true }`.
       * 4. Poll `GET /api/v1/simulations/{uuid}` every ~5s until `state` is `passed` or `failed`.
       * 5. `GET /api/v1/simulations/{uuid}/report` → score, criteria verdicts, issues, suggestions; transcripts under `/runs/{runUuid}`.
  - name: Contact Tags
    description: >-
      Manage contact tags for your account. Each tag is identified by its
      `uuid`.
  - name: WhatsApp Template Settings
    description: >-
      Template Settings make an APPROVED WhatsApp template campaign-ready by
      defining what fills each {{n}} placeholder when a message is sent to a
      contact.


      **Why two layers?** A WhatsApp template (see the WhatsApp Templates tag)
      is the Meta-approved message skeleton: 'Hi {{1}}, your {{2}} is ready'. A
      Template Setting is YOUR mapping for it: {{1}} = the contact's name, {{2}}
      = a fixed value like 'service appointment'. Campaigns reference a Template
      Setting, never a raw template — without one, a WhatsApp campaign has
      nothing to send.


      **Placeholder values — three kinds, resolved per contact at send time:**

      - `{{contact.<field>}}` — a base contact field: name, surname,
      phone_number, email, country_code, timezone, primary_language

      - `{{custom.<field_key>}}` — a custom contact field by its snake_case key
      (e.g. {{custom.car_model}}, {{custom.plate_number}})

      - any other string — sent literally, identical for every contact


      If a mapped field is empty for a contact, the placeholder resolves to an
      empty string and the message still sends.


      **Typical workflow:**

      1. GET /api/v1/whatsapp/templates?active_only=true — find an APPROVED
      template, note its uuid and how many {{n}} placeholders its content has

      2. POST /api/v1/whatsapp/template-settings — create the mapping (one value
      per placeholder, keys '1'..'N')

      3. POST /api/v1/listings with campaign_type='text' and
      contact_template_setting_uuid — launch the campaign


      **Deletion guard:** a setting referenced by a campaign that is In Process,
      Importing, Active, or Paused cannot be deleted (409). Finished campaigns
      don't block deletion.
  - name: Timezone
    description: Timezones available for agent configuration.
  - name: Voice Library
    description: >-
      Catalog of voices available to agents and the speed options each voice
      supports.
  - name: WhatsApp Templates
    description: >-
      Manage WhatsApp message templates — Meta-approved messages used for
      outbound WhatsApp campaigns. All endpoints are scoped to the tenant: you
      can only act on linked WABAs (WhatsApp Business Accounts).


      **Typical workflow — pull existing templates:**

      1. GET /api/v1/whatsapp/wabas — discover WABAs linked to your tenant

      2. POST /api/v1/whatsapp/templates/sync — pull all templates Meta has for
      a WABA (one-time bootstrap)

      3. GET /api/v1/whatsapp/templates?waba_id=...&active_only=true — list
      APPROVED templates ready to use

      4. Use a template UUID with POST /api/v1/whatsapp/template (one-shot send)
      or in a campaign


      **Typical workflow — create a brand-new template with a media header:**

      1. POST /api/v1/whatsapp/templates/upload-media (multipart) — upload your
      image/video/document, receive a `handle`

      2. POST /api/v1/whatsapp/templates — submit with `components` including
      HEADER referencing the handle

      3. Wait — Meta approval is async, usually minutes. Status starts as
      PENDING.

      4. POST /api/v1/whatsapp/templates/{uuid}/sync — refresh status until
      APPROVED, REJECTED, or PAUSED

      5. Once APPROVED, use it in sends/campaigns


      **Component shape — quick reference:**

      - HEADER text:    { type:'HEADER', format:'TEXT', text:'Hi {{1}}',
      example:{header_text:['John']} }

      - HEADER image:   { type:'HEADER', format:'IMAGE',
      example:{header_handle:['<from upload-media>']} }

      - HEADER video/document: same as image with format=VIDEO or DOCUMENT

      - BODY:           { type:'BODY', text:'Order {{1}} ready',
      example:{body_text:[['12345']]} }   note nested array

      - FOOTER:         { type:'FOOTER', text:'Reply STOP to unsubscribe' }

      - BUTTONS group:  { type:'BUTTONS', buttons:[ ... ] } with up to 10
      buttons:
          QUICK_REPLY:  { type:'QUICK_REPLY', text:'Yes please' }
          URL:          { type:'URL', text:'Track', url:'https://example.com' }
          PHONE_NUMBER: { type:'PHONE_NUMBER', text:'Call', phone_number:'+1234567890' }
          COPY_CODE:    { type:'COPY_CODE', example:'WELCOME10' }

      **Tenant scoping:**

      - 403: WABA is not linked to your tenant (no matching WhatsappSetting row)

      - 404 (not 403): templates that belong to other tenants — surfaced as 'not
      found' to avoid info leak. Same convention for non-whatsapp template types
      and orphan rows.


      **How auth works:** the existence of a WhatsappSetting row in the tenant
      DB IS the ownership proof — multi-tenant DB scoping handles isolation. The
      Meta access token used for API calls is the platform-global
      config('whatsapp.access_token'), the same token that powers every other
      WhatsApp send in this codebase (replies, campaigns, one-shot template
      sends). If WhatsappSetting.access_token is populated, that takes
      precedence — but onboarding doesn't fill it today, so the platform token
      is what actually runs.
  - name: Agent Channel Bindings
    description: Agent Channel Bindings
  - name: Agentic Search
    description: Agentic Search
  - name: Contact Blacklist
    description: Contact Blacklist
  - name: Flow
    description: Flow
  - name: SIP Trunk
    description: SIP Trunk
paths:
  /api/v1/agents:
    post:
      tags:
        - Agents
      summary: Create an agent
      description: >-
        Creates a new AI agent. Provide as much of the structured shape as you
        can in one call — a fully-formed agent at creation time has dramatically
        better runtime behavior than a thin agent that gets configured
        incrementally. A high-quality agent typically includes: (1) identity
        (name, company_name, role, language); (2) prompt fields that shape the
        runtime AI (objective, tone, behavior_guidelines, negative_response,
        length_detail); (3) the relevant settings block (settings.voice for
        phone agents, settings.text for messaging agents) populated with at
        minimum the interaction first/end messages and voice_profile or
        working_hours; (4) reference knowledge (notes, training Q&A pairs); (5)
        operational rules (guidelines for short do/don'ts, procedures for
        multi-step workflows); (6) capabilities the agent should perform
        (appointments + schedule_assignments with name/description filled,
        routing_rules with ai_prompt + phrases for IVR, guard_rules with
        when_condition + example_phrases for compliance escalations). Skipping
        prompt/description fields produces hollow agents that respond
        generically and ignore the operational rules at runtime — see each
        sub-schema's description for the AI-prompt fields that must not be left
        empty.
      operationId: 398659378679977808f3ebfabde5cc4f
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AgentUpsertInput'
      responses:
        '201':
          description: Agent created successfully
          content:
            application/json:
              schema:
                properties:
                  success:
                    description: >-
                      Indicates whether the request completed successfully. True
                      for successful responses; false for documented error
                      responses.
                    type: boolean
                  message:
                    description: >-
                      Human-readable response message. Safe to display in logs
                      or simple client notifications; use structured fields for
                      program logic.
                    type: string
                  data:
                    $ref: '#/components/schemas/AgentV1'
                type: object
        '403':
          description: Agent limit reached for the current plan
        '422':
          description: Validation error
      security:
        - bearerAuth: []
components:
  schemas:
    AgentUpsertInput:
      description: >-
        Full agent configuration. Fields fall into three groups: (1) identity
        (name, company, role) — what the agent IS; (2) behavior prompts
        (objective, tone, behavior_guidelines, custom_prompt, negative_response)
        — HOW the runtime AI thinks and talks; (3) capabilities (settings.voice,
        settings.text, guidelines, notes, procedures, training, appointments,
        routing_rules, guard_rules) — WHAT the agent can do. For an agent to
        actually behave well at runtime, populate at least: name, role,
        objective, tone, behavior_guidelines, language, plus the relevant
        settings.voice OR settings.text block. Skipping prompt fields produces
        hollow agents that respond generically.
      required:
        - name
      properties:
        name:
          description: >-
            Required. Internal label for this agent — used in dashboards, logs,
            and as the default `inbound_first_message` 'this is X' name.
            Customers should recognize the brand from the name.
          type: string
          example: Volvo Cagliari Service Agent
        description:
          description: >-
            Internal one-paragraph description of what this agent does. Helps
            your team understand the agent's purpose at a glance — not used by
            the runtime AI, but useful when AI-builder agents (via MCP) decide
            which existing agent to update vs create new.
          type: string
          example: >-
            Inbound voice agent for Volvo Cagliari service appointments. Books
            service slots, qualifies vehicle issues, escalates warranty cases.
          nullable: true
        company_name:
          description: >-
            Brand the agent represents. The runtime AI references this when
            introducing itself.
          type: string
          example: Volvo Cagliari
          nullable: true
        role:
          description: >-
            Strong recommendation. Concrete one-sentence role definition the
            runtime AI reads as system prompt context. Specific roles produce
            focused agents — 'Inbound service scheduler for a Volvo dealership'
            beats 'sales agent'. Without this set, the agent has no identity and
            answers everything generically.
          type: string
          example: >-
            Inbound service appointment scheduler for a Volvo dealership in
            Cagliari.
          nullable: true
        objective:
          description: >-
            Strong recommendation. The single primary outcome the agent should
            drive every conversation toward. Should be measurable. Without an
            objective the agent talks but doesn't close.
          type: string
          example: >-
            Book a service appointment for the customer's vehicle. Capture: VIN
            or license plate, preferred date, type of service.
          nullable: true
        tone:
          description: >-
            Strong recommendation. Voice and style guide. Determines word
            choice, formality, and rapport tactics.
          type: string
          example: >-
            Warm, professional, slightly formal. Use the customer's name. Avoid
            jargon — explain technical terms in plain language.
          nullable: true
        behavior_guidelines:
          description: >-
            Critical. Free-form instructions that shape how the runtime AI
            handles edge cases, escalations, and brand-sensitive moments. Treat
            this as the agent's SOP. Empty = the agent has no rules.
          type: string
          example: >-
            Always confirm vehicle details before booking. Never quote prices
            for warranty repairs — escalate to a human. If the customer is upset
            about a previous service, acknowledge the frustration first, then
            offer to connect them with a manager.
          nullable: true
        company_service:
          description: >-
            What the company actually sells/offers. Helps the agent stay
            on-topic and recognize off-domain questions.
          type: string
          example: >-
            Volvo vehicle service: maintenance, repairs, warranty work,
            accessories, pickup/delivery.
          nullable: true
        topic:
          description: >-
            The narrow conversational topic the agent should stay within.
            Anything off-topic should trigger handover or polite redirect.
          type: string
          example: Service appointment booking and vehicle maintenance questions.
          nullable: true
        length_detail:
          description: >-
            How long replies should be. Voice agents need short crisp turns;
            text agents can be longer.
          type: string
          example: >-
            Keep replies under 25 words for voice; under 200 characters for
            text. One question at a time.
          nullable: true
        interest_of_product:
          description: >-
            Product-marketing context the agent can use to answer questions
            about the offering. Useful for sales-oriented agents.
          type: string
          nullable: true
        negative_response:
          description: >-
            What the agent does when the conversation goes negative. Without
            this set, the agent may apologize excessively or escalate
            inappropriately.
          type: string
          example: >-
            If the customer becomes hostile or uses profanity, stay calm, do not
            escalate emotionally, and offer to transfer to a human supervisor.
          nullable: true
        status:
          description: >-
            Lifecycle state. `ready` = agent is live and reachable; `paused` =
            agent exists but won't accept new conversations.
          type: string
          enum:
            - pending
            - ready
            - in_progress
            - paused
            - completed
          nullable: true
        custom_prompt:
          description: >-
            Advanced. Raw additional system-prompt text appended to whatever the
            runtime AI assembles from the structured fields above. Use only when
            the structured fields can't express what you need — most cases are
            better served by tightening `behavior_guidelines` or adding
            `procedures`.
          type: string
          nullable: true
        language:
          description: >-
            ISO 639-1 code for the agent's primary language. Affects both voice
            (TTS/STT) and text (LLM language). Match
            `settings.voice.voice_profile.language`.
          type: string
          example: en
          nullable: true
        speed:
          description: >-
            Voice playback speed. Use `fast` for repeat customers who know the
            flow; default `normal`.
          type: string
          enum:
            - normal
            - fast
          nullable: true
        timezone:
          description: >-
            IANA timezone. Used for working hours, appointment booking, and
            follow-up scheduling.
          type: string
          example: America/New_York
          nullable: true
        appointment_scheduling_enabled:
          description: >-
            Master switch for appointment booking. When false, all
            schedule_assignments are inert.
          type: boolean
          nullable: true
        appointment_scheduling_randomly:
          description: >-
            When multiple primary schedule_assignments match, pick randomly
            instead of by priority. Use for load balancing across human staff.
          type: boolean
          nullable: true
        custom_llm_url:
          description: >-
            Optional override pointing at a custom LLM endpoint instead of the
            default. Advanced — reach out before using.
          type: string
          nullable: true
        settings:
          description: >-
            Channel-specific behavior. Populate `voice` for phone agents, `text`
            for messaging agents — most agents need only one. See
            AgentVoiceSettings / AgentTextSettings for full field details.
          properties:
            voice:
              $ref: '#/components/schemas/AgentVoiceSettings'
            text:
              $ref: '#/components/schemas/AgentTextSettings'
          type: object
        guidelines:
          description: >-
            Ordered list of short do's and don'ts the runtime AI follows on
            every turn. Use for short, atomic rules. For complex multi-step
            workflows use `procedures` instead.
          type: array
          items:
            $ref: '#/components/schemas/AgentGuidelineInput'
        notes:
          description: >-
            Free-form context the runtime AI keeps available throughout
            conversations — product facts, business rules, edge cases. Use for
            reference knowledge that doesn't fit a guideline or procedure.
          type: array
          items:
            $ref: '#/components/schemas/AgentNoteInput'
        procedures:
          description: >-
            Multi-step workflows the agent can execute end-to-end (e.g. 'book a
            service appointment', 'process a refund'). Each procedure has
            ordered steps. The runtime AI walks the steps when the relevant
            intent is detected.
          type: array
          items:
            $ref: '#/components/schemas/AgentProcedureInput'
        training:
          description: >-
            Few-shot Q&A pairs. The runtime AI uses these as examples of correct
            responses to common questions. Add 5-15 high-impact pairs covering
            frequent customer questions.
          type: array
          items:
            $ref: '#/components/schemas/AgentTrainingInput'
        appointments:
          $ref: '#/components/schemas/AgentAppointmentsInput'
        routing_rules:
          description: >-
            IVR-style transfer rules. The agent uses these to forward calls to
            extensions, phones, or other agents based on detected intent.
          type: array
          items:
            $ref: '#/components/schemas/AgentRoutingRuleInput'
        guard_rules:
          description: >-
            Compliance / safety / escalation triggers. Force the agent to
            forward or end the conversation when defined situations arise.
          type: array
          items:
            $ref: '#/components/schemas/AgentGuardRuleInput'
      type: object
    AgentV1:
      properties:
        agent_uuid:
          type: string
          format: uuid
        name:
          type: string
        description:
          type: string
          nullable: true
        company_name:
          type: string
          nullable: true
        role:
          type: string
          nullable: true
        objective:
          type: string
          nullable: true
        tone:
          type: string
          nullable: true
        behavior_guidelines:
          type: string
          nullable: true
        company_service:
          type: string
          nullable: true
        topic:
          type: string
          nullable: true
        length_detail:
          type: string
          nullable: true
        interest_of_product:
          type: string
          nullable: true
        negative_response:
          type: string
          nullable: true
        status:
          type: string
          enum:
            - pending
            - ready
            - in_progress
            - paused
            - completed
        custom_prompt:
          type: string
          nullable: true
        language:
          type: string
        speed:
          type: string
        timezone:
          type: string
        appointment_scheduling_enabled:
          type: boolean
        appointment_scheduling_randomly:
          type: boolean
        custom_llm_url:
          type: string
          nullable: true
        recommendations:
          description: >-
            JSON string of channel recommendations populated asynchronously
            after creation
          type: string
          nullable: true
        settings:
          properties:
            voice:
              type: object
            text:
              type: object
            memorize:
              type: object
            evaluation:
              type: object
          type: object
        guidelines:
          type: array
          items:
            $ref: '#/components/schemas/AgentGuidelineInput'
        notes:
          type: array
          items:
            $ref: '#/components/schemas/AgentNoteInput'
        procedures:
          type: array
          items:
            $ref: '#/components/schemas/AgentProcedureInput'
        training:
          type: array
          items:
            $ref: '#/components/schemas/AgentTrainingInput'
        intents:
          type: array
          items:
            $ref: '#/components/schemas/IntentV1'
        webhooks:
          description: Agent-scoped webhooks, capped at 5 per agent
          type: array
          items:
            $ref: '#/components/schemas/AgentWebhookV1'
        appointments:
          type: object
        routing_rules:
          type: array
          items:
            $ref: '#/components/schemas/AgentRoutingRuleInput'
        guard_rules:
          type: array
          items:
            $ref: '#/components/schemas/AgentGuardRuleInput'
        phone_numbers:
          type: array
          items:
            properties:
              phone_number_uuid:
                type: string
                format: uuid
                nullable: true
              number:
                type: string
              status:
                type: string
                enum:
                  - active
                  - pending
                  - inactive
                  - deleted
                nullable: true
              country_code:
                type: string
                nullable: true
              type:
                type: string
                nullable: true
              capabilities:
                properties:
                  call:
                    type: boolean
                    nullable: true
                  sms:
                    type: boolean
                    nullable: true
                  whatsapp:
                    type: boolean
                    nullable: true
                  whatsapp_call:
                    type: boolean
                    nullable: true
                type: object
            type: object
        channels:
          type: array
          items:
            type: object
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      type: object
    AgentVoiceSettings:
      description: >-
        Voice/phone behavior for the agent. The runtime AI uses these to script
        the start, middle, and end of every voice conversation, plus the
        technical voice profile (language, voice ID) and call constraints.
        Always populate `interaction.*` first messages and end-of-call message —
        without them the agent goes silent at critical moments.
      properties:
        interaction:
          description: Scripted messages and rules for live conversation flow.
          properties:
            customer_speak_first:
              description: >-
                If true, the agent waits for the customer to speak before
                greeting. Use for inbound where the contact called you and is
                expected to lead. Default false (agent greets first).
              type: boolean
              example: false
            inbound_first_message:
              description: >-
                Required for inbound calls. The first words the agent speaks
                when picking up. Should identify the brand and offer help.
              type: string
              example: Hi, this is Sara from Volvo. How can I help you today?
            outbound_first_message:
              description: >-
                Required for outbound calls. Should identify the brand, the
                reason for calling, and ask permission to continue.
              type: string
              example: >-
                Hi, this is Sara from Volvo Cagliari calling about your service
                appointment. Do you have a moment to talk?
            voice_mail_message:
              description: >-
                Spoken when the call goes to voicemail (detected by
                silence/answering machine). Keep it short and actionable.
              type: string
              example: >-
                Hi, this is Sara from Volvo Cagliari. I called about your
                service appointment — please call us back at your convenience.
            end_call_message:
              description: >-
                Required. Spoken right before the agent hangs up. Always set
                this — without it the call ends abruptly and feels rude.
              type: string
              example: Thank you for calling, have a great day!
            silence_message:
              description: >-
                Spoken when the customer goes silent for
                `silence_timeout_seconds`. Helps recover from network blips and
                disengaged callers.
              type: string
              example: >-
                Are you still there? I want to make sure I'm helping you with
                what you need.
            max_silence_prompts:
              description: >-
                How many times the agent will ask 'are you still there?' before
                hanging up.
              type: integer
              minimum: 1
              example: 3
          type: object
        interruption:
          properties:
            mode:
              description: >-
                Controls how the agent reacts when the customer talks over them.
                `sensitive` = stop instantly on any sound (best for casual
                chat). `balanced` = stop on full words/phrases (recommended
                default). `never_stop` = finish the sentence regardless (use for
                legally-required disclosures).
              type: string
              enum:
                - sensitive
                - balanced
                - never_stop
              example: balanced
          type: object
        voice_profile:
          description: >-
            Technical voice rendering settings. Required for the agent to
            actually sound like anything.
          properties:
            language:
              description: >-
                ISO 639-1 code for the spoken language. Determines accent,
                idioms, and the speech model used. Examples: 'en', 'es', 'de',
                'fr', 'it'.
              type: string
              example: en
            voice_uuid:
              description: >-
                UUID of the selected voice in /api/v1/voice_library. Used both
                on read and write. On update, the matching library row's
                provider voice id is resolved automatically. Use this UUID to
                call /api/v1/voice_speed/{voice_uuid}.
              type: string
              format: uuid
              example: ebeba3e0-89b5-4c94-9841-9555ab155dbc
              nullable: true
            voice_name:
              description: Display name of the selected voice. Read-only on response.
              type: string
              example: Giulia
              nullable: true
          type: object
        call_behavior:
          description: Call-level constraints and behavior.
          properties:
            audio_recording:
              description: >-
                Records the call audio for later evaluation/coaching. Required
                for QA features and most compliance regimes — but check local
                consent laws.
              type: boolean
              example: true
            background_sound:
              description: >-
                Plays a subtle office/call-center ambience. Makes the agent feel
                more human; some markets prefer it off.
              type: boolean
              example: true
            silence_timeout_seconds:
              description: >-
                Seconds of customer silence before the agent triggers
                `silence_message`.
              type: integer
              minimum: 1
              example: 60
            max_call_duration_seconds:
              description: >-
                Hard limit on call length in seconds. The agent ends with
                `max_call_duration_message` when reached. Use to cap runaway
                costs.
              type: integer
              minimum: 60
              example: 1800
            max_call_duration_message:
              description: Spoken right before the call is terminated due to max duration.
              type: string
              example: Thanks for the call — we've reached the time limit. Goodbye!
          type: object
        compliance:
          description: >-
            Regulatory toggles. Affect what the runtime AI may capture, repeat,
            or act on.
          properties:
            eu_gdpr_compliance:
              type: boolean
              example: true
            hipaa_compliance:
              type: boolean
              example: false
          type: object
        normalizers:
          description: >-
            Phone-number normalization rules. Free-form objects per direction;
            consult provider docs for accepted keys.
          properties:
            outbound:
              type: object
              nullable: true
            inbound:
              type: object
              nullable: true
          type: object
      type: object
    AgentTextSettings:
      description: >-
        Text/messaging behavior for the agent (WhatsApp, SMS, Instagram, FB
        Messenger, web chat, email). The runtime AI uses these to time replies,
        simulate human typing, hand over to a human when needed, tune
        personality, and sign emails. HOW TO USE — READ: GET
        /api/v1/agents/{uuid} returns the current values under settings.text
        (this exact shape). CREATE: include a settings.text object in the body
        of POST /api/v1/agents. UPDATE: send the same settings.text object to
        PUT /api/v1/agents/{uuid} — updates are PARTIAL, so only the fields you
        include change and anything you omit is left exactly as it was (to
        change one thing, send just that nested field, e.g.
        settings.text.personality.emoji_usage = Low). CLEAR a value: send it
        explicitly — booleans to false, and strings that support it (like
        email.signature) to an empty string; omitting a field never clears it.
        The email signature also has dedicated endpoints if you prefer:
        GET/PUT/POST/DELETE /api/v1/agents/{uuid}/email-signature (DELETE clears
        it). Defaults work out of the box; each property below documents exactly
        what it does and its allowed values.
      properties:
        daily_limits:
          properties:
            daily_max_messages_per_conversation:
              description: >-
                Per-conversation cap on messages the agent will send in a 24h
                window. Protects against runaway loops and angry follow-ups.
              type: integer
              minimum: 1
              example: 100
            daily_conversation_limit_exceeded_message:
              description: >-
                Sent once when the per-day cap is hit. Tell the contact when the
                agent will be back.
              type: string
              nullable: true
          type: object
        timing_and_delay:
          description: >-
            How fast the agent types and replies. Tune to match the channel —
            WhatsApp tolerates faster cadence than SMS.
          properties:
            base_delay:
              description: >-
                Seconds before the agent starts typing after a customer message
                arrives.
              type: number
              example: 0.5
            pause_before_reply:
              description: >-
                Seconds the agent appears to 'think' before its visible typing
                indicator starts.
              type: number
              example: 1
            typing_speed_wpm_min:
              description: Minimum simulated typing speed in words per minute.
              type: integer
              example: 40
            typing_speed_wpm_max:
              description: >-
                Maximum simulated typing speed. Agent picks a value in [min,max]
                per message — variation makes it feel human.
              type: integer
              example: 60
            typing_speed_char:
              description: >-
                Per-character delay in seconds. Used as a finer-grained
                alternative to wpm.
              type: number
              example: 0.05
            delay_jitter_min:
              type: number
              example: 0.1
            delay_jitter_max:
              description: >-
                Random jitter added to each reply timing within [min,max]
                seconds. Avoids robotic pacing.
              type: number
              example: 1.5
          type: object
        typing_simulation:
          properties:
            show_typing_indicator:
              description: >-
                Send the channel's 'is typing…' indicator while composing.
                Channel-dependent — WhatsApp supports it, some SMS providers
                don't.
              type: boolean
              example: true
            simulate_typing_breaks:
              description: >-
                Insert short pauses mid-message as if the agent stopped to
                think.
              type: boolean
              example: true
            simulate_typos_corrections:
              description: >-
                Send a typo and correct it — extreme realism, but easy to
                overdo. Use sparingly.
              type: boolean
              example: false
          type: object
        working_hours:
          description: >-
            When the agent is allowed to actively reply. Outside these hours,
            behavior follows `outside_hours_behavior`.
          properties:
            enabled:
              type: boolean
              example: false
            start:
              type: string
              example: 9 AM
            end:
              type: string
              example: 5 PM
            timezone:
              type: string
              example: America/New_York
            outside_hours_behavior:
              description: >-
                `Auto-reply` sends a holding message; `Ignore` queues the
                message for the next working hour; `Escalate to AI` lets the
                agent answer anyway.
              type: string
              enum:
                - Auto-reply
                - Ignore
                - Escalate to AI
              example: Auto-reply
            offline_message:
              description: >-
                Sent during off-hours when behavior is `Auto-reply`. Should set
                expectations on response time.
              type: string
              nullable: true
            during_hours_agent:
              description: >-
                Who handles messages during working hours: `ai` = the agent
                itself, `human` = forward to live staff.
              type: string
              enum:
                - ai
                - human
              example: ai
          type: object
        handover:
          description: >-
            When and how to hand a conversation off to a human (or another
            agent).
          properties:
            enabled:
              type: boolean
              example: false
            handover_triggers:
              description: >-
                What event triggers handover. `User request` = customer
                explicitly asks for a human; `Low confidence` = AI uncertainty
                above threshold; `Complex query` = topic detection; `After
                timeout` = no resolution within N turns.
              type: string
              enum:
                - User request
                - Low confidence
                - Complex query
                - After timeout
              example: User request
            handover_method:
              type: string
              enum:
                - Assign agent
                - Email notification
                - Queue system
              example: Assign agent
            handover_message:
              description: >-
                Sent to the customer at the moment of handover. Set
                expectations: 'A teammate will be with you shortly.'
              type: string
              nullable: true
            assignment_strategy:
              type: string
              enum:
                - First available
                - Round robin
                - Skill-based
              example: First available
            handover_timeout:
              description: >-
                Seconds the AI will wait for a human to pick up before falling
                back to `fallback_agent`.
              type: integer
              example: 60
            fallback_agent:
              description: >-
                Where the conversation goes if no human is available within the
                timeout.
              type: string
              example: Bot assistant
          type: object
        confidence_controls:
          properties:
            min_confidence_threshold:
              description: >-
                Below this score the AI will trigger handover (if `Low
                confidence` is in handover_triggers) or ask a clarifying
                question.
              type: number
              maximum: 1
              minimum: 0
              example: 0.7
            ask_clarifying_questions:
              description: >-
                When confidence is low, ask the customer for clarification
                instead of guessing.
              type: boolean
              example: false
          type: object
        message_behavior:
          description: >-
            Optional 'second message' and 'follow-up' personalities — make the
            agent feel proactive instead of reactive.
          properties:
            second_message_behavior:
              description: >-
                Probability that the agent sends an unprompted second message
                right after its first reply (e.g. 'Also — let me know if you
                want me to send a confirmation email').
              properties:
                enabled:
                  type: boolean
                  example: false
                chance:
                  description: 0..1 probability per reply.
                  type: number
                  maximum: 1
                  minimum: 0
                  example: 0.25
                delay_min:
                  type: number
                  example: 1
                delay_max:
                  type: number
                  example: 4
              type: object
            follow_up_behavior:
              description: >-
                Whether the agent reaches out again after a resolved
                conversation goes silent (in hours).
              properties:
                enabled:
                  type: boolean
                  example: false
                delay_min:
                  type: number
                  example: 24
                delay_max:
                  type: number
                  example: 48
              type: object
          type: object
        personality:
          description: >-
            Tone-of-voice knobs. Subtle changes here have outsized impact on how
            human the agent feels.
          properties:
            use_response_variations:
              description: Vary phrasing across replies so the agent doesn't sound canned.
              type: boolean
              example: true
            emoji_usage:
              description: >-
                How often the agent uses emoji. Match the brand and channel —
                High emoji on a B2B legal channel reads as unprofessional.
              type: string
              enum:
                - None
                - Low
                - Medium
                - High
              example: None
            use_punctuation_variation:
              type: boolean
              example: false
            use_filler_words:
              description: >-
                Sprinkle 'sure', 'okay', 'right' into replies. Adds warmth; can
                slow down task-focused conversations.
              type: boolean
              example: false
            enable_small_talk:
              description: >-
                Allow brief off-topic chat (weather, weekend) when the customer
                initiates it.
              type: boolean
              example: false
            energy_level:
              description: >-
                Free-form label for the agent's energy. Examples: 'Friendly',
                'Calm', 'Energetic', 'Professional'. The runtime AI uses this as
                style guidance.
              type: string
              example: Friendly
            empathy_level:
              description: >-
                How explicitly the agent acknowledges the customer's feelings.
                High empathy is essential for support and complaint channels.
              type: string
              enum:
                - None
                - Low
                - Medium
                - High
              example: Medium
          type: object
        advanced:
          properties:
            split_messages:
              description: >-
                Break long replies into multiple shorter messages. Feels more
                like a real person typing thoughts as they form.
              type: boolean
              example: true
            simulate_message_editing:
              description: >-
                Show 'edited' indicator on some messages — extreme realism, off
                by default.
              type: boolean
              example: false
            use_memory_based_context:
              description: >-
                Pull from the contact's memorize settings (see
                /api/v1/memorize/...) when generating replies.
              type: boolean
              example: false
            human_first_mode:
              description: >-
                When true, a human writes the first reply and the AI takes over
                from there. Use during AI rollout to build trust.
              type: boolean
              example: false
          type: object
        email:
          description: >-
            Email-channel behavior. Currently the agent's signature, appended
            automatically to every outgoing email (replies, single sends, and
            email tasks/campaigns that don't already include it).
          properties:
            signature:
              description: >-
                HTML signature for this agent's outgoing emails. Sanitized on
                save; send an empty string to clear it; omit the field to leave
                it unchanged. Requires a connected email address (Mails
                channel). Also editable directly via GET/PUT/POST/DELETE
                /api/v1/agents/{uuid}/email-signature.
              type: string
              example: <p>—<br>Jane, Acme Support</p>
              nullable: true
          type: object
      type: object
    AgentGuidelineInput:
      description: >-
        One short do/don't rule. The runtime AI consults the full set of
        guidelines on every reply. Keep each one atomic and specific — 'Always
        confirm the booking date in YYYY-MM-DD format' beats 'Be professional'.
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
          nullable: true
        content:
          description: >-
            Required. The rule itself, in natural language. Imperative voice
            works best.
          type: string
          example: >-
            Always confirm vehicle VIN or license plate before creating a
            service appointment.
        order:
          description: Display/evaluation order. Lower numbers come first.
          type: integer
          example: 0
      type: object
    AgentNoteInput:
      description: >-
        A piece of reference knowledge the runtime AI can quote when relevant —
        product facts, hours, policies. Notes are passive (consulted on demand)
        versus guidelines which are active (applied on every turn).
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
          nullable: true
        content:
          description: >-
            Required. Free-form reference text. Keep notes focused — one fact or
            policy per note.
          type: string
          example: >-
            Service appointments take 60-90 minutes for standard maintenance,
            2-4 hours for warranty work. Same-day pickup is available before 4
            PM.
        order:
          type: integer
          example: 0
      type: object
    AgentProcedureInput:
      description: >-
        A multi-step workflow the agent can execute (e.g. 'book a service
        appointment'). The runtime AI walks the steps in order when it detects
        the relevant intent. Procedures are how you teach the agent to actually
        DO things instead of just talking.
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
          nullable: true
        name:
          description: Required. Short imperative name describing what this procedure does.
          type: string
          example: Book service appointment
        description:
          description: >-
            When the runtime AI should invoke this procedure. Be specific about
            the trigger.
          type: string
          example: >-
            Used when the customer wants to schedule a service appointment for
            their vehicle.
          nullable: true
        steps:
          description: >-
            Ordered actions the agent performs. Reference an intent_uuid on a
            step to trigger a tool call instead of plain conversation.
          type: array
          items:
            properties:
              order:
                type: integer
                example: 1
              description:
                type: string
                example: Ask the customer for their vehicle license plate or VIN.
              intent_uuid:
                description: >-
                  Optional. UUID of an intent that, when matched, executes a
                  tool/integration at this step (lookup, create record, send
                  notification).
                type: string
                format: uuid
                nullable: true
            type: object
      type: object
    AgentTrainingInput:
      description: >-
        A single few-shot Q&A example. The runtime AI uses these as templates
        for high-quality responses to common questions. Most useful for:
        brand-specific phrasing, tricky FAQs, edge cases the agent keeps getting
        wrong.
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
          nullable: true
        content:
          description: The customer question or scenario.
          type: string
          example: What does Volvo's standard warranty cover?
        intent:
          description: >-
            Optional intent label that lets the runtime AI cluster similar
            questions.
          type: string
          example: warranty_inquiry
          nullable: true
        response:
          description: >-
            The model answer. Match the agent's tone — what you write here is
            what the agent will sound like for similar questions.
          type: string
          example: >-
            Volvo's standard warranty covers 4 years or 100,000 km, whichever
            comes first, including parts and labor at any authorized service
            center. Would you like the details for your specific model?
          nullable: true
      type: object
    AgentAppointmentsInput:
      properties:
        enabled:
          type: boolean
        random_assignment:
          type: boolean
        schedule_assignments:
          description: >-
            Each entry connects the agent to a schedule and tells the runtime AI
            when and how to use it. Always provide `name` and `description` for
            every assignment — without them the runtime AI cannot distinguish
            between schedule types when a contact asks for an appointment.
          type: array
          items:
            properties:
              schedule_uuid:
                description: UUID of the schedule from /api/v1/schedules.
                type: string
                format: uuid
              priority:
                description: >-
                  Used when multiple assignments match a request — primary is
                  preferred.
                type: string
                enum:
                  - primary
                  - secondary
                  - backup
              status:
                type: string
                enum:
                  - active
                  - inactive
              name:
                description: >-
                  Required for the AI to identify this schedule. Short label the
                  runtime agent uses when offering this appointment type to a
                  contact. Examples: 'Service Appointment', 'Sales
                  Consultation', 'Test Drive'. Always set this — assignments
                  without a name are invisible to the AI's selection logic.
                type: string
                example: Service Appointment
              description:
                description: >-
                  Required for the AI to know when to use this schedule.
                  Describes the customer intent or situation that should trigger
                  this assignment. The runtime agent reads this as instructions
                  when deciding which schedule to offer. Always set this — empty
                  descriptions cause the AI to fall back to the primary
                  assignment regardless of customer need.
                type: string
                example: >-
                  When the customer requires routine maintenance, oil change, or
                  scheduled service for their vehicle.
              slot_rules:
                $ref: '#/components/schemas/ScheduleAssignmentSlotRules'
              rescheduling:
                $ref: '#/components/schemas/ScheduleAssignmentRescheduling'
              cancellation:
                $ref: '#/components/schemas/ScheduleAssignmentCancellation'
              questions:
                $ref: '#/components/schemas/ScheduleAssignmentQuestions'
              approval:
                $ref: '#/components/schemas/ScheduleAssignmentApproval'
            type: object
      type: object
    AgentRoutingRuleInput:
      description: >-
        Routing rules tell the runtime agent when and how to transfer a call to
        another extension, phone number, or agent (the IVR equivalent). The
        runtime AI relies on `ai_prompt` and `phrases` to decide whether a
        customer utterance should trigger this rule — assignments without those
        fields will never fire.
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
          nullable: true
        detection_mode:
          description: >-
            How the AI matches customer utterances to this rule. `exact` =
            literal keyword (fast but narrow), `intent` = AI semantic
            understanding (broader, recommended), `both` = combine for max
            accuracy.
          type: string
          enum:
            - exact
            - intent
            - both
          example: intent
        trigger_keyword:
          description: >-
            Literal keyword that triggers `exact`/`both` matching. Required when
            detection_mode is exact or both.
          type: string
          example: sales
          nullable: true
        department_name:
          description: >-
            Human-readable label for this rule. Helps you and the AI identify
            what the rule is for.
          type: string
          example: Sales Department
          nullable: true
        phrases:
          description: >-
            Example customer utterances that should trigger this rule. The
            runtime AI uses these as training signal when detection_mode
            includes intent matching. Provide 3-5 varied phrasings.
          type: array
          items:
            type: string
            example: I want to talk to sales
        ai_prompt:
          description: >-
            Required for intent-based matching. Natural-language instructions
            the runtime AI uses to decide whether a customer utterance matches
            this rule. Without this field set, intent and both detection modes
            have no guidance to act on, so the rule will never trigger. Always
            provide concrete instructions describing what customer intent should
            fire this rule.
          type: string
          example: >-
            Detect when the customer wants to speak with the sales team — they
            may ask about pricing, new products, quotes, or directly mention
            sales.
          nullable: true
        voice_response:
          description: >-
            Message the runtime agent speaks to the customer immediately before
            initiating the transfer. Required.
          type: string
          example: Sure, I'll transfer you to our sales team now. One moment please.
        voice_on_error:
          description: >-
            Spoken when the transfer fails (busy, no answer, error).
            Recommended.
          type: string
          example: >-
            I'm sorry, I couldn't reach sales right now. Please call back later
            or leave a message.
          nullable: true
        voice_on_success:
          description: >-
            Spoken when the transfer completes successfully (typically only used
            for warm/ping-and-transfer modes).
          type: string
          example: You've been successfully connected. Have a great day.
          nullable: true
        destination_type:
          description: >-
            Where the call is sent. `extension` = SIP extension or URI (e.g.
            '101' or 'sip:101@domain.com'), `phone` = external phone number in
            E.164, `agent` = another mihu agent (set destination_agent_uuid).
          type: string
          enum:
            - extension
            - phone
            - agent
          example: extension
          nullable: true
        destination:
          description: >-
            The actual destination value. Format depends on destination_type:
            extension number, SIP URI, or E.164 phone. Ignored when
            destination_type=agent.
          type: string
          example: '101'
          nullable: true
        destination_agent_uuid:
          description: UUID of the target agent. Required when destination_type=agent.
          type: string
          format: uuid
          nullable: true
        transfer_type:
          description: >-
            Telephony transfer mechanism. `transfer_call` = default transfer
            (recommended for most cases). `forward_call` = simple forwarding.
            `warm_transfer_call` = the agent stays on the line and announces the
            caller before connecting. `blind_transfer_call` = hang up the moment
            the destination rings. `ping_and_transfer_call` = the agent briefly
            announces the caller, then transfers.
          type: string
          enum:
            - transfer_call
            - forward_call
            - warm_transfer_call
            - blind_transfer_call
            - ping_and_transfer_call
          example: transfer_call
        transfer_config:
          description: >-
            Optional telephony-provider-specific configuration. Free-form
            key/value map; consult provider docs for accepted keys.
          type: object
          nullable: true
        priority:
          description: >-
            Match priority. Lower numbers run first when multiple rules could
            match the same utterance.
          type: integer
          example: 1
        is_active:
          type: boolean
          example: true
      type: object
    AgentGuardRuleInput:
      description: >-
        Guard rules let the agent forward or end a conversation when a defined
        situation arises (compliance, safety, escalation). The runtime AI relies
        on `when_condition` and `example_phrases` to decide whether a customer
        utterance triggers the guard — rules without those fields filled cannot
        fire reliably.
      properties:
        uuid:
          type: string
          format: uuid
          readOnly: true
          nullable: true
        name:
          description: Optional short name for the guard rule.
          type: string
          example: Legal complaint escalation
          nullable: true
        when_condition:
          description: >-
            Required. Natural-language description of the situation that should
            trigger this guard. The runtime AI uses this as instructions when
            classifying customer utterances. Be specific — 'customer is angry'
            is too vague; 'customer uses profanity or threatens to escalate' is
            actionable.
          type: string
          example: >-
            Customer mentions a legal complaint, lawyer, lawsuit, or threatens
            to take legal action.
        example_phrases:
          description: >-
            Customer utterances that should trigger this guard. Provide 3-5
            varied phrasings — the runtime AI uses these as positive examples
            when classifying.
          type: array
          items:
            type: string
            example: I'm calling my lawyer about this
        then_action:
          description: >-
            What the runtime agent does when the guard fires. `forward`
            transfers to a human or another agent; `end_conversation` politely
            ends the call/chat.
          type: string
          enum:
            - forward
            - end_conversation
          example: forward
        selected_channels:
          description: Channels where this guard is active. Defaults to phone-only.
          type: array
          items:
            type: string
            enum:
              - phone
              - instagram
              - whatsapp
              - facebook_messenger
        say_before_forwarding:
          description: Message spoken before the transfer when then_action=forward.
          type: string
          example: >-
            I understand this is important — let me connect you with someone who
            can help.
          nullable: true
        say_before_end:
          description: Message spoken before ending when then_action=end_conversation.
          type: string
          example: >-
            I'm sorry I couldn't help further. Please contact our team directly.
            Goodbye.
          nullable: true
        destination_type:
          description: >-
            Where the call is sent when then_action=forward (same semantics as
            routing rules).
          type: string
          enum:
            - extension
            - phone
            - agent
          nullable: true
        destination:
          description: >-
            Destination value (extension, SIP URI, or E.164 phone) when
            then_action=forward.
          type: string
          nullable: true
        destination_agent_uuid:
          description: Target agent UUID when destination_type=agent.
          type: string
          format: uuid
          nullable: true
        is_active:
          type: boolean
          example: true
        is_default:
          description: >-
            Marks this guard as a default that auto-applies to new agents in the
            workspace.
          type: boolean
          example: false
      type: object
    IntentV1:
      properties:
        intent_uuid:
          type: string
          format: uuid
        key:
          type: string
        name:
          type: string
        description:
          type: string
          nullable: true
        recommendation_actions:
          type: string
          nullable: true
        confidence_threshold:
          type: number
          format: float
        is_system:
          type: boolean
        intent_llm_handle_by_response:
          type: boolean
        webhook:
          properties:
            url:
              type: string
              nullable: true
            auth_token:
              type: string
              nullable: true
          type: object
        parameters:
          type: array
          items:
            $ref: '#/components/schemas/IntentParameterInput'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      type: object
    AgentWebhookV1:
      properties:
        webhook_uuid:
          type: string
          format: uuid
        url:
          type: string
          format: uri
        events:
          type: array
          items:
            type: string
            enum:
              - conversation_status
              - conversation_end_report
              - conversation_update
              - voice_evaluation
              - text_evaluation
              - intent_call
        is_active:
          type: boolean
        has_secret:
          description: >-
            True if a secret_key is set on this webhook. The secret itself is
            never returned.
          type: boolean
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      type: object
    ScheduleAssignmentSlotRules:
      description: >-
        Controls when slots are offered and how the AI resolves scheduling
        conflicts.
      properties:
        offer_slots_from:
          description: Minimum lead time before a slot becomes offerable to a contact.
          type: string
          enum:
            - now
            - 30_min
            - 1_hour
            - 2_hours
            - 3_hours
            - 6_hours
            - 24_hours
          example: 3_hours
        book_slots_from:
          description: >-
            Minimum lead time before a slot becomes bookable. Usually >=
            offer_slots_from.
          type: string
          enum:
            - now
            - 30_min
            - 1_hour
            - 2_hours
            - 3_hours
            - 6_hours
            - 24_hours
          example: 6_hours
        max_appointments_per_day:
          description: Daily booking cap for this assignment. Null = unlimited.
          type: integer
          minimum: 1
          example: 10
          nullable: true
        conflict_resolution_enabled:
          description: >-
            When true, the AI suggests alternative slots if the requested time
            is unavailable.
          type: boolean
          example: true
        alternative_slots_count:
          description: How many alternatives to offer when a conflict is detected.
          type: integer
          minimum: 1
          example: 3
        suggestion_priority:
          description: >-
            How alternatives are ranked: nearest in time, same calendar day, or
            same time slot on a different day.
          type: string
          enum:
            - nearest
            - same_day
            - same_time
          example: nearest
        prefer_same_day:
          type: boolean
          example: true
        prefer_same_time_slot:
          type: boolean
          example: false
        include_same_week:
          type: boolean
          example: true
      type: object
    ScheduleAssignmentRescheduling:
      description: When and how the contact may reschedule an existing appointment.
      properties:
        policy:
          description: >-
            always_ask = every reschedule needs human approval; auto_minor = AI
            can reschedule minor changes; auto_all = AI may reschedule freely
            within the rules.
          type: string
          enum:
            - always_ask
            - auto_minor
            - auto_all
          example: always_ask
        minor_change_hours:
          description: >-
            Maximum hour delta that counts as a 'minor' reschedule under the
            auto_minor policy.
          type: integer
          minimum: 0
          example: 2
        minor_change_same_day:
          type: boolean
          example: true
        minor_change_same_week:
          type: boolean
          example: false
        minor_change_same_slot:
          type: boolean
          example: false
        min_rescheduling_notice:
          description: >-
            Minimum advance notice before the appointment that a reschedule is
            allowed.
          type: string
          enum:
            - none
            - 1_hour
            - 2_hours
            - 6_hours
            - 24_hours
          example: 2_hours
      type: object
    ScheduleAssignmentCancellation:
      description: >-
        Cancellation notice window, fee policy, and whether the AI may cancel
        autonomously.
      properties:
        min_cancellation_notice:
          description: >-
            Minimum advance notice before the appointment that a cancellation is
            allowed.
          type: string
          enum:
            - none
            - 1_hour
            - 6_hours
            - 24_hours
            - 48_hours
          example: 24_hours
        ai_can_cancel:
          description: >-
            When true, the runtime AI may cancel an appointment on the contact's
            request without human approval.
          type: boolean
          example: false
        require_cancellation_reason:
          description: >-
            When true, the AI must capture a cancellation reason from the
            contact before confirming.
          type: boolean
          example: true
        cancellation_fee_policy:
          description: >-
            Open-ended label describing how cancellation fees are handled (e.g.
            'no_fee', 'flat_fee', 'percent_of_booking').
          type: string
          example: no_fee
      type: object
    ScheduleAssignmentQuestions:
      description: >-
        Custom intake questions the AI asks the contact when booking through
        this assignment.
      properties:
        inherit_from_schedule:
          description: >-
            When true, the assignment uses the parent schedule's
            custom_questions. Set false to override with per-assignment
            questions.
          type: boolean
          example: true
        custom_questions:
          description: >-
            Per-assignment override list. Ignored when inherit_from_schedule is
            true.
          type: array
          items:
            properties:
              name:
                type: string
                example: License plate
              type:
                type: string
                enum:
                  - text
                  - textarea
                  - number
                  - email
                  - phone
                example: text
              description:
                type: string
                example: Vehicle license plate number for the service appointment.
              required:
                type: boolean
                example: true
            type: object
      type: object
    ScheduleAssignmentApproval:
      description: >-
        Human approval workflow for create / reschedule / cancel / notes
        actions.
      properties:
        require_approval:
          description: >-
            Master switch — when false, all actions are auto-approved regardless
            of the per-action flags.
          type: boolean
          example: true
        approval_threshold:
          description: >-
            Auto-approve actions if the lead time is at least this long; never =
            always require approval.
          type: string
          enum:
            - never
            - 15_min
            - 30_min
            - 1_hour
            - 24_hours
          example: 1_hour
        approval_for_create:
          type: boolean
          example: false
        approval_for_reschedule:
          type: boolean
          example: true
        approval_for_cancel:
          type: boolean
          example: true
        approval_for_notes:
          type: boolean
          example: false
        notify_calendar_owner:
          type: string
          enum:
            - always
            - approval_only
            - never
          example: always
        notify_admins:
          type: string
          enum:
            - always
            - approval_only
            - never
          example: always
        expected_response_time:
          description: >-
            Free-form label for how quickly approvers are expected to respond
            (e.g. '5_min', '15_min', '1_hour').
          type: string
          example: 5_min
      type: object
    IntentParameterInput:
      required:
        - key
      properties:
        key:
          type: string
          example: email
        default:
          description: Default value; leave empty to ask the user
          type: string
          nullable: true
        type:
          description: >-
            Parameter data type. Limited to these four primitives so it maps
            cleanly to OpenAI's tool-schema format.
          type: string
          enum:
            - string
            - number
            - boolean
            - array
          example: string
        required:
          type: boolean
      type: object
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      description: >-
        Use a Bearer token to access these API endpoints. Example: "Bearer
        {your-token}"

````