Voice agents
An agent is the persona a caller hears: its name, the company it says it works for, the voice it speaks with, the languages it handles, and how it behaves. Agents hold no telephony of their own — a flow is what binds one to a phone number or a contact list.
List agents
GET /api/voice/agents
{
"agents": [
{
"uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"name": "Aria",
"role": "Sales representative",
"description": "Handles inbound product enquiries",
"agent_category": "sales",
"company_name": "Pragati AI",
"phone_number": "+915550010000",
"languages": ["en-IN", "hi-IN"],
"preferred_gender": "female",
"background": "Five years selling ergonomic furniture.",
"tone": "warm_professional",
"traits": ["patient", "concise"],
"style_notes": "Never quotes a price without confirming the model.",
"avatar_image": null,
"avatar_color": "#7473E4",
"avatar_initials": "AR",
"reference_audio_s3_key": null,
"voice_config": { "provider": "sarvam", "speaker": "anushka", "language_code": "en-IN" },
"is_active": true,
"created_at": "2026-09-18T11:02:10Z",
"updated_at": "2026-09-20T09:15:44Z"
}
]
}
Get an agent
GET /api/voice/agents/{uuid}
Returns the same object. 404 if it belongs to another organization.
Create an agent
POST /api/voice/agents
{
"name": "Aria",
"role": "Sales representative",
"company_name": "Pragati AI",
"agent_category": "sales",
"languages": ["en-IN", "hi-IN"],
"preferred_gender": "female",
"tone": "warm_professional",
"traits": ["patient", "concise"],
"voice_config": { "provider": "sarvam", "speaker": "anushka", "language_code": "en-IN" }
}
| Field | Type | Required | Notes |
|---|---|---|---|
name | string | ✓ | What the agent calls itself on the call |
role | string | — | Job title, used in the system prompt |
description | string | — | Internal note; not spoken |
agent_category | string | — | Free-form grouping, e.g. sales, support |
company_name | string | — | Spoken on the call. Falls back to the organization name |
phone_number | string | — | The number an inbound flow for this agent will use |
languages | string[] | — | BCP-47 tags the agent is expected to handle |
preferred_gender | string | — | Narrows the voice picker |
background | string | — | Backstory injected into the prompt |
tone | string | — | Also sets synthesis pace and temperature — see below |
traits | string[] | — | Short behavioural adjectives |
style_notes | string | — | Free-form rules added to the prompt |
avatar_color / avatar_initials | string | — | Console display only |
voice_config | object | — | Voice selection — see below |
is_active | bool | — | Inactive agents stay configured but are not offered |
Update an agent
PATCH /api/voice/agents/{uuid}
Accepts the same fields; send only what changes.
Delete an agent
DELETE /api/voice/agents/{uuid} → 204
A flow pointing at a deleted agent has no voice to answer with. Activating such a flow is refused; one already active fails at call time.
Voice configuration
voice_config is stored as JSON and read by the pipeline when the call starts:
{
"provider": "sarvam",
"tts_provider": "sarvam",
"stt_provider": "deepgram",
"speaker": "anushka",
"model": "bulbul:v2",
"language_code": "en-IN",
"pace": 1.0,
"temperature": 0.6,
"voice_description": "Warm, unhurried",
"voice_gender": "female"
}
Anything you set here wins over the defaults. Browse available voices through the voice catalog, or clone one and reference the resulting speaker name.
Tone presets
tone shapes delivery as well as wording — the same sentence read flatly
sounds robotic however good the prompt is:
| Tone | Pace | Temperature |
|---|---|---|
energetic | 1.1 | 0.8 |
friendly_casual | 1.05 | 0.75 |
warm_professional | 1.0 | 0.6 |
empathetic | 0.9 | 0.5 |
direct | 1.05 | 0.45 |
An explicit pace or temperature in voice_config overrides the preset.
Language behaviour
The agent follows the caller between languages, but the text and the voice move on different schedules, deliberately:
- The model is told what the current turn looked like, so it can follow a caller into Hindi on their first Hindi sentence.
- The synthesiser follows the profile's settled language, which needs
several turns of evidence (
VOICE_LANG_LOCK_WORDS, default 15 words).
The tradeoff: the model being wrong costs one reply in the wrong language, while retargeting the voice on one uncertain turn is audible and hard to undo.
This is why a call can produce Hindi words in an English voice, or English
numbers read in Hindi, during the turns before the profile settles. Raising
VOICE_LANG_LOCK_WORDS makes the voice switch later and less often; lowering
it makes one misheard turn able to flip the whole call.
Human agents
The routes under /api/voice/agents/phone-numbers and
/api/voice/agents/tag-assignments are not about voice agents — they map
your human teammates to phone numbers and customer tags for click-to-call and
handoff. See Telephony.