Agents
Agents are the core entity in VOCALS. Each agent defines a conversational AI persona with its own STT, LLM, and TTS provider configuration, system prompt, voice settings, and phone number assignments.
List Agents
GET /agents
Returns all agents for the current tenant, ordered by name.
Response
[
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Support Agent",
"active_stt_provider_id": "...",
"active_llm_provider_id": "...",
"active_tts_provider_id": "...",
"is_active": true,
"phone_count": 2,
"has_webhook": true,
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-20T14:00:00Z"
}
]
Response Fields (List)
| Field | Type | Description |
|---|---|---|
id | uuid | Agent ID |
name | string | Agent display name |
active_stt_provider_id | uuid | null | Assigned STT provider |
active_llm_provider_id | uuid | null | Assigned LLM provider |
active_tts_provider_id | uuid | null | Assigned TTS provider |
is_active | boolean | Whether the agent is active |
phone_count | integer | Number of assigned phone numbers |
has_webhook | boolean | Whether a webhook URL is configured |
created_at | datetime | Creation timestamp |
updated_at | datetime | Last update timestamp |
Get Agent
GET /agents/{agent_id}
Returns full agent detail including phone number assignments.
Response
{
"id": "550e8400-e29b-41d4-a716-446655440000",
"name": "Support Agent",
"active_stt_provider_id": "...",
"active_llm_provider_id": "...",
"active_tts_provider_id": "...",
"system_prompt": "You are a helpful support agent...",
"welcome_message": "Hello! How can I help you today?",
"voice_id": "rachel",
"language": "en",
"silence_threshold": 0.5,
"max_call_duration": 300,
"barge_in_sensitivity": "medium",
"stt_endpointing_sensitivity": "medium",
"interruptible": true,
"welcome_interruptible": false,
"amd_enabled": false,
"tts_config": { "speed": 1.0 },
"custom_variables": [
{ "name": "company_name", "default": "Acme Corp" },
{ "name": "support_hours", "default": "9am-5pm" }
],
"webhook_url": "https://example.com/webhook",
"webhook_secret": "whsec_...",
"is_active": true,
"phone_numbers": [
{
"id": "...",
"phone_number": "+15551234567",
"sip_config_id": "..."
}
],
"created_at": "2026-01-15T10:30:00Z",
"updated_at": "2026-02-20T14:00:00Z"
}
Response Fields (Detail)
| Field | Type | Description |
|---|---|---|
id | uuid | Agent ID |
name | string | Agent display name |
active_stt_provider_id | uuid | null | Assigned STT provider |
active_llm_provider_id | uuid | null | Assigned LLM provider |
active_tts_provider_id | uuid | null | Assigned TTS provider |
system_prompt | string | null | System prompt sent to the LLM |
welcome_message | string | null | Message spoken at call start |
voice_id | string | null | TTS voice identifier |
language | string | Language code (e.g. en, es) |
silence_threshold | float | Deprecated and ignored. Stored and returned for backwards compatibility only; it has no effect on a call. Use stt_endpointing_sensitivity instead. |
max_call_duration | integer | Max call length in seconds (0 = unlimited) |
barge_in_sensitivity | string | very_low, low, medium, high, or very_high |
stt_endpointing_sensitivity | string | very_low, low, medium, high, or very_high. How quickly the agent decides the caller has finished speaking (see Response Trigger Speed). |
interruptible | boolean | Whether the agent can be interrupted mid-speech |
welcome_interruptible | boolean | Whether the welcome message can be interrupted |
amd_enabled | boolean | Answering machine detection for outbound calls |
tts_config | object | null | Provider-specific TTS settings |
custom_variables | array | null | Per-agent custom variable definitions, each { "name": ..., "default": ... }. Used to fill {{name}} placeholders in the system prompt and welcome message. See Dynamic Variables. |
webhook_url | string | null | URL for call event webhooks |
webhook_secret | string | null | Secret for webhook signature verification |
is_active | boolean | Whether the agent is active |
phone_numbers | array | Assigned phone numbers with SIP config references |
created_at | datetime | Creation timestamp |
updated_at | datetime | Last update timestamp |
Create Agent
POST /agents
Request Body
{
"name": "Sales Agent",
"active_stt_provider_id": "uuid-of-stt-provider",
"active_llm_provider_id": "uuid-of-llm-provider",
"active_tts_provider_id": "uuid-of-tts-provider",
"system_prompt": "You are a sales representative...",
"welcome_message": "Hi there! Thanks for calling.",
"voice_id": "rachel",
"language": "en",
"max_call_duration": 600,
"barge_in_sensitivity": "medium",
"stt_endpointing_sensitivity": "medium",
"interruptible": true,
"welcome_interruptible": false,
"amd_enabled": false,
"tts_config": { "speed": 1.0 },
"custom_variables": [
{ "name": "company_name", "default": "Acme Corp" }
],
"webhook_url": "https://example.com/webhook",
"is_active": true,
"phone_numbers": [
{
"phone_number": "+15551234567",
"sip_config_id": "uuid-of-sip-config"
}
]
}
Request Fields
| Field | Type | Required | Default | Description |
|---|---|---|---|---|
name | string | Yes | -- | Agent display name |
active_stt_provider_id | uuid | No | null | STT provider to use |
active_llm_provider_id | uuid | No | null | LLM provider to use |
active_tts_provider_id | uuid | No | null | TTS provider to use |
system_prompt | string | No | null | System prompt for the LLM |
welcome_message | string | No | null | Message spoken when call starts |
voice_id | string | No | null | TTS voice identifier |
language | string | No | "en" | Language code |
silence_threshold | float | No | 0.5 | Deprecated and ignored. Still accepted so existing clients keep working, but it has no effect on a call. Use stt_endpointing_sensitivity instead. |
max_call_duration | integer | No | 0 | Max call duration (0 = unlimited) |
barge_in_sensitivity | string | No | "medium" | Barge-in sensitivity level |
stt_endpointing_sensitivity | string | No | "medium" | How quickly the agent decides the caller has finished speaking (see Response Trigger Speed) |
interruptible | boolean | No | true | Allow mid-speech interruption |
welcome_interruptible | boolean | No | false | Allow welcome message interruption |
amd_enabled | boolean | No | false | Enable answering machine detection |
tts_config | object | No | null | Extra TTS provider config |
custom_variables | array | No | null | Per-agent custom variable definitions (see below) |
webhook_url | string | No | null | Webhook endpoint URL |
webhook_secret | string | No | null | Webhook signing secret |
is_active | boolean | No | true | Whether agent is active |
phone_numbers | array | No | null | Phone number assignments. Each phone_number must be E.164 with the country code (+34930485412); separators are stripped, and a value without a leading + and country code returns 422. |
Custom Variables
custom_variables defines the agent's dynamic-variable placeholders. Each entry is an object with a name and a default:
"custom_variables": [
{ "name": "company_name", "default": "Acme Corp" },
{ "name": "support_hours", "default": "9am-5pm" }
]
| Field | Type | Description |
|---|---|---|
name | string | Variable name. Lowercase letters, digits, and underscores only. Must be unique within the agent and must not collide with a built-in variable name. |
default | string | Required, non-empty default value used whenever the variable is not overridden for a call. |
Reference a custom variable as {{name}} in the system_prompt or welcome_message; it is resolved at call start. Defaults can be overridden per call via the call-trigger API. For the full list of built-in variables and authoring behaviour, see Dynamic Variables.
The API returns 422 Unprocessable Entity when a default is empty or absent (the message names the offending variable), when a name is malformed, when names are duplicated, when a name collides with a built-in variable, or when the list exceeds the per-agent cap.
Response
201 Created -- Returns the full AgentResponse object.
Provider IDs are validated against your tenant's configured providers. If a provider ID is invalid or belongs to the wrong type (e.g. passing an LLM provider ID as the STT provider), the API returns 400 Bad Request.
tts_config is stored exactly as sent
No model is ever substituted for the one you configure. tts_config is persisted verbatim on both create and update: send no model_id and none is stored, in which case the call uses the model on the agent's TTS provider row.
An earlier release briefly seeded "model_id": "eleven_flash_v2_5" onto new ElevenLabs agents. That has been removed. Agents created while it was active still have the value in their stored tts_config and will keep using it until you send a different model_id or recreate them.
When the agent uses either Google TTS provider (google or google_gemini) together with a voice_id, the save runs a test synthesis of that exact voice before the agent is stored. If the synthesis fails - for example a voice the credential's project cannot reach, an invalid credential, or a Cloud Text-to-Speech key pasted into a google_gemini provider - the API returns 400 Bad Request with the underlying error surfaced, and the agent is not saved. If tts_config.google_style_prompt exceeds its maximum length of 500 characters, the API returns 422 Unprocessable Entity before any changes are made. Both checks apply to create and update.
tts_config.google_style_prompt
An optional delivery instruction, up to 500 characters, applied to every response the agent speaks:
{
"active_tts_provider_id": "550e8400-e29b-41d4-a716-446655440000",
"voice_id": "Zephyr",
"tts_config": { "google_style_prompt": "Speak warmly and slowly" }
}
It takes effect only when the agent's active TTS provider is google_gemini, whose voices accept delivery direction. Every other TTS provider ignores it - including google (Google Cloud TTS), which has no style capability on its surface: the value is stored but has no effect on synthesis. Note that google_gemini voice ids are bare prebuilt names such as Zephyr, not the locale-prefixed ids Google Cloud TTS uses.
Response Trigger Speed
stt_endpointing_sensitivity controls how quickly the agent decides the caller has finished speaking and starts replying. It uses the same five-level scale as barge_in_sensitivity, and defaults to "medium":
| Value | Behaviour |
|---|---|
very_low | Waits longest before replying. Best for callers who pause mid-sentence or read out long numbers. |
low | Waits a little longer than the default. |
medium | Balanced default. |
high | Replies sooner, at the cost of occasionally cutting in on a pause. |
very_high | Fastest reply. Best for short, quick exchanges on a clean line. |
Any other value returns 422 Unprocessable Entity listing the allowed values. The setting has no effect on speech-to-speech (live) agents, where the model handles end-of-speech detection itself.
Update Agent
PUT /agents/{agent_id}
Partial updates are supported. Only include the fields you want to change.
Request Body
{
"name": "Updated Agent Name",
"system_prompt": "New system prompt...",
"is_active": false
}
All fields from the create schema are accepted, but none are required.
Response
200 OK -- Returns the updated AgentResponse object.
Delete Agent
DELETE /agents/{agent_id}
Permanently deletes an agent and its phone number assignments.
Response
204 No Content -- No response body.
Get Agent by Phone Number
GET /agents/by-phone/{phone}
Look up the agent assigned to a specific phone number. Useful for routing logic.
Path Parameters
| Parameter | Type | Description |
|---|---|---|
phone | string | Phone number in E.164 format (e.g. +15551234567) |
Response
Returns the full AgentResponse object, or 404 if no agent is assigned to that number.