{"openapi":"3.1.0","info":{"title":"smao Public API","version":"1.6.0","summary":"Programmatic access to assistants, selectable voices, contact data, calls and recordings, and usage statistics.","description":"The smao Public API gives you programmatic access to the resources you\nmanage in the dashboard: assistants, selectable voices, assistant configuration\n(prompts, knowledge items, glossary, pronunciation, forwardings, calendars, tools), contact data,\ncall history with transcripts and recordings, outbound call triggering, and\nusage statistics.\n\n## Base URL\n\nProduction: `https://api.smao.ai/api/v1`\n\n## Authentication\n\nAll endpoints (except `/openapi.*` and `/docs`) require a bearer token in the\n`Authorization` header:\n\n```\nAuthorization: Bearer <your_api_key>\n```\n\nAPI keys are created in the smao dashboard under *Settings → API Keys*.\nEach key is scoped to a single organization and a single role.\n\n## Response shape\n\n**Success (2xx):**\n```json\n{ \"data\": { … } }\n```\nor for paginated list endpoints:\n```json\n{ \"data\": [ … ], \"meta\": { \"has_more\": false, \"next_cursor\": null } }\n```\n\n**Error (4xx / 5xx):**\n```json\n{ \"error\": { \"code\": \"validation_failed\", \"message\": \"…\", \"details\": [] } }\n```\n\n## Field naming\n\nAPI-defined request and response field names use `snake_case`. Caller-defined\nJSON objects such as tool parameters and custom webhook headers retain the\nkeys supplied by the caller. Timestamps are ISO-8601 strings in UTC. Object\nIDs are 24-character lowercase hex strings.\n\n## Pagination\n\nList endpoints use **opaque cursor pagination**. Send `?limit=N` on the first\nrequest; if `meta.has_more` is `true`, pass `meta.next_cursor` back as the\n`cursor` query parameter for the next page. Cursors are opaque — do not parse\nor construct them.\n\n## Rate limiting\n\nMatched operations are rate-limited per API key. After authentication, the\nfeature gate, and the limiter succeed, responses include:\n\n- `X-RateLimit-Limit` — bucket limit\n- `X-RateLimit-Remaining` — remaining requests in the current window\n- `X-RateLimit-Reset` — unix timestamp when the window resets\n\nDefault buckets (deployments may override these values):\n\n| Category | Limit | Applies to |\n|---|---|---|\n| `read` | 1000 / min | All GET endpoints |\n| `write` | 200 / min | POST / PATCH / DELETE on all resources except `POST /calls` |\n| `outbound_trigger` | 60 / hour | POST /calls |\n\n`POST /calls` also permits only one outbound call per assistant in any\n60-second window. When a bucket is exhausted you receive HTTP `429` with\n`error.code = rate_limit_exceeded` and `Retry-After`. The per-assistant\ncooldown and limiter-storage failure use the same status/code but do not\ninclude `Retry-After`. Authentication failures, feature-gate failures,\nunmatched routes, and limiter-storage failures do not include the complete\nrate-limit header set.\n","contact":{"name":"smao Support","email":"support@smao.ai"},"license":{"name":"Proprietary","identifier":"LicenseRef-Proprietary"}},"servers":[{"url":"https://api.smao.ai/api/v1","description":"Production"}],"tags":[{"name":"Meta","description":"Health and connectivity."},{"name":"Contacts","description":"Create and manage contact records — phone numbers, names, emails, group assignment."},{"name":"Groups","description":"Organize contacts, knowledge items, forwardings, glossary entries, and pronunciation rules."},{"name":"Knowledge-items","description":"Knowledge-base entries used by assistants for RAG."},{"name":"Prompts","description":"Reusable assistant prompts (answering and email templates).\n\nWhen automated prompt rating is enabled for the deployment, every save\n(`POST` or `PATCH`) runs deterministic checks first. Blocking defects are\nrated immediately; other prompts enter asynchronous quality review. See\nthe `Prompt` schema for the rating fields and their lifecycle.\n"},{"name":"Assistants","description":"Voice assistants — the phone-answering bots that run your conversations."},{"name":"Voices","description":"Voices currently selectable for new assistants and voice changes."},{"name":"Forwardings","description":"Call-forwarding targets (phone or SIP) that assistants route to."},{"name":"Glossary","description":"Domain-specific terms and abbreviations assistants use during calls."},{"name":"Pronunciation","description":"Word-level pronunciation overrides that assistants apply when speaking during calls. Each rule matches one written token, not a multi-word phrase. Replacement text and spell-out affect both voice generations; speaking-rate rules and IPA transcriptions are applied on v2 voices and ignored on v1 voices."},{"name":"Calendars","description":"Opening-hours calendars — multi-schedule (opening/service/office/operating), weekly templates, and date-specific overrides that assistants consult during calls."},{"name":"Calls","description":"Read call history, fetch recordings, and trigger outbound calls."},{"name":"Statistics","description":"Aggregated call statistics — weekly and monthly usage breakdowns, per-assistant rollups, and last-24h hourly counts. Read-only, computed at query time."},{"name":"Tools","description":"Custom webhook tools that assistants invoke during calls. v1 supports webhook-type tools only (integration tools are created via the dashboard OAuth flow). Auth secrets are encrypted at rest with AES-256-GCM and are never returned by the API — the response surfaces `has_secret: boolean` instead."}],"security":[{"bearerAuth":[]}],"paths":{"/ping":{"get":{"operationId":"getPing","tags":["Meta"],"summary":"Health check","description":"Confirms the API is reachable and your API key is valid.","responses":{"200":{"description":"OK","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"}},"content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","properties":{"ok":{"type":"boolean","example":true},"now":{"type":"string","format":"date-time"}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/contacts":{"get":{"operationId":"listContacts","tags":["Contacts"],"summary":"List contacts (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Limit200"},{"name":"group_id","in":"query","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"},"description":"Filter by contacts group."}],"responses":{"200":{"description":"Page of contacts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageContact"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createContact","tags":["Contacts"],"summary":"Create a contact","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/contacts/{contact_id}":{"parameters":[{"$ref":"#/components/parameters/ContactId"}],"get":{"operationId":"getContact","tags":["Contacts"],"summary":"Get a contact","responses":{"200":{"description":"The contact.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateContact","tags":["Contacts"],"summary":"Update a contact","description":"Partial update — only included fields are changed.","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ContactUpdate"}}}},"responses":{"200":{"description":"Updated contact.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Contact"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteContact","tags":["Contacts"],"summary":"Delete a contact","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/groups":{"get":{"operationId":"listGroups","tags":["Groups"],"summary":"List groups (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/Limit200"},{"name":"type","in":"query","schema":{"type":"string","enum":["contacts","knowledges","forwardings","glossaries","pronunciations"]},"description":"Filter by group type."}],"responses":{"200":{"description":"Page of groups.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageGroup"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createGroup","tags":["Groups"],"summary":"Create a group","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Group"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/groups/{group_id}":{"parameters":[{"$ref":"#/components/parameters/GroupId"}],"get":{"operationId":"getGroup","tags":["Groups"],"summary":"Get a group","responses":{"200":{"description":"The group.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Group"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateGroup","tags":["Groups"],"summary":"Update a group","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GroupUpdate"}}}},"responses":{"200":{"description":"Updated group.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Group"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteGroup","tags":["Groups"],"summary":"Delete a group","description":"Permanently deletes the group and all contacts, knowledge items,\nforwardings, glossary entries, or pronunciation rules it contains.\nKnowledge chunks are also removed. This operation is not reversible.\n\nFails with 409 `conflict` if the group is assigned to an assistant or is\nthe organization's last group of that type.\n","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/knowledge-items":{"get":{"operationId":"listKnowledgeItems","tags":["Knowledge-items"],"summary":"List knowledge items (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"},{"name":"group_id","in":"query","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"},"description":"Filter by knowledges group."}],"responses":{"200":{"description":"Page of knowledge items.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageKnowledgeItem"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createKnowledgeItem","tags":["Knowledge-items"],"summary":"Create a knowledge item","description":"Creates a new knowledge item and asynchronously embeds its text for\nretrieval. `sync_status.state` follows the lifecycle:\n\n`pending` → `syncing` → `synced` (success) or `failed` (terminal).\n\nPoll the item via `GET` to observe the transition. `pending` is\nnon-terminal: use a client-side polling timeout because a queueing\nfailure can leave the item pending. A later valid `PATCH` re-enqueues\nindexing; contact support if the state does not progress.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeItemCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KnowledgeItem"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/knowledge-items/{knowledge_item_id}":{"parameters":[{"$ref":"#/components/parameters/KnowledgeItemId"}],"get":{"operationId":"getKnowledgeItem","tags":["Knowledge-items"],"summary":"Get a knowledge item (with full text)","responses":{"200":{"description":"The knowledge item.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KnowledgeItemDetail"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateKnowledgeItem","tags":["Knowledge-items"],"summary":"Update a knowledge item","description":"Every update currently re-indexes the item, including changes limited\nto `name`, `group_id`, or `active`. `sync_status.state` resets to\n`pending` and follows the same lifecycle as a fresh create:\n\n`pending` → `syncing` → `synced` (success) or `failed` (terminal).\n\nUse a client-side polling timeout because a queueing failure can leave\nthe item pending.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/KnowledgeItemUpdate"}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/KnowledgeItem"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteKnowledgeItem","tags":["Knowledge-items"],"summary":"Delete a knowledge item","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/prompts":{"get":{"operationId":"listPrompts","tags":["Prompts"],"summary":"List prompts (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"}],"responses":{"200":{"description":"Page of prompts.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePrompt"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createPrompt","tags":["Prompts"],"summary":"Create a prompt","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Prompt"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/prompts/{prompt_id}":{"parameters":[{"$ref":"#/components/parameters/PromptId"}],"get":{"operationId":"getPrompt","tags":["Prompts"],"summary":"Get a prompt","responses":{"200":{"description":"The prompt.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Prompt"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updatePrompt","tags":["Prompts"],"summary":"Update a prompt","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PromptUpdate"}}}},"responses":{"200":{"description":"Updated.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Prompt"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deletePrompt","tags":["Prompts"],"summary":"Delete a prompt","description":"Before deleting, clear both `prompt_id` and `email_prompt_id` references\nfrom assistants. The server returns 409 `conflict` when the prompt is\nstill assigned through `prompt_id`; clients must not rely on that guard\nto detect an `email_prompt_id` reference.\n","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/voices":{"get":{"operationId":"listVoices","tags":["Voices"],"summary":"List selectable voices","description":"Returns the voices the authenticated instance can assign to a new\nassistant or select during a voice change. Legacy voices retained by\nexisting assistants and voices reserved for internally managed lines\nare not returned.\n","responses":{"200":{"description":"Selectable voices.","content":{"application/json":{"schema":{"type":"object","required":["data"],"additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Voice"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/assistants":{"get":{"operationId":"listAssistants","tags":["Assistants"],"summary":"List assistants (paginated)","description":"Includes each assistant's pre_call_webhook configuration (null if unconfigured). Authentication secrets and passwords are never returned.","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"}],"responses":{"200":{"description":"Page of assistants.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageAssistant"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createAssistant","tags":["Assistants"],"summary":"Create an assistant","description":"Creates a new assistant and provisions a phone number for it. The\n`phone_number` field on the response is assigned by the platform —\ncallers cannot set or change it via this API. Cross-resource refs\n(prompt_id, knowledge_group_ids, etc.) are validated to belong to\nyour organization before the assistant is saved.\n\nOptionally configure `pre_call_webhook` in this initial request.\nConfiguration and credentials are validated and encrypted before\nassistant creation begins; saving does not call the webhook.\nAdd `@preCallData` to the assigned prompt to use the lookup response.\nSee the pre-call webhook schema for template variables and runtime limits.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Assistant"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/assistants/{assistant_id}":{"parameters":[{"$ref":"#/components/parameters/AssistantId"}],"get":{"operationId":"getAssistant","tags":["Assistants"],"summary":"Get an assistant","description":"Includes the credential-free pre_call_webhook configuration, or null. A returned configuration can be sent back on PATCH without resending its stored credentials.","responses":{"200":{"description":"The assistant.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Assistant"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateAssistant","tags":["Assistants"],"summary":"Update an assistant","description":"Partial update — only included fields are changed. `phone_number` and\n`carrier` are read-only and cannot be updated via this endpoint.\nCross-resource refs are validated to belong to your organization.\n\nWhen `introduction` is included, the successful response confirms that\nthe new opening text has been committed to the active assistant\nconfiguration used by the dashboard and by newly initialized calls.\nExisting localized translations are regenerated asynchronously;\nalready initialized or in-progress calls keep the configuration they\nloaded earlier. A code-managed line whose greeting is owned by an\nenterprise line profile returns `409 Conflict`.\n\n`pre_call_webhook` is merged: omit it to preserve it, or send null\nto remove it and its credentials. A supplied object requires `enabled`\nand, when enabled, `url`; other omitted fields retain their values.\nA supplied header map replaces all custom headers; null clears them.\nOmit `auth` to preserve authentication, or send null to remove it.\nWith the same auth type, omitted secrets/passwords are retained.\nChanging auth type removes its old fields and requires the new credential\n(except for `none`). Missing required credentials return 400.\nDisabling preserves credentials; clearing removes them.\n\nEnterprise assistants reject webhook mutations with 409. A concurrent\nclear or auth-state change that invalidates the merge also returns 409\nwithout applying any part of this PATCH; read the current configuration\nbefore submitting an updated request. Saving never fires the webhook.\nThe assigned prompt must contain `@preCallData` to use its response.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AssistantUpdate"},"examples":{"configure":{"summary":"Configure a bearer-authenticated lookup","value":{"pre_call_webhook":{"enabled":true,"url":"https://crm.example.com/lookup","auth":{"type":"bearer","secret":"example-only-token"}}}},"edit_without_credentials":{"summary":"Change the URL and retain the stored bearer token","value":{"pre_call_webhook":{"enabled":true,"url":"https://crm.example.com/lookup-v2","auth":{"type":"bearer"}}}},"rotate":{"summary":"Replace the bearer token","value":{"pre_call_webhook":{"enabled":true,"url":"https://crm.example.com/lookup","auth":{"type":"bearer","secret":"example-only-new-token"}}}},"disable":{"summary":"Disable execution and retain the configuration","value":{"pre_call_webhook":{"enabled":false}}},"clear":{"summary":"Remove configuration and credentials","value":{"pre_call_webhook":null}},"introduction":{"summary":"Change only the opening text","value":{"introduction":"Guten Tag, hier ist Sarah von Example GmbH."}}}}}},"responses":{"200":{"description":"Updated assistant.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Assistant"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteAssistant","tags":["Assistants"],"summary":"Delete an assistant","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/forwardings":{"get":{"operationId":"listForwardings","tags":["Forwardings"],"summary":"List forwardings (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"},{"name":"group_id","in":"query","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"},"description":"Filter by forwardings group."}],"responses":{"200":{"description":"Page of forwardings.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageForwarding"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createForwarding","tags":["Forwardings"],"summary":"Create a forwarding","description":"Creates a new forwarding target inside a forwardings-type group. The\nreferenced `group_id` must belong to your organization and have\n`type: forwardings`. When `destination_type` is `sip`, `sip_uri` is\nrequired. When `destination_type` is `sip_refer`, `sip_refer_target`\nis required. For a usable `phone` destination, provide a non-empty\n`phone_number`; current request validation also accepts an omitted or\nempty value, which produces a target that cannot be dialed.\n","requestBody":{"required":true,"content":{"application/json":{"example":{"group_id":"65a1234567890abcdef01234","type":"queue","destination_type":"phone","phone_number":"+12025550123"},"schema":{"$ref":"#/components/schemas/ForwardingCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Forwarding"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The referenced `group_id` does not exist in your organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Group not found"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/forwardings/{forwarding_id}":{"parameters":[{"$ref":"#/components/parameters/ForwardingId"}],"get":{"operationId":"getForwarding","tags":["Forwardings"],"summary":"Get a forwarding","responses":{"200":{"description":"The forwarding.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Forwarding"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateForwarding","tags":["Forwardings"],"summary":"Update a forwarding","description":"Partial update — only included fields are changed. `group_id` cannot\nbe changed via this endpoint; create a new forwarding in the target\ngroup instead. When changing to `destination_type: phone`, also send a\nnon-empty `phone_number`; the validator permits it to be omitted or\nempty, but the resulting target cannot be dialed.\n","requestBody":{"required":true,"content":{"application/json":{"example":{"timeout":30},"schema":{"$ref":"#/components/schemas/ForwardingUpdate"}}}},"responses":{"200":{"description":"Updated forwarding.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Forwarding"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteForwarding","tags":["Forwardings"],"summary":"Delete a forwarding","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/glossary":{"get":{"operationId":"listGlossary","tags":["Glossary"],"summary":"List glossary items (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"},{"name":"group_id","in":"query","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"},"description":"Filter by glossaries group."}],"responses":{"200":{"description":"Page of glossary items.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageGlossary"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createGlossary","tags":["Glossary"],"summary":"Create a glossary item","description":"Creates a new glossary item inside a glossaries-type group. The\nreferenced `group_id` must belong to your organization and have\n`type: glossaries`.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlossaryCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Glossary"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The referenced `group_id` does not exist in your organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Group not found"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/glossary/{glossary_id}":{"parameters":[{"$ref":"#/components/parameters/GlossaryId"}],"get":{"operationId":"getGlossary","tags":["Glossary"],"summary":"Get a glossary item","responses":{"200":{"description":"The glossary item.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Glossary"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateGlossary","tags":["Glossary"],"summary":"Update a glossary item","description":"Partial update — only included fields are changed. `group_id` cannot\nbe changed via this endpoint; create a new glossary item in the target\ngroup instead.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GlossaryUpdate"}}}},"responses":{"200":{"description":"Updated glossary item.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Glossary"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteGlossary","tags":["Glossary"],"summary":"Delete a glossary item","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/pronunciation":{"get":{"operationId":"listPronunciation","tags":["Pronunciation"],"summary":"List pronunciation items (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"},{"name":"group_id","in":"query","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"},"description":"Filter by pronunciations group."}],"responses":{"200":{"description":"Page of pronunciation items.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PagePronunciation"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createPronunciation","tags":["Pronunciation"],"summary":"Create a pronunciation item","description":"Creates a new pronunciation item inside a pronunciations-type group. The\nreferenced `group_id` must belong to your organization and have\n`type: pronunciations`.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PronunciationCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Pronunciation"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The referenced `group_id` does not exist in your organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Group not found"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/pronunciation/{pronunciation_id}":{"parameters":[{"$ref":"#/components/parameters/PronunciationId"}],"get":{"operationId":"getPronunciation","tags":["Pronunciation"],"summary":"Get a pronunciation item","responses":{"200":{"description":"The pronunciation item.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Pronunciation"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updatePronunciation","tags":["Pronunciation"],"summary":"Update a pronunciation item","description":"Partial update — only included fields are changed. `group_id` cannot\nbe changed via this endpoint; create a new pronunciation item in the\ntarget group instead.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/PronunciationUpdate"}}}},"responses":{"200":{"description":"Updated pronunciation item.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Pronunciation"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deletePronunciation","tags":["Pronunciation"],"summary":"Delete a pronunciation item","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/calendars":{"get":{"operationId":"listCalendars","tags":["Calendars"],"summary":"List calendars (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"}],"responses":{"200":{"description":"Page of calendars.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageCalendar"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createCalendar","tags":["Calendars"],"summary":"Create a calendar","description":"Creates a new calendar. You can optionally seed one or more schedules\n(opening hours, service hours, etc.) along with their weekly template\nand date-specific overrides in a single request. Calendar names must\nbe unique within your organization.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Calendar"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A calendar with that name already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"A calendar with this name already exists"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/calendars/{calendar_id}":{"parameters":[{"$ref":"#/components/parameters/CalendarId"}],"get":{"operationId":"getCalendar","tags":["Calendars"],"summary":"Get a calendar","responses":{"200":{"description":"The calendar.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Calendar"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateCalendar","tags":["Calendars"],"summary":"Update a calendar","description":"Partial update — only included fields are changed. Passing\n`schedules` replaces the calendar's full schedules array.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CalendarUpdate"}}}},"responses":{"200":{"description":"Updated calendar.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Calendar"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"A calendar with that name already exists.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"A calendar with this name already exists"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCalendar","tags":["Calendars"],"summary":"Delete a calendar","description":"Deletes a calendar. Fails with `409 conflict` if the calendar is still\nassigned to one or more assistants — unlink it from every assistant\nfirst (via the Assistants endpoint) and retry.\n","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Calendar is still assigned to one or more assistants.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"This calendar is still being used by assistants"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/calls":{"get":{"operationId":"listCalls","tags":["Calls"],"summary":"List calls (paginated)","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitCalls"},{"name":"assistant_id","in":"query","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"},"description":"Filter by assistant."},{"name":"assistant_phone","in":"query","schema":{"type":"string","pattern":"^\\+\\d{6,20}$","example":"+491701234567"},"description":"Filter by assistant phone number. E.164 format — a leading `+` followed by 6–20 digits."},{"name":"created_from","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"created_to","in":"query","schema":{"type":"string","format":"date-time"}}],"responses":{"200":{"description":"Page of calls.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageCall"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createCall","tags":["Calls"],"summary":"Trigger an outbound call","description":"Starts an outbound call. Provide exactly one of `assistant_id` or\n`assistant_phone` to select the assistant, and exactly one of `to` or\n`target_phone` for the destination number (`to` is preferred, `target_phone`\nis an alias retained for backwards compatibility).\n\nThis operation uses the per-key `outbound_trigger` bucket (60 requests\nper hour by default) and a separate one-outbound-call-per-assistant\ncooldown over a rolling 60-second window. A cooldown rejection is 429\n`rate_limit_exceeded` without `Retry-After`.\n\nIf the normalized destination exactly matches a caller-blocking entry\nassigned to the selected assistant, no call is created and the operation\nreturns 409 `outbound_target_blocked`. Caller-blocking lists and Assistant\nassignments are managed in Dashboard → Settings → Blocked callers; the\nPublic API does not expose caller-blocking configuration. Retrying the same\ndestination while it remains blocked returns the same rejection.\n","requestBody":{"required":true,"content":{"application/json":{"examples":{"assistantIdTo":{"summary":"Assistant ID and preferred destination field","value":{"assistant_id":"65a1234567890abcdef01234","to":"+12025550123"}},"assistantIdTargetPhone":{"summary":"Assistant ID and legacy destination field","value":{"assistant_id":"65a1234567890abcdef01234","target_phone":"+12025550123"}},"assistantPhoneTo":{"summary":"Assistant phone and preferred destination field","value":{"assistant_phone":"+12025550120","to":"+12025550123"}},"assistantPhoneTargetPhone":{"summary":"Assistant phone and legacy destination field","value":{"assistant_phone":"+12025550120","target_phone":"+12025550123"}}},"schema":{"$ref":"#/components/schemas/TriggerOutbound"}}}},"responses":{"201":{"description":"Call created and queued.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"type":"object","required":["call_id","assistant_id","assistant_phone","to","status","created_at"],"properties":{"call_id":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65f8fa6f1a9d8e0012ab34cd"},"assistant_id":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"},"assistant_phone":{"type":["string","null"],"pattern":"^\\+\\d{6,20}$","example":"+491701234567","description":"E.164 phone number of the assistant, or null if the assistant has no phone number."},"to":{"type":"string","pattern":"^\\+\\d{6,20}$","example":"+491701234999","description":"Normalized E.164 destination number."},"status":{"type":"string","example":"queued"},"created_at":{"type":"string","format":"date-time"}}}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"The normalized destination is blocked for the selected assistant.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"outbound_target_blocked","message":"The target phone number is blocked for this assistant"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/calls/{call_id}":{"parameters":[{"$ref":"#/components/parameters/CallId"}],"get":{"operationId":"getCall","tags":["Calls"],"summary":"Get a call with transcript, analyses, and notes","responses":{"200":{"description":"The call.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/CallDetail"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/calls/{call_id}/recording":{"parameters":[{"$ref":"#/components/parameters/CallId"}],"get":{"operationId":"getCallRecording","tags":["Calls"],"summary":"Download the call recording","description":"Returns the audio recording as a binary stream. Supports HTTP `Range`\nfor partial content. Returns 404 with JSON envelope when no recording\nexists for the call.\n","responses":{"200":{"description":"Audio stream. The actual `Content-Type` depends on the recording's\nstored format — current recordings are FLAC, legacy recordings may\nbe WAV. Clients should dispatch on the response `Content-Type` rather\nthan assuming a single format.\n","content":{"audio/flac":{"schema":{"type":"string","format":"binary"}},"audio/wav":{"schema":{"type":"string","format":"binary"}},"audio/mpeg":{"schema":{"type":"string","format":"binary"}}}},"206":{"description":"Partial content (byte range response)."},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteCallRecording","tags":["Calls"],"summary":"Permanently delete the call recording","description":"**Irreversible.** Erases every audio artifact of the call from object\nstorage — the master recording, both channel recordings, the playback\ntranscode and the waveform data — and reports success only after the\ndeletion has been verified. The call itself is kept: transcript,\nanalyses, notes, metadata and diagnostics are untouched, and the call\nkeeps appearing in `GET /calls`.\n\nAfterwards `recording.available` on the call is `false` and\n`GET /calls/{call_id}/recording` returns 404.\n\nRequires an API key whose role carries the `call_logs.call_recording`\ndelete permission; keys without it receive 403. Repeating the call on an\nalready-erased recording succeeds without changing anything, and a call\nthat never had a recording returns 404. A call that is still running, or\nwhose recording is still being processed, is rejected with 409 — retry\nonce the call has ended. A 500 means the audio was **not** fully removed\nand nothing was changed; the recording stays downloadable and the call is\nsafe to retry.\n","responses":{"200":{"description":"The recording was deleted and the deletion was verified.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"$ref":"#/components/responses/Conflict"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/statistics/summary":{"get":{"operationId":"getStatisticsSummary","tags":["Statistics"],"summary":"List available statistics filters","description":"Returns the filter values that populate statistics dashboards:\nevery (week, year) pair that has at least one completed call in the\norganization, plus every assistant in the organization. The `all`\nassistant sentinel is **not** returned — clients can always pass\n`assistant_id=all` to the `/usage` endpoint regardless of this list.\n","responses":{"200":{"description":"Filter values.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StatisticsSummary"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/statistics/usage":{"get":{"operationId":"getStatisticsUsage","tags":["Statistics"],"summary":"Usage breakdown for a week + assistant filter","description":"Returns the monthly + weekly + last-24h breakdown for the selected\nweek/year window. `assistant_id=all` aggregates across every assistant;\npassing a concrete 24-hex ID filters to that assistant's calls only.\nSupplying an ID that does not belong to the caller's organization\nreturns 404.\n\nAll duration fields are integer **seconds** (billable, with 60s minimum\nper call), not minutes. `hourly_call_counts_last_24h` always reflects\nthe 24h window ending at request time — it ignores the `week`/`year`\nfilter.\n","parameters":[{"name":"week","in":"query","required":true,"schema":{"type":"integer","minimum":1,"maximum":53,"example":17},"description":"ISO week number (1–53)."},{"name":"year","in":"query","required":true,"schema":{"type":"integer","minimum":2020,"maximum":2100,"example":2026}},{"name":"assistant_id","in":"query","required":true,"description":"Either the sentinel `all` or a 24-hex assistant id.","schema":{"oneOf":[{"type":"string","enum":["all"]},{"type":"string","pattern":"^[a-f0-9]{24}$"}]},"examples":{"all":{"value":"all","summary":"Aggregate across every assistant"},"one":{"value":"65a1234567890abcdef01234","summary":"Filter to one assistant"}}}],"responses":{"200":{"description":"Usage breakdown.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StatisticsUsage"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"description":"The supplied `assistant_id` does not exist in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Assistant not found"}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/statistics/assistants":{"get":{"operationId":"getStatisticsAssistants","tags":["Statistics"],"summary":"Per-assistant usage for a week","description":"Returns one breakdown row per assistant that had at least one completed\ncall in the selected week. Includes assistants that have since been\ndeleted — their calls still count and the row carries `is_deleted: true`.\nAll duration fields are integer seconds (billable, with 60s minimum).\n","parameters":[{"name":"week","in":"query","required":true,"schema":{"type":"integer","minimum":1,"maximum":53,"example":17}},{"name":"year","in":"query","required":true,"schema":{"type":"integer","minimum":2020,"maximum":2100,"example":2026}}],"responses":{"200":{"description":"Per-assistant usage.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/StatisticsAssistantsUsage"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/tools":{"get":{"operationId":"listTools","tags":["Tools"],"summary":"List tools (paginated)","description":"Returns the organization's custom tools, ordered by `created_at` DESC.\nAuth configuration is summarized — the stored secret value is never\nreturned; `auth.has_secret` indicates whether a credential is set.\n","parameters":[{"$ref":"#/components/parameters/Cursor"},{"$ref":"#/components/parameters/LimitDefault"}],"responses":{"200":{"description":"Page of tools.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/PageTool"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"post":{"operationId":"createTool","tags":["Tools"],"summary":"Create a tool","description":"Creates a new webhook-type tool. `tool_key` must be unique within your\norganization; reuse returns 409. Auth secrets are stored AES-256-GCM\nencrypted and are never returned — submit them on create / PATCH to set\nor rotate. Integration-type tools must be created via the dashboard\n(OAuth flow) and cannot be created through the public API in v1.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolCreate"}}}},"responses":{"201":{"description":"Created.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tool"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"409":{"description":"A tool with the requested `tool_key` already exists in this organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"A tool with that tool_key already exists."}}}}},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/tools/{tool_id}":{"parameters":[{"$ref":"#/components/parameters/ToolId"}],"get":{"operationId":"getTool","tags":["Tools"],"summary":"Get a tool","responses":{"200":{"description":"The tool.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tool"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"patch":{"operationId":"updateTool","tags":["Tools"],"summary":"Update a tool","description":"Partial update — only included fields are changed. `tool_key` and\n`execution_type` are immutable (create a new tool instead). To rotate\nan auth secret, submit a full `auth` object with the new value; the\nprevious secret is overwritten in place.\n","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/ToolUpdate"}}}},"responses":{"200":{"description":"Updated tool.","content":{"application/json":{"schema":{"type":"object","properties":{"data":{"$ref":"#/components/schemas/Tool"}}}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}},"delete":{"operationId":"deleteTool","tags":["Tools"],"summary":"Delete a tool","description":"Deletes the tool and removes its `_id` from any assistant's `tool_ids`\nlist so no assistant is left referencing a missing tool.\n","responses":{"200":{"description":"Deleted.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/EmptySuccess"}}}},"400":{"$ref":"#/components/responses/ValidationFailed"},"401":{"$ref":"#/components/responses/Unauthorized"},"402":{"$ref":"#/components/responses/SubscriptionRequired"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}}},"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","description":"API key in the `Authorization: Bearer <key>` header.\nKeys are created in the smao dashboard (*Settings → API Keys*).\n"}},"headers":{"XRateLimitLimit":{"description":"Maximum requests allowed in the current window for this bucket.","schema":{"type":"integer","example":1000}},"XRateLimitRemaining":{"description":"Requests remaining in the current window.","schema":{"type":"integer","example":997}},"XRateLimitReset":{"description":"Unix timestamp (seconds) when the window resets.","schema":{"type":"integer","example":1776902940}},"RetryAfter":{"description":"Seconds to wait before retrying after a 429 response.","schema":{"type":"integer","example":60}}},"parameters":{"Cursor":{"name":"cursor","in":"query","description":"Opaque cursor from a prior `meta.next_cursor`. Base64url-encoded\n(unpadded) — do not parse or construct it manually.\n","schema":{"type":"string","pattern":"^[A-Za-z0-9_-]+$"}},"Limit200":{"name":"limit","in":"query","description":"Items per page (1–200, default 50).","schema":{"type":"integer","minimum":1,"maximum":200,"default":50}},"LimitDefault":{"name":"limit","in":"query","description":"Items per page (1–100, default 50).","schema":{"type":"integer","minimum":1,"maximum":100,"default":50}},"LimitCalls":{"name":"limit","in":"query","description":"Items per page (1–100, default 25).","schema":{"type":"integer","minimum":1,"maximum":100,"default":25}},"ContactId":{"name":"contact_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"GroupId":{"name":"group_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"KnowledgeItemId":{"name":"knowledge_item_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"PromptId":{"name":"prompt_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"AssistantId":{"name":"assistant_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"ForwardingId":{"name":"forwarding_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"GlossaryId":{"name":"glossary_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"PronunciationId":{"name":"pronunciation_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"CalendarId":{"name":"calendar_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"CallId":{"name":"call_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"ToolId":{"name":"tool_id","in":"path","required":true,"example":"65f8fa6f1a9d8e0012ab34cd","schema":{"type":"string","pattern":"^[a-f0-9]{24}$"}}},"responses":{"Unauthorized":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"unauthorized","message":"Missing API key"}}}}},"Forbidden":{"description":"The API key's role lacks permission for this action.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"forbidden","message":"No permission"}}}}},"NotFound":{"description":"Resource not found.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"not_found","message":"Not found"}}}}},"ValidationFailed":{"description":"Request body or query parameters failed validation.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"validation_failed","message":"Validation failed"}}}}},"Conflict":{"description":"Resource is in use or the operation would violate an invariant.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"conflict","message":"Group is assigned to an assistant"}}}}},"RateLimited":{"description":"Rate limit exceeded. Bucket exhaustion includes the rate-limit headers and `Retry-After`. The separate outbound per-assistant cooldown, or a fail-closed limiter-storage error, uses the same 429/code without `Retry-After`; a storage error may omit all rate-limit headers.","headers":{"X-RateLimit-Limit":{"$ref":"#/components/headers/XRateLimitLimit"},"X-RateLimit-Remaining":{"$ref":"#/components/headers/XRateLimitRemaining"},"X-RateLimit-Reset":{"$ref":"#/components/headers/XRateLimitReset"},"Retry-After":{"$ref":"#/components/headers/RetryAfter"}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"rate_limit_exceeded","message":"Rate limit exceeded"}}}}},"SubscriptionRequired":{"description":"A feature required by this endpoint is not enabled for the organization.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"subscription_required","message":"This feature is not available in your current subscription. Please upgrade to a higher plan"}}}}},"InternalError":{"description":"Unexpected server error. The operation did not complete. Safe to retry\nidempotent reads; for mutations, check the resource state before retrying.\n","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"error":{"code":"internal_error","message":"An unexpected error occurred."}}}}}},"schemas":{"Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string","enum":["unauthorized","forbidden","not_found","validation_failed","conflict","outbound_target_blocked","rate_limit_exceeded","subscription_required","internal_error"]},"message":{"type":"string"},"details":{"type":"array","description":"Optional validation details. Present only for schema/model validation failures.","items":{"type":"object","properties":{"path":{"type":"array","items":{"type":["string","integer"]}},"message":{"type":"string"}}}}}}}},"EmptySuccess":{"type":"object","properties":{"data":{"type":"object","description":"Empty — present for envelope consistency."}}},"PageMeta":{"type":"object","required":["has_more","next_cursor"],"properties":{"has_more":{"type":"boolean"},"next_cursor":{"type":["string","null"],"description":"Opaque cursor for the next page, or `null` on the last page."}}},"Contact":{"type":"object","required":["id","group_id","group_name","phone_numbers","first_name","last_name","email","company","gender","prompt","preferred_language","forwarding_id","created_at","updated_at"],"properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"group_id":{"type":["string","null"],"example":"65a1234567890abcdef01234","description":"`null` for legacy or orphaned records with no group. Deleting a contacts group through this API deletes its contacts rather than clearing their group reference."},"group_name":{"type":["string","null"],"example":"VIP Customers"},"phone_numbers":{"type":"array","items":{"type":"string","example":"+491701234567"}},"first_name":{"type":"string","example":"Ada"},"last_name":{"type":"string","example":"Lovelace"},"email":{"type":"string","example":"ada@example.com"},"company":{"type":"string","example":"Analytical Engine Inc"},"gender":{"type":"string","example":"female","description":"Empty string means the contact's gender is not specified."},"prompt":{"type":"string","description":"Optional per-contact prompt fragment."},"preferred_language":{"type":"string","example":"en"},"forwarding_id":{"type":["string","null"],"example":"65a1234567890abcdef09999"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ContactCreate":{"type":"object","required":["group_id","phone_numbers"],"additionalProperties":false,"example":{"group_id":"65a1234567890abcdef01234","phone_numbers":["+12025550123"],"first_name":"Ada","last_name":"Lovelace"},"properties":{"group_id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"phone_numbers":{"type":"array","minItems":1,"items":{"type":"string","minLength":1,"example":"+491701234567"}},"first_name":{"type":"string","default":""},"last_name":{"type":"string","default":""},"email":{"type":"string","format":"email","default":"","description":"Email address. Empty string is accepted if you don't have the contact's email."},"company":{"type":"string","default":""},"prompt":{"type":"string","default":""},"preferred_language":{"type":"string","enum":["de","en","fr","it","de-CH","es","pt","tr","sv","fi","unknown"],"example":"en"},"gender":{"type":"string","default":"","description":"Optional gender value. Omit it or send an empty string when not specified."},"forwarding_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$","default":null}}},"ContactUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"description":"Partial update — include only the fields you want to change.","example":{"first_name":"Grace"},"properties":{"group_id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"phone_numbers":{"type":"array","minItems":1,"items":{"type":"string","minLength":1}},"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string","format":"email","description":"Email address. Empty string is accepted if you don't have the contact's email."},"company":{"type":"string"},"prompt":{"type":"string"},"preferred_language":{"type":"string","enum":["de","en","fr","it","de-CH","es","pt","tr","sv","fi","unknown"]},"gender":{"type":"string","description":"Send an empty string to clear the value; omit the property to preserve it."},"forwarding_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$"}}},"PageContact":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Contact"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"Group":{"type":"object","required":["id","type","name","description","created_at","updated_at"],"properties":{"id":{"type":"string"},"type":{"type":"string","enum":["contacts","knowledges","forwardings","glossaries","pronunciations"]},"name":{"type":"string","example":"VIP Customers"},"description":{"type":"string"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"GroupCreate":{"type":"object","required":["type","name"],"additionalProperties":false,"example":{"type":"contacts","name":"Priority Customers"},"properties":{"type":{"type":"string","enum":["contacts","knowledges","forwardings","glossaries","pronunciations"]},"name":{"type":"string","minLength":1,"maxLength":200,"description":"Trimmed of leading/trailing whitespace before storage."},"description":{"type":"string","maxLength":500,"default":""}}},"GroupUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"example":{"name":"Enterprise Customers"},"properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Trimmed of leading/trailing whitespace before storage."},"description":{"type":"string","maxLength":500}}},"PageGroup":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Group"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"KnowledgeItemSyncStatus":{"type":"object","required":["state","synced_at","total_chunks","estimated_duration_ms","error"],"properties":{"state":{"type":"string","enum":["pending","syncing","synced","failed"],"description":"Indexing status."},"synced_at":{"type":["string","null"],"format":"date-time"},"total_chunks":{"type":["integer","null"]},"estimated_duration_ms":{"type":["integer","null"]},"error":{"type":["string","null"]}}},"KnowledgeItem":{"type":"object","description":"Summary shape — `text` is omitted; use the detail endpoint for full body.","required":["id","group_id","name","active","text_length","sync_status","created_at","updated_at"],"properties":{"id":{"type":"string"},"group_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"},"name":{"type":"string","example":"Shipping Policy"},"active":{"type":"boolean"},"text_length":{"type":"integer","maximum":5000000,"description":"Character count of the stored `text` body."},"sync_status":{"$ref":"#/components/schemas/KnowledgeItemSyncStatus"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"KnowledgeItemDetail":{"allOf":[{"$ref":"#/components/schemas/KnowledgeItem"},{"type":"object","required":["text"],"properties":{"text":{"type":"string"}}}]},"KnowledgeItemCreate":{"type":"object","required":["group_id","name","text"],"additionalProperties":false,"example":{"group_id":"65a1234567890abcdef01234","name":"Shipping Policy","text":"Orders ship within two business days."},"properties":{"group_id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"name":{"type":"string","minLength":1,"maxLength":200,"description":"Trimmed of leading/trailing whitespace before storage."},"text":{"type":"string","minLength":1,"maxLength":5000000},"active":{"type":"boolean","default":true}}},"KnowledgeItemUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"example":{"name":"International Shipping Policy"},"properties":{"group_id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"name":{"type":"string","minLength":1,"maxLength":200,"description":"Trimmed of leading/trailing whitespace before storage."},"text":{"type":"string","minLength":1,"maxLength":5000000},"active":{"type":"boolean"}}},"PageKnowledgeItem":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/KnowledgeItem"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"Prompt":{"type":"object","required":["id","name","description","prompt","type","health_score","approved","feedback","rated_at","rating_status","created_at","updated_at"],"description":"A reusable assistant prompt. When automated prompt rating is enabled\nfor the deployment, every save (POST/PATCH) runs deterministic checks\nbefore any LLM review.\nThe rating fields (`health_score`, `approved`, `feedback`, `rated_at`,\n`rating_status`) are read-only — create/update requests reject them —\nand follow one of these `rating_status` lifecycles:\n\n- Blocking deterministic defect: `null` → `\"rated\"` immediately, with\n  `health_score: 0`, `approved: false`, localized feedback, and no\n  semantic rating request. Prompt-language detection may run first.\n- Otherwise: `null` → `\"pending\"` (queued/in-flight) → `\"rated\"` or\n  `\"failed\"` after asynchronous LLM review.\n\nWhen changed prompt content enters `\"pending\"`, stale rating fields are\ncleared instead of being shown for the new content. On `\"failed\"`, all\nrating fields except `rating_status` are cleared — the next save\nenqueues a fresh attempt. When rating is disabled,\n`rating_status`, `health_score`, `approved`, and `rated_at` remain\n`null`, and `feedback` remains an empty string.\n","properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"name":{"type":"string","example":"Sales — Initial Outreach"},"description":{"type":"string","example":"Opening prompt for cold outbound calls."},"prompt":{"type":"string","description":"The full prompt body passed to the assistant."},"type":{"type":"string","enum":["answering","email"],"description":"Prompt kind — `answering` for voice/chat, `email` for email replies."},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"},"health_score":{"type":["integer","null"],"minimum":0,"maximum":10,"example":8,"description":"Automated quality score from 0–10. `0` is reserved for a blocking\ndeterministic rule; the LLM judge returns only 1–10. `null` until\nthe first rating completes, and after a failed rating attempt.\n"},"approved":{"type":["boolean","null"],"example":true,"description":"Whether the review considers the prompt production-ready.\nA deterministic score of `0` is always `false`. For LLM ratings,\napproval is independent of `health_score` — a prompt does not need\na perfect score to be approved.\n"},"feedback":{"type":"string","example":"The prompt follows the template exactly and is production-ready. No changes required.","description":"Review feedback. All natural-language feedback is written in the\ndominant supported language detected from the current prompt.\nRequest locale and assistant language do not select this language,\nand unsupported or unclassifiable prompts fail with empty feedback\ninstead of falling back to another language. Empty string until the\nfirst rating completes, while changed content is pending, and after\na failed rating attempt.\n"},"rated_at":{"type":["string","null"],"format":"date-time","description":"When the latest rating completed. `null` until the first rating completes, and after a failed attempt."},"rating_status":{"type":["string","null"],"enum":[null,"pending","rated","failed"],"example":"rated","description":"Rating lifecycle status:\n- `null` — never rated, or automated rating is disabled.\n- `\"pending\"` — save accepted, review queued or in flight. Rating fields are cleared when prompt content changed or the previous result was not language-verified.\n- `\"rated\"` — deterministic or LLM review complete; `health_score` / `approved` / `feedback` populated.\n- `\"failed\"` — review attempt failed. All other rating fields are cleared; the next save enqueues a fresh attempt.\n"}}},"PromptCreate":{"type":"object","required":["name","prompt"],"additionalProperties":false,"example":{"name":"Reception","prompt":"Answer customer questions clearly and concisely."},"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"prompt":{"type":"string","minLength":1,"maxLength":100000},"description":{"type":"string","maxLength":2000,"default":""},"type":{"type":"string","enum":["answering","email"],"default":"answering"}}},"PromptUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"description":"Partial update — include only the fields you want to change.","example":{"description":"Reception prompt for inbound customer calls."},"properties":{"name":{"type":"string","minLength":1,"maxLength":200},"prompt":{"type":"string","minLength":1,"maxLength":100000},"description":{"type":"string","maxLength":2000},"type":{"type":"string","enum":["answering","email"]}}},"PagePrompt":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Prompt"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"Voice":{"type":"object","required":["id","name","languages","gender","version"],"additionalProperties":false,"properties":{"id":{"type":"string","minLength":1,"description":"Voice ID to send as `voice_id` when creating or updating an assistant.","example":"1887"},"name":{"type":"string","minLength":1,"example":"Celine Weber"},"languages":{"type":"array","minItems":1,"uniqueItems":true,"items":{"type":"string","enum":["de","en","fr","it","de-CH","es","pt","tr","sv","fi"]},"example":["de"]},"gender":{"type":"string","enum":["female","male","neutral"],"example":"female"},"version":{"type":"string","enum":["v1","v2"],"description":"Voice version shown in the dashboard (`v1` or `v2`).","example":"v2"}}},"PreCallWebhook":{"type":["object","null"],"additionalProperties":false,"required":["enabled","url","method","headers","body_template","auth","timeout_ms"],"description":"Credential-free pre-call lookup configuration, or null if unconfigured.\nThe lookup runs in the background at call initialization for inbound and\noutbound calls. Use `@preCallData` in the assigned prompt; prompts are\nnever edited automatically. Execution is best-effort: disabled, failed,\ntimed-out or busy requests contribute an empty value, and there are no\nretries. Each prompt render may wait up to 400 ms while the lookup is\npending; once settled, the response is cached for later turns. Responses\nare bounded to 256 KiB and the injected text to 4000 characters.\n","example":{"enabled":true,"url":"https://crm.example.com/lookup","method":"POST","headers":{"X-Caller":"@callerNumber"},"body_template":"{\"caller\":\"@callerNumber\",\"session\":\"@sessionId\"}","timeout_ms":5000,"auth":{"type":"bearer"}},"properties":{"enabled":{"type":"boolean","description":"False disables execution without removing the stored configuration or credentials."},"url":{"type":["string","null"],"maxLength":2000,"description":"HTTPS endpoint, required and nonempty when enabled. URLs are not templated. Runtime SSRF protection blocks private destinations and redirects."},"method":{"type":"string","enum":["GET","POST"],"description":"Defaults to POST on first configuration. GET sends no body; use templated headers for lookup parameters."},"headers":{"type":["object","null"],"maxProperties":50,"propertyNames":{"maxLength":200,"pattern":"^[A-Za-z0-9!#$%&'*+.^_`|~-]+$"},"additionalProperties":{"type":"string","minLength":1,"maxLength":2000},"description":"Custom header values support the body_template variables. Names are literal. A supplied map replaces all custom headers; null clears them. Use auth for credentials, not this readable map."},"body_template":{"type":"string","maxLength":50000,"description":"JSON/text template for POST. Empty (the default) sends the standard\nlookup payload. GET ignores this field. Supported variables:\n`@callerNumber`, `@assistantNumber`, `@direction`, `@assistantId`,\n`@assistantName`, `@organizationId`, `@sessionId`, `@language`.\nThe default payload uses those names without the @ prefix.\nCaller means the human in either call direction.\n"},"timeout_ms":{"type":"integer","minimum":500,"maximum":15000,"description":"Request timeout in milliseconds; defaults to 5000 on first configuration. The runner also bounds elapsed waiting to this value plus 500 ms."},"auth":{"type":["object","null"],"additionalProperties":false,"required":["type"],"description":"Only fields relevant to the auth type are returned. Secret and password are never returned, including as ciphertext.","properties":{"type":{"type":"string","enum":["none","apiKey","bearer","basic"]},"header_name":{"type":"string","minLength":1,"maxLength":200,"description":"apiKey only; omitted means x-api-key."},"username":{"type":"string","minLength":1,"maxLength":200,"description":"Basic auth only."}}}}},"PreCallWebhookAuthInput":{"description":"Omit auth on PATCH to retain it; null clears authentication. Secrets and\npasswords are write-only and always encrypted. A new configuration or\nauth-type change requires the corresponding credential. On a same-type\nPATCH, omission keeps the stored credential. Bearer uses Authorization;\napiKey defaults to x-api-key when header_name is omitted.\n","oneOf":[{"title":"No authentication","type":"null"},{"title":"None","type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string","const":"none"}}},{"title":"API key","type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string","const":"apiKey"},"header_name":{"type":"string","minLength":1,"maxLength":200,"pattern":"\\S"},"secret":{"type":"string","minLength":1,"maxLength":4000,"writeOnly":true}}},{"title":"Bearer","type":"object","additionalProperties":false,"required":["type"],"properties":{"type":{"type":"string","const":"bearer"},"secret":{"type":"string","minLength":1,"maxLength":4000,"writeOnly":true}}},{"title":"Basic","type":"object","additionalProperties":false,"required":["type","username"],"properties":{"type":{"type":"string","const":"basic"},"username":{"type":"string","minLength":1,"maxLength":200},"password":{"type":"string","minLength":1,"maxLength":4000,"writeOnly":true}}}]},"PreCallWebhookUrl":{"type":"string","format":"uri","maxLength":2000,"pattern":"^[Hh][Tt][Tt][Pp][Ss]://(?:[^/?#@]*@)?(?:\\[[^\\]]+\\]|[^:/?#@\\[\\]]+)(?::[0-9]*)?(?:[/?#]|$)"},"PreCallWebhookInput":{"type":["object","null"],"additionalProperties":false,"required":["enabled"],"description":"Null clears the configuration. A supplied object requires enabled and,\nwhen enabled, a nonempty HTTPS url. Any supplied nonempty url must be\nvalid HTTPS even when disabled; disabled configurations also accept\nnull or an empty string. A host is required, ports must be numeric,\nand percent escapes must contain two hexadecimal digits. String length\nlimits count Unicode characters. Other omitted fields preserve their\nvalues on PATCH. Initial defaults are POST, empty headers/body template, no\nauthentication and 5000 ms. See PreCallWebhook for runtime behavior.\n","properties":{"enabled":{"$ref":"#/components/schemas/PreCallWebhook/properties/enabled"},"url":{"description":"Nonempty values must be valid HTTPS URLs, even when disabled. Null or an empty string clears the URL only when disabled; omission preserves it on PATCH.","anyOf":[{"type":["string","null"],"enum":["",null]},{"$ref":"#/components/schemas/PreCallWebhookUrl"}]},"method":{"$ref":"#/components/schemas/PreCallWebhook/properties/method"},"headers":{"$ref":"#/components/schemas/PreCallWebhook/properties/headers"},"body_template":{"$ref":"#/components/schemas/PreCallWebhook/properties/body_template"},"timeout_ms":{"$ref":"#/components/schemas/PreCallWebhook/properties/timeout_ms"},"auth":{"$ref":"#/components/schemas/PreCallWebhookAuthInput"}},"allOf":[{"if":{"type":"object","additionalProperties":true,"required":["enabled"],"properties":{"enabled":{"const":true}}},"then":{"additionalProperties":true,"required":["url"],"properties":{"url":{"$ref":"#/components/schemas/PreCallWebhookUrl"}}}}]},"Assistant":{"type":"object","required":["id","name","description","language","voice_id","record_call","speed","tts_style_level","background_ambience","interruptable","appointment_booking_enabled","contextual_asr_correction_enabled","allow_preferred_language","whitelist","introduction","company_name","company_industry","phone_number","carrier","prompt_id","email_prompt_id","knowledge_group_ids","glossary_group_ids","pronunciation_group_ids","forwarding_group_ids","contact_group_ids","calendar_ids","tool_ids","analysis_ids","pre_call_webhook","created_at","updated_at"],"properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"name":{"type":"string","example":"Sarah"},"description":{"type":"string","example":"Receptionist assistant for inbound calls."},"language":{"type":"string","enum":["de","en","fr","it","de-CH","es","pt","tr","sv","fi"],"example":"de"},"voice_id":{"type":"string","example":"cgSgspJ2msm6clMCkdW9","description":"Current voice ID. `GET /voices` returns IDs selectable for new assignments; an existing legacy ID can appear here but is not selectable."},"record_call":{"type":"boolean"},"speed":{"type":"number","minimum":0.7,"maximum":1.2,"description":"Voice playback rate multiplier. Some voices only support 0.8–1.2; out-of-range values for such voices return 400."},"tts_style_level":{"type":"number","minimum":0,"maximum":1,"multipleOf":0.01,"description":"Voice style level from 0 (calm) to 1 (expressive). The platform calibrates this level for the selected voice."},"background_ambience":{"type":"string","enum":["clean","office"],"description":"Background ambience bed mixed under the assistant voice during phone calls. \"clean\" plays no bed."},"interruptable":{"type":"boolean"},"appointment_booking_enabled":{"type":"boolean"},"contextual_asr_correction_enabled":{"type":"boolean","description":"Per-turn LLM correction of misrecognised proper nouns (names, companies, products) in caller transcripts, using the assistant's own contacts, employees, glossary and knowledge. Adds latency on turns that carry a candidate. Default false."},"allow_preferred_language":{"type":"boolean"},"whitelist":{"type":"boolean"},"introduction":{"type":"string","description":"The supported scalar API view of the canonical localized opening configuration. This is the text returned by the dashboard and used for newly initialized calls in the original language."},"company_name":{"type":"string"},"company_industry":{"type":"string"},"phone_number":{"type":["string","null"],"description":"Assigned by platform on create. Read-only — cannot be set or changed via this API.","example":"+491701234567"},"carrier":{"type":["string","null"],"description":"Telephony carrier assigned by the platform. Read-only."},"prompt_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"},"email_prompt_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef05678"},"knowledge_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"}},"glossary_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"}},"pronunciation_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"}},"forwarding_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"}},"contact_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"}},"calendar_ids":{"type":"array","maxItems":1,"items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"},"description":"At most one calendar per assistant."},"tool_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"},"description":"Webhook-type tools only. Integration-type / internal tools cannot be\nreferenced via the public API and will return 404 on create/update.\n"},"analysis_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"},"description":"Call-analysis definition IDs to run on this assistant's calls."},"pre_call_webhook":{"$ref":"#/components/schemas/PreCallWebhook"},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"AssistantCreate":{"type":"object","required":["name","language","voice_id","company_name","company_industry","introduction"],"additionalProperties":false,"example":{"name":"Sarah","language":"de","voice_id":"cgSgspJ2msm6clMCkdW9","company_name":"Example GmbH","company_industry":"Logistics","introduction":"Hello, how can I help you today?","pre_call_webhook":{"enabled":true,"url":"https://crm.example.com/lookup","auth":{"type":"bearer","secret":"example-only-token"}}},"properties":{"name":{"type":"string","minLength":1,"maxLength":100},"description":{"type":"string","maxLength":500,"default":""},"language":{"type":"string","enum":["de","en","fr","it","de-CH","es","pt","tr","sv","fi"],"description":"BCP-47-ish language code from the platform-supported list."},"voice_id":{"type":"string","description":"Voice ID. Must be one of the values returned by `GET /voices`; an unknown or unavailable ID returns 400."},"company_name":{"type":"string","minLength":1,"maxLength":200},"company_industry":{"type":"string","minLength":1,"maxLength":200},"introduction":{"type":"string","minLength":1,"maxLength":5000,"description":"Opening text in the assistant language. The platform stores it as the canonical original localized introduction and generates other supported-language variants asynchronously."},"record_call":{"type":"boolean"},"speed":{"type":"number","minimum":0.7,"maximum":1.2,"description":"Voice playback rate multiplier. Some voices only support 0.8–1.2; out-of-range values for such voices return 400."},"tts_style_level":{"type":"number","minimum":0,"maximum":1,"multipleOf":0.01,"description":"Voice style level from 0 (calm) to 1 (expressive). Omit to use 0.5."},"background_ambience":{"type":"string","enum":["clean","office"],"description":"Background ambience bed mixed under the assistant voice during phone calls. Omit to use clean (no bed)."},"interruptable":{"type":"boolean"},"appointment_booking_enabled":{"type":"boolean"},"contextual_asr_correction_enabled":{"type":"boolean","description":"Per-turn LLM correction of misrecognised proper nouns (names, companies, products) in caller transcripts, using the assistant's own contacts, employees, glossary and knowledge. Adds latency on turns that carry a candidate. Default false."},"allow_preferred_language":{"type":"boolean"},"whitelist":{"type":"boolean"},"prompt_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$"},"email_prompt_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$"},"knowledge_group_ids":{"type":"array","default":[],"items":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"}},"glossary_group_ids":{"type":"array","default":[],"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"pronunciation_group_ids":{"type":"array","default":[],"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"forwarding_group_ids":{"type":"array","default":[],"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"contact_group_ids":{"type":"array","default":[],"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"calendar_ids":{"type":"array","default":[],"maxItems":1,"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"tool_ids":{"type":"array","default":[],"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"analysis_ids":{"type":"array","default":[],"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"pre_call_webhook":{"$ref":"#/components/schemas/PreCallWebhookInput"}}},"AssistantUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"description":"Partial update — include only the fields you want to change.","example":{"description":"Handles first-line customer support calls."},"properties":{"name":{"type":"string","minLength":1,"maxLength":100},"description":{"type":"string","maxLength":500},"language":{"type":"string","enum":["de","en","fr","it","de-CH","es","pt","tr","sv","fi"]},"voice_id":{"type":"string","description":"Voice ID. Use a value returned by `GET /voices`. An existing legacy ID may remain unchanged, but changing to a legacy, unknown, or unavailable ID returns 400."},"company_name":{"type":"string","minLength":1,"maxLength":200},"company_industry":{"type":"string","minLength":1,"maxLength":200},"introduction":{"type":"string","minLength":1,"maxLength":5000,"description":"Replaces the canonical original opening text atomically. If `language` is omitted, the current original introduction language is retained; stale translations are discarded and regenerated asynchronously."},"record_call":{"type":"boolean"},"speed":{"type":"number","minimum":0.7,"maximum":1.2,"description":"Voice playback rate multiplier. Some voices only support 0.8–1.2; out-of-range values for such voices return 400."},"tts_style_level":{"type":"number","minimum":0,"maximum":1,"multipleOf":0.01,"description":"Voice style level from 0 (calm) to 1 (expressive)."},"background_ambience":{"type":"string","enum":["clean","office"],"description":"Background ambience bed mixed under the assistant voice during phone calls."},"interruptable":{"type":"boolean"},"appointment_booking_enabled":{"type":"boolean"},"contextual_asr_correction_enabled":{"type":"boolean","description":"Per-turn LLM correction of misrecognised proper nouns (names, companies, products) in caller transcripts, using the assistant's own contacts, employees, glossary and knowledge. Adds latency on turns that carry a candidate. Default false."},"allow_preferred_language":{"type":"boolean"},"whitelist":{"type":"boolean"},"prompt_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$"},"email_prompt_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$"},"knowledge_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"glossary_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"pronunciation_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"forwarding_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"contact_group_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"calendar_ids":{"type":"array","maxItems":1,"items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"tool_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$"},"description":"Webhook-type tools only. Integration-type / internal tools cannot be\nreferenced via the public API and will return 404 on create/update.\n"},"analysis_ids":{"type":"array","items":{"type":"string","pattern":"^[a-f0-9]{24}$"}},"pre_call_webhook":{"$ref":"#/components/schemas/PreCallWebhookInput"}}},"PageAssistant":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Assistant"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"DtmfSequenceItem":{"type":"object","required":["action"],"properties":{"action":{"type":"string","enum":["pause","dtmf"],"description":"Step kind:\n  - `pause` — pause for `duration` ms before the next step.\n  - `dtmf` — send the `digits` as DTMF tones.\n"},"duration":{"type":["integer","null"],"description":"Pause duration in milliseconds. Relevant when `action=pause`."},"digits":{"type":["string","null"],"description":"DTMF digit string to send. Relevant when `action=dtmf`."}}},"Forwarding":{"type":"object","required":["id","group_id","group_name","type","gender","job_title","first_name","last_name","email","competence","activation_keywords","destination_type","phone_number","sip_uri","sip_username","sip_refer_target","has_sip_credentials","active","fallback","timeout","dtmf_sequence","created_at","updated_at"],"properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"group_id":{"type":"string","example":"65a1234567890abcdef01234"},"group_name":{"type":["string","null"],"example":"Escalations"},"type":{"type":["string","null"],"enum":["personal","queue","fallback",null],"description":"Forwarding kind. `null` if unset."},"gender":{"type":"string","example":"female","description":"Empty string means the forwarding's gender is not specified."},"job_title":{"type":"string","example":"Head of Support"},"first_name":{"type":"string","example":"Ada"},"last_name":{"type":"string","example":"Lovelace"},"email":{"type":"string","example":"ada@example.com"},"competence":{"type":"string","example":"billing"},"activation_keywords":{"type":"array","description":"Optional per-forwarding activation keywords. When every active forwarding\nhas at least one custom activation keyword, generic transfer words are\nnot used for forwarding activation.\n","items":{"type":"string","maxLength":80},"maxItems":50},"destination_type":{"type":"string","enum":["phone","sip","sip_refer"],"description":"Where the call routes — an E.164 phone number, SIP URI, or SIP REFER target."},"phone_number":{"type":"string","example":"+491701234567","description":"Destination number for `phone` forwarding. May be an empty string when it was omitted at write time; such a target cannot be dialed."},"sip_uri":{"type":"string","description":"SIP URI in `sip:user@host` form. Relevant when `destination_type=sip`.","example":"sip:forwarding@example.com"},"sip_username":{"type":["string","null"],"description":"Optional SIP auth username. Relevant when `destination_type=sip`."},"sip_refer_target":{"type":["string","null"],"description":"SIP REFER target. Relevant when `destination_type=sip_refer`."},"has_sip_credentials":{"type":["boolean","null"],"description":"Whether SIP credentials are stored for this forwarding. `sip_password` is never returned."},"identity_source":{"type":["string","null"],"enum":["employee",null],"description":"Read-only. `employee` marks a forwarding created by the employee import whose identity and destination follow the employee record; updates to those fields are rejected — edit the employee instead. `null` for hand-managed records."},"active":{"type":"boolean","default":true},"fallback":{"type":"boolean","default":false},"timeout":{"type":"integer","minimum":10,"maximum":60,"default":30,"description":"Ring timeout in seconds before the call gives up on this target."},"dtmf_sequence":{"type":["array","null"],"description":"Optional DTMF steps to run after the callee picks up. `null` if none configured.","items":{"$ref":"#/components/schemas/DtmfSequenceItem"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ForwardingCreateFields":{"type":"object","required":["group_id"],"additionalProperties":false,"properties":{"group_id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"type":{"type":"string","enum":["personal","queue","fallback"]},"destination_type":{"type":"string","enum":["phone","sip","sip_refer"],"default":"phone"},"gender":{"type":"string","description":"Optional gender value. Omit it or send an empty string when not specified."},"job_title":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"competence":{"type":"string"},"activation_keywords":{"type":"array","items":{"type":"string","maxLength":80},"maxItems":50},"phone_number":{"type":"string","example":"+12025550123"},"sip_uri":{"type":"string","pattern":"^sip:","description":"SIP URI. Required when `destination_type=sip`.","example":"sip:forwarding@example.com"},"sip_username":{"type":["string","null"],"description":"Optional SIP auth username. Only allowed when `destination_type=sip`."},"sip_password":{"type":["string","null"],"format":"password","description":"Optional SIP auth password. Only allowed when `destination_type=sip`; never returned in responses."},"sip_refer_target":{"type":"string","minLength":1,"pattern":"^\\S+$","description":"SIP REFER target. Required when `destination_type=sip_refer`."},"active":{"type":"boolean"},"fallback":{"type":"boolean"},"timeout":{"type":"integer","minimum":10,"maximum":60},"dtmf_sequence":{"type":"array","items":{"$ref":"#/components/schemas/DtmfSequenceItem"}}}},"ForwardingCreate":{"description":"When `destination_type` is `sip`, `sip_uri` must be provided. When\n`destination_type` is `sip_refer`, `sip_refer_target` must be provided.\nFor a usable `phone` destination, provide a non-empty `phone_number`.\nThe current validator permits it to be omitted or empty, but such a\nforwarding cannot be dialed.\n","oneOf":[{"title":"Phone destination","allOf":[{"$ref":"#/components/schemas/ForwardingCreateFields"},{"type":"object","properties":{"destination_type":{"type":"string","const":"phone"}},"not":{"anyOf":[{"properties":{"sip_username":{}},"required":["sip_username"]},{"properties":{"sip_password":{}},"required":["sip_password"]},{"properties":{"sip_refer_target":{}},"required":["sip_refer_target"]}]}}]},{"title":"SIP destination","allOf":[{"$ref":"#/components/schemas/ForwardingCreateFields"},{"type":"object","required":["destination_type","sip_uri"],"properties":{"destination_type":{"type":"string","const":"sip"}},"not":{"properties":{"sip_refer_target":{}},"required":["sip_refer_target"]}}]},{"title":"SIP REFER destination","allOf":[{"$ref":"#/components/schemas/ForwardingCreateFields"},{"type":"object","required":["destination_type","sip_refer_target"],"properties":{"destination_type":{"type":"string","const":"sip_refer"}},"not":{"anyOf":[{"properties":{"sip_username":{}},"required":["sip_username"]},{"properties":{"sip_password":{}},"required":["sip_password"]},{"properties":{"type":{"const":"personal"}},"required":["type"]}]}}]}]},"ForwardingUpdateFields":{"type":"object","minProperties":1,"additionalProperties":false,"properties":{"type":{"type":"string","enum":["personal","queue","fallback"]},"destination_type":{"type":"string","enum":["phone","sip","sip_refer"]},"gender":{"type":"string","description":"Send an empty string to clear the value; omit the property to preserve it."},"job_title":{"type":"string"},"first_name":{"type":"string"},"last_name":{"type":"string"},"email":{"type":"string"},"competence":{"type":"string"},"activation_keywords":{"type":"array","items":{"type":"string","maxLength":80},"maxItems":50},"phone_number":{"type":"string"},"sip_uri":{"type":"string","pattern":"^sip:"},"sip_username":{"type":["string","null"],"description":"Optional SIP auth username. Only allowed when the effective `destination_type` is `sip`."},"sip_password":{"type":["string","null"],"format":"password","description":"Optional SIP auth password. Only allowed when the effective `destination_type` is `sip`; never returned in responses."},"sip_refer_target":{"type":"string","minLength":1,"pattern":"^\\S+$","description":"SIP REFER target. Required when changing `destination_type` to `sip_refer`."},"active":{"type":"boolean"},"fallback":{"type":"boolean"},"timeout":{"type":"integer","minimum":10,"maximum":60},"dtmf_sequence":{"type":"array","items":{"$ref":"#/components/schemas/DtmfSequenceItem"}}}},"ForwardingUpdate":{"description":"Partial update — include only the fields you want to change.\n`group_id` cannot be changed via this endpoint.\n","oneOf":[{"title":"Other fields or stored SIP credentials","allOf":[{"$ref":"#/components/schemas/ForwardingUpdateFields"},{"type":"object","not":{"anyOf":[{"properties":{"destination_type":{}},"required":["destination_type"]},{"properties":{"sip_refer_target":{}},"required":["sip_refer_target"]}]}}]},{"title":"Phone destination","allOf":[{"$ref":"#/components/schemas/ForwardingUpdateFields"},{"type":"object","required":["destination_type"],"properties":{"destination_type":{"type":"string","const":"phone"}},"not":{"anyOf":[{"properties":{"sip_username":{}},"required":["sip_username"]},{"properties":{"sip_password":{}},"required":["sip_password"]},{"properties":{"sip_refer_target":{}},"required":["sip_refer_target"]}]}}]},{"title":"SIP destination","allOf":[{"$ref":"#/components/schemas/ForwardingUpdateFields"},{"type":"object","required":["destination_type"],"properties":{"destination_type":{"type":"string","const":"sip"}},"not":{"properties":{"sip_refer_target":{}},"required":["sip_refer_target"]}}]},{"title":"SIP REFER destination","allOf":[{"$ref":"#/components/schemas/ForwardingUpdateFields"},{"type":"object","required":["destination_type","sip_refer_target"],"properties":{"destination_type":{"type":"string","const":"sip_refer"}},"not":{"anyOf":[{"properties":{"sip_username":{}},"required":["sip_username"]},{"properties":{"sip_password":{}},"required":["sip_password"]},{"properties":{"type":{"const":"personal"}},"required":["type"]}]}}]}]},"PageForwarding":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Forwarding"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"Glossary":{"type":"object","required":["id","group_id","group_name","abbreviation","name","description","active","created_at","updated_at"],"properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"group_id":{"type":"string","example":"65a1234567890abcdef01234"},"group_name":{"type":["string","null"],"example":"Product terminology"},"abbreviation":{"type":"string","example":"API"},"name":{"type":"string","example":"Application Programming Interface"},"description":{"type":"string","example":"A set of definitions and protocols for building software."},"active":{"type":"boolean","default":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"GlossaryCreate":{"type":"object","required":["group_id","name"],"additionalProperties":false,"example":{"group_id":"65a1234567890abcdef01234","name":"Application Programming Interface","abbreviation":"API"},"properties":{"group_id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"name":{"type":"string","minLength":1,"maxLength":200,"description":"Whitespace is trimmed; the trimmed name must be at least 1 character."},"abbreviation":{"type":"string","maxLength":100,"default":""},"description":{"type":"string","maxLength":5000,"default":""},"active":{"type":"boolean","default":true}}},"GlossaryUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"description":"Partial update — include only the fields you want to change.\n`group_id` cannot be changed via this endpoint.\n","example":{"description":"A set of definitions and protocols for building software."},"properties":{"name":{"type":"string","minLength":1,"maxLength":200,"description":"Whitespace is trimmed; the trimmed name must be at least 1 character."},"abbreviation":{"type":"string","maxLength":100},"description":{"type":"string","maxLength":5000},"active":{"type":"boolean"}}},"PageGlossary":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Glossary"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"Pronunciation":{"type":"object","required":["id","group_id","group_name","word","replacement","ipa","spell_out","rate","case_sensitive","active","created_at","updated_at"],"properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"group_id":{"type":"string","example":"65a1234567890abcdef01234"},"group_name":{"type":["string","null"],"example":"Brand names"},"word":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\s<>]+$","example":"smao","description":"The written single-token form to match in generated speech. Whitespace and angle brackets (`<`, `>`) are rejected."},"replacement":{"type":"string","example":"ess-mao","description":"Phonetic respelling spoken in place of the word."},"ipa":{"type":"string","example":"ɛsmaʊ","description":"International Phonetic Alphabet transcription. Applied on v2 voices; ignored on v1 voices."},"spell_out":{"type":"boolean","default":false,"description":"When true, the matched word is spoken letter by letter — `API` is spoken as `A`, `P`, `I`."},"rate":{"type":["string","null"],"enum":[null,"slow","medium","fast"],"default":null,"description":"Speaking-rate override applied when the word is spoken. `null` inherits the voice/request speed; `medium` is explicit normal speed. Applied on v2 voices; ignored on v1 voices."},"case_sensitive":{"type":"boolean","default":false},"active":{"type":"boolean","default":true},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"PronunciationCreate":{"type":"object","required":["group_id","word"],"additionalProperties":false,"example":{"group_id":"65a1234567890abcdef01234","word":"SMAO","spell_out":true},"properties":{"group_id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"word":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\s<>]+$","description":"The written single-token form to match. Whitespace and angle\nbrackets (`<`, `>`) are rejected.\n"},"replacement":{"type":"string","maxLength":1000,"default":"","description":"Phonetic respelling. Angle brackets (`<`, `>`) are rejected. Must be empty when `spell_out` is true."},"ipa":{"type":"string","maxLength":1000,"default":"","description":"International Phonetic Alphabet transcription. Applied on v2 voices; ignored on v1 voices. Must be empty when `spell_out` is true."},"spell_out":{"type":"boolean","default":false,"description":"When true, the matched word is spoken letter by letter — `API` is spoken as `A`, `P`, `I`."},"rate":{"type":["string","null"],"enum":[null,"slow","medium","fast"],"default":null,"description":"Speaking-rate override. `null` inherits the voice/request speed; `medium` is explicit normal speed."},"case_sensitive":{"type":"boolean","default":false},"active":{"type":"boolean","default":true}}},"PronunciationUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"description":"Partial update — include only the fields you want to change.\n`group_id` cannot be changed via this endpoint.\nThe final merged state must not combine `spell_out: true` with a\nnon-empty `replacement` or `ipa`.\n","example":{"case_sensitive":true},"properties":{"word":{"type":"string","minLength":1,"maxLength":200,"pattern":"^[^\\s<>]+$","description":"The written single-token form to match. Whitespace and angle\nbrackets (`<`, `>`) are rejected.\n"},"replacement":{"type":"string","maxLength":1000,"description":"Angle brackets (`<`, `>`) are rejected. Must be empty when the final `spell_out` state is true."},"ipa":{"type":"string","maxLength":1000,"description":"International Phonetic Alphabet transcription. Applied on v2 voices; ignored on v1 voices. Must be empty when the final `spell_out` state is true."},"spell_out":{"type":"boolean","description":"When true, the matched word is spoken letter by letter — `API` is spoken as `A`, `P`, `I`."},"rate":{"type":["string","null"],"enum":[null,"slow","medium","fast"],"description":"Speaking-rate override. Send `null` to return to the default inherited speed, or `medium` for an explicit normal-speed span."},"case_sensitive":{"type":"boolean"},"active":{"type":"boolean"}}},"PagePronunciation":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Pronunciation"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"CalendarSlot":{"type":"object","required":["from","to"],"additionalProperties":false,"properties":{"from":{"type":"string","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","example":"09:00"},"to":{"type":"string","pattern":"^([01][0-9]|2[0-3]):[0-5][0-9]$","example":"17:00"}}},"CalendarDaySchedule":{"type":"object","required":["is_open","slots"],"additionalProperties":false,"properties":{"is_open":{"type":"boolean"},"slots":{"type":"array","items":{"$ref":"#/components/schemas/CalendarSlot"}}}},"CalendarWeeklySchedule":{"type":"object","description":"Weekly opening-hours template. Each weekday is optional. Omitted\nweekdays (`mon`–`fri`) default to open 09:00–17:00; omitted weekend\ndays (`sat`–`sun`) default to closed with no slots. To close an omitted\nweekday explicitly, send `{ \"is_open\": false, \"slots\": [] }`.\nKeys use 3-letter day abbreviations: `mon`, `tue`, `wed`, `thu`, `fri`,\n`sat`, `sun`.\n","additionalProperties":false,"properties":{"mon":{"$ref":"#/components/schemas/CalendarDaySchedule"},"tue":{"$ref":"#/components/schemas/CalendarDaySchedule"},"wed":{"$ref":"#/components/schemas/CalendarDaySchedule"},"thu":{"$ref":"#/components/schemas/CalendarDaySchedule"},"fri":{"$ref":"#/components/schemas/CalendarDaySchedule"},"sat":{"$ref":"#/components/schemas/CalendarDaySchedule"},"sun":{"$ref":"#/components/schemas/CalendarDaySchedule"}}},"CalendarOverride":{"type":"object","required":["date","type"],"additionalProperties":false,"description":"Date-specific override — either closes the calendar for the day\n(`type: closed`) or replaces the day's slots (`type: modified`).\n`slots` is required (and must contain at least one entry) when\n`type` is `modified`; it is optional/omitted when `type` is `closed`.\n","properties":{"date":{"type":"string","pattern":"^[0-9]{4}-[0-9]{2}-[0-9]{2}$","example":"2026-12-24","description":"Date in `YYYY-MM-DD` shape. Send a real calendar date; current request validation checks the shape but not month/day validity."},"type":{"type":"string","enum":["closed","modified"]},"reason":{"type":["string","null"],"example":"Christmas Eve"},"slots":{"type":"array","description":"Always present in responses. On request input, required and\nnon-empty when `type: modified`. For `type: closed`, supplied\nvalues are accepted, stored, and returned, but ignored when\neffective opening hours are computed; omit them to receive `[]`.\n","items":{"$ref":"#/components/schemas/CalendarSlot"}}}},"CalendarSchedule":{"type":"object","required":["id","type","weekly_schedule","overrides"],"additionalProperties":false,"description":"Schedule as returned in responses. `id` is always present and\nserver-assigned. For write payloads see `CalendarScheduleCreate` and\n`CalendarScheduleUpdate`.\n","properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"type":{"type":"string","enum":["opening_hours","service_hours","office_hours","operating_hours"]},"weekly_schedule":{"$ref":"#/components/schemas/CalendarWeeklySchedule"},"overrides":{"type":"array","items":{"$ref":"#/components/schemas/CalendarOverride"}}}},"CalendarScheduleCreate":{"type":"object","required":["type"],"additionalProperties":false,"description":"Schedule shape for create requests. `id` is server-assigned on POST\nand therefore omitted; for the response shape see `CalendarSchedule`.\n","properties":{"type":{"type":"string","enum":["opening_hours","service_hours","office_hours","operating_hours"]},"weekly_schedule":{"$ref":"#/components/schemas/CalendarWeeklySchedule"},"overrides":{"type":"array","items":{"$ref":"#/components/schemas/CalendarOverride"}}}},"CalendarScheduleUpdate":{"type":"object","required":["type"],"additionalProperties":false,"description":"Schedule shape accepted when replacing `schedules` on PATCH. Include\nthe response `id` to preserve an existing schedule's identifier; omit\nit to let the server assign a new identifier.\n","properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$"},"type":{"type":"string","enum":["opening_hours","service_hours","office_hours","operating_hours"]},"weekly_schedule":{"$ref":"#/components/schemas/CalendarWeeklySchedule"},"overrides":{"type":"array","items":{"$ref":"#/components/schemas/CalendarOverride"}}}},"Calendar":{"type":"object","required":["id","name","timezone","schedules","created_at","updated_at"],"properties":{"id":{"type":"string","example":"65f8fa6f1a9d8e0012ab34cd"},"name":{"type":"string","example":"Main Office"},"timezone":{"type":"string","example":"Europe/Berlin"},"schedules":{"type":"array","items":{"$ref":"#/components/schemas/CalendarSchedule"}},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"CalendarCreate":{"type":"object","required":["name"],"additionalProperties":false,"example":{"name":"Main Office","timezone":"Europe/Berlin"},"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Whitespace is trimmed; the trimmed name must be at least 1 character."},"timezone":{"type":"string","minLength":1,"maxLength":100,"default":"Europe/Berlin","description":"IANA timezone string. Validated server-side."},"schedules":{"type":"array","items":{"$ref":"#/components/schemas/CalendarScheduleCreate"},"default":[]}}},"CalendarUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"description":"Partial update — include only the fields you want to change. Passing\n`schedules` replaces the full schedules array for this calendar.\n","example":{"name":"Main Office Berlin"},"properties":{"name":{"type":"string","minLength":1,"maxLength":100,"description":"Whitespace is trimmed; the trimmed name must be at least 1 character."},"timezone":{"type":"string","minLength":1,"maxLength":100},"schedules":{"type":"array","items":{"$ref":"#/components/schemas/CalendarScheduleUpdate"}}}},"PageCalendar":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Calendar"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"RecordingSummary":{"type":"object","required":["available"],"properties":{"available":{"type":"boolean"},"format":{"type":["string","null"],"example":"flac"},"mime_type":{"type":["string","null"],"example":"audio/flac"},"duration_ms":{"type":["integer","null"]},"size_bytes":{"type":["integer","null"]}}},"Call":{"type":"object","required":["id","direction","source","done","success","created_at"],"properties":{"id":{"type":"string"},"assistant_id":{"type":["string","null"]},"assistant_name":{"type":["string","null"]},"assistant_phone":{"type":["string","null"]},"direction":{"type":"string","enum":["inbound","outbound"]},"source":{"type":"string","enum":["inbound_phone","outbound_widget","outbound_api","outbound_manual"],"description":"How the call was originated:\n  - `inbound_phone` — caller dialed in from a real phone number.\n  - `outbound_widget` — chat widget kicked off an outbound call.\n  - `outbound_api` — Public API (POST /calls) triggered the call.\n  - `outbound_manual` — dashboard user manually triggered the call.\n"},"phone_number":{"type":["string","null"],"description":"Remote party phone number."},"duration_seconds":{"type":["integer","null"]},"done":{"type":"boolean"},"success":{"type":"boolean"},"language":{"type":["string","null"]},"started_at":{"type":["string","null"],"format":"date-time"},"ended_at":{"type":["string","null"],"format":"date-time"},"created_at":{"type":"string","format":"date-time"}}},"CallTranscriptMessage":{"type":"object","required":["role","content"],"properties":{"role":{"type":"string","example":"assistant"},"content":{"type":"string","description":"On an assistant with contextual_asr_correction_enabled, caller turns carry the corrected text the assistant actually answered, not the raw recogniser output."},"timestamp":{"type":["string","null"],"format":"date-time"}}},"CallAnalysis":{"type":"object","required":["id","status"],"properties":{"id":{"type":"string"},"name":{"type":["string","null"]},"status":{"type":"string","example":"completed"},"body_result":{"description":"Raw analysis result. Shape depends on the configured analysis.","oneOf":[{"type":"object"},{"type":"string"},{"type":"null"}]},"started_at":{"type":["string","null"],"format":"date-time"},"completed_at":{"type":["string","null"],"format":"date-time"}}},"CallNote":{"type":"object","required":["id","content","created_at"],"properties":{"id":{"type":"string"},"content":{"type":"string"},"author_id":{"type":["string","null"]},"author_name":{"type":["string","null"]},"created_at":{"type":"string","format":"date-time"}}},"CallDetail":{"allOf":[{"$ref":"#/components/schemas/Call"},{"type":"object","required":["transcript","analyses","notes","recording"],"properties":{"transcript":{"type":"array","items":{"$ref":"#/components/schemas/CallTranscriptMessage"}},"analyses":{"type":"array","items":{"$ref":"#/components/schemas/CallAnalysis"}},"notes":{"type":"array","items":{"$ref":"#/components/schemas/CallNote"}},"recording":{"$ref":"#/components/schemas/RecordingSummary"}}}]},"PageCall":{"type":"object","required":["data","meta"],"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Call"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}},"TriggerOutboundFields":{"type":"object","additionalProperties":false,"properties":{"assistant_id":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234","description":"The assistant that will make the call."},"assistant_phone":{"type":"string","pattern":"^\\+\\d{6,20}$","example":"+491701234567","description":"Alternative to `assistant_id` — look up the assistant by its phone number in E.164 format (leading `+` followed by 6–20 digits)."},"to":{"type":"string","pattern":"^\\+\\d{6,20}$","example":"+491701234999","description":"Destination phone number in E.164 format (leading `+` followed by 6–20 digits)."},"target_phone":{"type":"string","pattern":"^\\+\\d{6,20}$","example":"+12025550123","description":"Legacy alias for `to`. Same E.164 format."},"details":{"type":"string","maxLength":1000,"description":"Optional free-text context passed to the assistant prompt."}}},"TriggerOutbound":{"description":"Provide **exactly one** of `assistant_id` or `assistant_phone`, and\n**exactly one** of `to` or `target_phone` (`target_phone` is a legacy alias).\n","oneOf":[{"title":"Assistant ID + to","allOf":[{"$ref":"#/components/schemas/TriggerOutboundFields"},{"type":"object","required":["assistant_id","to"]}]},{"title":"Assistant ID + target_phone","allOf":[{"$ref":"#/components/schemas/TriggerOutboundFields"},{"type":"object","required":["assistant_id","target_phone"]}]},{"title":"Assistant phone + to","allOf":[{"$ref":"#/components/schemas/TriggerOutboundFields"},{"type":"object","required":["assistant_phone","to"]}]},{"title":"Assistant phone + target_phone","allOf":[{"$ref":"#/components/schemas/TriggerOutboundFields"},{"type":"object","required":["assistant_phone","target_phone"]}]}]},"StatisticsWeekYear":{"type":"object","required":["week","year"],"properties":{"week":{"type":"integer","example":17},"year":{"type":"integer","example":2026}}},"StatisticsAvailableAssistant":{"type":"object","required":["id","name"],"properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65a1234567890abcdef01234"},"name":{"type":"string","example":"Inbound Receptionist"}}},"StatisticsDailyCallCount":{"type":"object","required":["date","count"],"properties":{"date":{"type":"string","example":"2026-04-22","description":"ISO date (YYYY-MM-DD), Europe/Berlin timezone."},"count":{"type":"integer","example":12}}},"StatisticsMonthlyBreakdown":{"type":"object","required":["call_count","overall_call_seconds","average_calls_per_day","daily_call_counts"],"properties":{"call_count":{"type":"integer","example":240,"description":"Completed, non-error calls in the selected ISO-week window, including calls that have no usable duration."},"overall_call_seconds":{"type":"integer","example":60000,"description":"Sum of billable seconds. Calls with a usable duration have a 60-second minimum; calls without one contribute 0 seconds even though they remain included in `call_count`."},"average_calls_per_day":{"type":"number","example":12,"description":"Calls divided by the number of days that had calls (not all calendar days in the month), rounded to the nearest whole number."},"daily_call_counts":{"type":"array","items":{"$ref":"#/components/schemas/StatisticsDailyCallCount"}}}},"StatisticsSummary":{"type":"object","required":["available_weeks","available_assistants"],"properties":{"available_weeks":{"type":"array","description":"Every (week, year) pair with at least one completed call.","items":{"$ref":"#/components/schemas/StatisticsWeekYear"}},"available_assistants":{"type":"array","description":"Every assistant currently in the organization. The sentinel `all` is NOT included — clients may always pass `assistant_id=all` to `/usage`.","items":{"$ref":"#/components/schemas/StatisticsAvailableAssistant"}}}},"StatisticsUsage":{"type":"object","required":["period","assistant_id","monthly","weekly_call_counts","weekly_call_seconds","hourly_call_counts_last_24h"],"properties":{"period":{"$ref":"#/components/schemas/StatisticsWeekYear"},"assistant_id":{"oneOf":[{"type":"string","enum":["all"]},{"type":"string","pattern":"^[a-f0-9]{24}$"}],"description":"Echoes the filter the client sent."},"monthly":{"type":"object","description":"Breakdown for the month or months intersecting the selected ISO week, keyed by month name from the server runtime locale (for example `April`). Only months with at least one completed, non-error call appear. Treat keys as display labels, not stable identifiers.","additionalProperties":{"$ref":"#/components/schemas/StatisticsMonthlyBreakdown"}},"weekly_call_counts":{"type":"array","description":"7 integers, Mon..Sun, for the selected (week, year). Unlike `monthly.*.call_count`, this array counts only calls with a usable duration greater than zero. The service returns an empty array when no calls match.","minItems":0,"maxItems":7,"items":{"type":"integer"}},"weekly_call_seconds":{"type":"array","description":"7 integers of billable seconds, Mon..Sun, for the selected week. The service returns an empty array when no calls match.","minItems":0,"maxItems":7,"items":{"type":"integer"}},"hourly_call_counts_last_24h":{"type":"array","description":"24 integers for the last 24 hours ending at request time (index 0 = 23–24h ago, index 23 = 0–1h ago). Counts only calls with a positive recorded `callTime` (including the legacy nested fallback). This array is organization-wide and independent of the `week`, `year`, and `assistant_id` filters.","minItems":24,"maxItems":24,"items":{"type":"integer"}}}},"StatisticsAssistantEntry":{"type":"object","required":["assistant_id","assistant_name","assistant_language","is_deleted","total_calls","total_call_seconds","average_call_seconds","average_calls_per_day","weekly_call_counts","weekly_call_seconds","daily_call_counts"],"properties":{"assistant_id":{"type":["string","null"],"pattern":"^[a-f0-9]{24}$","example":"65f8fa6f1a9d8e0012ab34cd","description":"Null when the call was recorded without an assistant reference (legacy or orphaned calls)."},"assistant_name":{"type":"string"},"assistant_language":{"type":["string","null"],"description":"Assistant language tag (commonly a 2-letter code like `de`/`en`, or BCP-47 like `de-DE`), or `null` if unset. Format is provider-defined and not validated."},"is_deleted":{"type":"boolean","description":"True if the assistant has since been deleted."},"total_calls":{"type":"integer","description":"Completed, non-error calls in the week, including calls without a usable duration."},"total_call_seconds":{"type":"integer","description":"Billable seconds for the week. Calls with a usable duration have a 60-second minimum; durationless calls contribute 0 seconds but remain included in `total_calls` and count arrays."},"average_call_seconds":{"type":"number","description":"Mean billable seconds per call in the week, rounded to the nearest whole second."},"average_calls_per_day":{"type":"number","description":"Mean calls per day across days that had calls, rounded to one decimal place."},"weekly_call_counts":{"type":"array","minItems":7,"maxItems":7,"items":{"type":"integer"},"description":"Mon..Sun completed, non-error call counts, including calls without a usable duration."},"weekly_call_seconds":{"type":"array","minItems":7,"maxItems":7,"items":{"type":"integer"},"description":"Mon..Sun billable seconds."},"daily_call_counts":{"type":"array","items":{"$ref":"#/components/schemas/StatisticsDailyCallCount"}}}},"StatisticsAssistantsUsage":{"type":"object","required":["period","total_assistants","total_calls","assistants"],"properties":{"period":{"$ref":"#/components/schemas/StatisticsWeekYear"},"total_assistants":{"type":"integer"},"total_calls":{"type":"integer"},"assistants":{"type":"array","items":{"$ref":"#/components/schemas/StatisticsAssistantEntry"}}}},"Tool":{"type":"object","required":["id","tool_key","display_name","description","parameters","execution_type","source","webhook","integration","auth","created_at","updated_at"],"additionalProperties":false,"properties":{"id":{"type":"string","pattern":"^[a-f0-9]{24}$","example":"65f8fa6f1a9d8e0012ab34cd"},"tool_key":{"type":"string","example":"get_opening_hours"},"display_name":{"type":"string","example":"Get Opening Hours"},"description":{"type":"string","example":"Returns the opening hours for the requested weekday."},"parameters":{"type":"object","additionalProperties":true,"description":"JSON Schema for tool arguments. Customer-defined."},"execution_type":{"type":"string","enum":["webhook"],"description":"Public API list/get operations expose webhook tools only. Integration-type tools created in the dashboard are filtered out."},"source":{"type":"string","enum":["custom","template"]},"webhook":{"oneOf":[{"$ref":"#/components/schemas/ToolWebhookConfig"},{"type":"null"}]},"integration":{"type":"null","description":"Always `null` because integration tools are not exposed by this API."},"auth":{"oneOf":[{"$ref":"#/components/schemas/ToolAuthSummary"},{"type":"null"}]},"created_at":{"type":"string","format":"date-time"},"updated_at":{"type":"string","format":"date-time"}}},"ToolWebhookConfig":{"type":"object","required":["url"],"additionalProperties":false,"properties":{"url":{"type":"string","format":"uri","pattern":"^https://","example":"https://api.example.com/smao-tools","description":"Endpoint that receives tool invocations. Use HTTPS in every environment: although non-production request validation accepts `http://localhost`, the executor rejects every non-HTTPS URL. At invocation time, URLs that resolve to private, loopback, link-local, or cloud-metadata addresses are rejected and redirects are not followed — an HTTPS URL that redirects to a private address will fail."},"method":{"type":"string","enum":["GET","POST","PUT","PATCH","DELETE"],"default":"POST"},"headers":{"type":"object","additionalProperties":true,"description":"Custom HTTP headers. WARNING — do NOT put secrets in headers. Use the `auth` object for bearer tokens / API keys / basic auth. Values in this object are stored and returned as plaintext."},"body_template":{"type":"string","maxLength":50000,"description":"Template string with `@key` placeholders for argument interpolation."},"timeout_ms":{"type":"integer","minimum":500,"maximum":60000},"retry_count":{"type":"integer","minimum":0,"maximum":5}}},"ToolAuthSummary":{"type":"object","required":["type","has_secret"],"additionalProperties":false,"description":"RESPONSE-ONLY auth shape. Never contains the stored secret value; the API surfaces `has_secret` as the only signal of whether a credential is configured. To rotate, PATCH the tool with a new `auth` input.","properties":{"type":{"type":"string","enum":["apiKey","bearer","basic"]},"header_name":{"type":["string","null"],"description":"Custom header name for `apiKey` / `bearer` auth types."},"username":{"type":["string","null"],"description":"Username for `basic` auth."},"has_secret":{"type":"boolean","description":"True when an auth secret / password is stored. The actual value is never returned by the API — submit a new value on PATCH to rotate."}}},"ToolAuthInput":{"description":"Auth credentials sent on POST/PATCH. Shape varies by `type`.\nNote: `secret` and `password` are write-only; responses use `ToolAuthSummary`.\n","oneOf":[{"title":"ApiKey","type":"object","additionalProperties":false,"required":["type","header_name","secret"],"properties":{"type":{"type":"string","const":"apiKey"},"header_name":{"type":"string","minLength":1},"secret":{"type":"string","minLength":1,"writeOnly":true}}},{"title":"Bearer","type":"object","additionalProperties":false,"required":["type","header_name","secret"],"properties":{"type":{"type":"string","const":"bearer"},"header_name":{"type":"string","minLength":1},"secret":{"type":"string","minLength":1,"writeOnly":true}}},{"title":"Basic","type":"object","additionalProperties":false,"required":["type","username","password"],"properties":{"type":{"type":"string","const":"basic"},"username":{"type":"string","minLength":1},"password":{"type":"string","minLength":1,"writeOnly":true}}}],"discriminator":{"propertyName":"type"}},"ToolCreate":{"type":"object","required":["tool_key","display_name","execution_type","webhook"],"additionalProperties":false,"example":{"tool_key":"get_opening_hours","display_name":"Get Opening Hours","execution_type":"webhook","webhook":{"url":"https://api.example.com/smao-tools"}},"properties":{"tool_key":{"type":"string","pattern":"^[a-z][a-z0-9_]*$","minLength":1,"maxLength":80,"example":"get_opening_hours"},"display_name":{"type":"string","minLength":1,"maxLength":200,"description":"Leading/trailing whitespace is trimmed."},"description":{"type":"string","default":"","maxLength":1000},"execution_type":{"type":"string","enum":["webhook"],"description":"v1 accepts `webhook` only. Integration-type tools must be created via the dashboard (OAuth flow)."},"parameters":{"type":"object","additionalProperties":true,"description":"JSON Schema defining the tool arguments."},"webhook":{"$ref":"#/components/schemas/ToolWebhookConfig"},"auth":{"$ref":"#/components/schemas/ToolAuthInput"}}},"ToolUpdate":{"type":"object","minProperties":1,"additionalProperties":false,"description":"Partial update — include only fields you want to change. `tool_key` and `execution_type` are immutable.","example":{"display_name":"Get Current Opening Hours"},"properties":{"display_name":{"type":"string","minLength":1,"maxLength":200,"description":"Leading/trailing whitespace is trimmed."},"description":{"type":"string","maxLength":1000},"parameters":{"type":"object","additionalProperties":true},"webhook":{"$ref":"#/components/schemas/ToolWebhookConfig"},"auth":{"$ref":"#/components/schemas/ToolAuthInput"}}},"PageTool":{"type":"object","required":["data","meta"],"additionalProperties":false,"properties":{"data":{"type":"array","items":{"$ref":"#/components/schemas/Tool"}},"meta":{"$ref":"#/components/schemas/PageMeta"}}}}}}