Why voice is not chat
Three constraints. Everything below follows from them. The caller cannot scroll, and cannot re-read. A sentence they missed is gone. Anything that matters gets said once, short, and gets read back. A long reply is the thing they wait through. They hear every word before they can answer. Reply length is the single biggest latency lever you own — bigger than anything in the stack. Cap it in the prompt, in words the model cannot round up: “one short sentence, maximum two”. Turn-taking replaces reading. In chat you can ask three things in one message and let the reader sort it out. On a call, two questions in one turn get one answer and you will not know which. One ask, then stop.What the engine already does
A lot of what people write into voice prompts is already handled below the prompt. Writing it again does not make it truer; it just spends turns and tokens.- The opening line runs before the model does.
first_messageis spoken the moment the callee answers. It is your first-audio latency. The model is told what was said, so it does not greet twice. - Refusals already end the call. When
end_call.enabledis true (the default), the engine appends an ending rule to every prompt: if the caller refuses or asks to end — “नहीं चाहिए”, “बात नहीं करनी”, “रखता हूं”, “call खत्म करो” — the agent does not re-sell, says one farewell sentence and callsend_call. Same on a second refusal. You do not write this. - A bare “ok” does not hang up. With
end_call.confirm: true(the default), the firstend_callinside the window asks the caller to confirm; the second one ends the call. - Barge-in is automatic. The caller can talk over the agent — after two words of caller speech the agent stops and listens. If they barge in without actual words, the agent says “हाँ, बोलिए ना, क्या बात है?”.
- Silence is handled. If the caller goes quiet, the agent checks in after about 15 seconds; after three unanswered check-ins the call ends. Nothing to write.
- Voicemail is detected by the engine and handled by the agent’s
voicemailsetting. Nothing to write. - Per-call data is substituted for you.
{{placeholders}}in bothsystem_promptandfirst_messageare filled from the call’svariables.
The structure
Every house template follows one discipline. Six blocks, in this order, nothing else:The opening line
first_message is spoken before the model runs, so it is pure first-audio
latency and it should be short: name, brand, person check. Nothing else.
The console renders this for you when you pick a template. The API does not —
if you switch
voice_id on an existing agent, fix the opening line in the same
request.
Language rules for Hinglish
Real Indian phone calls are not Hindi and are not English. They are Hindi grammar carrying English nouns, and an agent that picks one pure language sounds like a recording. This block is what the console appends to every template. Paste it at the end of your prompt, unchanged:- Devanagari for Hindi words. Romanized Hindi in the prompt gets read as English. “kar payenge” comes out with English vowels and the caller hears an accent, not a person.
- Roman script for English words. Nobody on a phone call says भुगतान. They say payment. Writing the English word in Roman is not laziness — it is how the sentence is actually spoken.
- No shuddh Hindi. Formal Hindi is the register of a government notice, not a phone call. It reads as a recording even when the audio is perfect.
- Numbers as English words. The voice reads English number words most reliably. Digits and Hindi number words are read inconsistently.
- धन्यवाद once. Models over-thank. Thanking four times in ninety seconds is the clearest tell that nobody is there.
language: "en-IN") the shape is identical — drop the
Devanagari rule and keep everything else. Numbers still go in as words, and
identifiers are still read digit by digit.
Numbers, dates, amounts and identifiers
The model copies what you write straight into speech. Write for the ear.
Amounts and quantities are natural words; quantities can sit inline in a Hindi
sentence (“दो items”). Identifiers — pincode, phone, order id, vehicle number,
challan number — are always digit by digit, never grouped into “ninety-eight
thousand”.
Digit-count sanity. An Indian pincode is six digits. A mobile number is ten.
If a read-back is short, the recogniser dropped digits — the agent must push
back, never accept:
Facts, and the customer
FACTS is a contract. The agent may say what is in it and nothing more. Anything outside — a policy question, an exception, a price you did not list — is answered with “the team will call you back”. Never invent policy, never waive a penalty, never quote a number that is not in FACTS. Per-call data goes invariables, not in the prompt. One agent runs
thousands of calls; the customer’s name, amount and date change every time.
Hard-coding them means one agent per customer, and nobody wants to manage that.
5200 is a gamble;
five thousand two hundred is not.
A few properties worth knowing:
- Names are matched loosely.
{{Customer Name}},{{customer_name}}and{{CustomerName}}are the same variable — letters and digits only, case-insensitive. - An unknown placeholder in the system prompt becomes an empty string. It does not error, and it does not leave braces for the agent to read aloud.
- Values are plain strings, and braces inside a value are stripped.
- Variables are static per call. There is no way to change one mid-call.
- Keep them short. They are prompt tokens on every turn.
The flow
- One ask per step. Two questions in one turn get one answer, and you will not know which one it was.
- Never assume what was not clearly said. If the caller mumbled a date, the agent asks again. A confidently wrong confirmation is worse than a second question.
- Confirm by exception. Read back only what changed, and do one consolidated read-back at the end. Confirming every field turns a ninety-second call into three minutes.
- Listen when they are dictating. While the caller reads out an address, the agent’s job is backchannels — “जी”, “हम्म” — and then one read-back at the end. Interrupting a dictated address to confirm line one is how you lose the rest of it.
- Mishear recovery is surgical. Re-ask the one field that was wrong. Never restart the flow.
- Answer, then return. If the caller derails with a question, answer it in one line from FACTS and go straight back to the step you were on.
- Every turn moves forward. Acknowledge and ask the next thing in one utterance. A turn that only says “ठीक है” costs the caller time and buys nothing.
Pushback and endings
One light nudge, then accept. The engine already enforces the refusal ending, so your job is the success ending — and it is the line people forget:end_call. Say धन्यवाद once, in that goodbye. Leave
end_call.message empty — the default — and the
model’s own goodbye is the farewell. If you do set a message, it is spoken
after the model’s goodbye, so it must not repeat it: a धन्यवाद in both means
the caller hears it twice.
Finally, size the call. max_duration_secs is a hard cap, and hitting it ends
the call with ended_reason: exceeded-max-duration mid-sentence. For a one-job
call, 180–300 seconds is right. The default is 300; the range is 30–1800.
Sounding like a person
- Lead word up front. “जी।”, “अच्छा—”, “ठीक है।” at the start of a turn does two things: the voice starts sooner, and it sounds like somebody who was listening rather than a system that was processing.
- Punctuation is your only expressiveness control. Interjections and emphasis at the moments that carry them — an apology, a pushback — and flat everywhere else. Expressiveness everywhere is the same as expressiveness nowhere.
- No stage directions, no tags, no emoji, no markdown. The voice reads the
text it is given. Asterisks, bullet characters and
(warmly)come out as noise. - Match the caller’s register. If they answer in English, the agent continues in English. If they switch to Hindi mid-call, so does it.
- Contractions and everyday words. Write the sentence you would say out loud, not the one you would put in an email.
What not to write
Test, then refine
Every real phone call costs money — there is no test key — so the loop is designed to find problems in the cheapest place first.1
Start from a template
Agent Studio in the console has six house
scripts in the template dropdown — Govt · Traffic challan, BFSI · EMI reminder,
BFSI · GSTR-1 filing, D2C · Order confirmation, D2C · Service reminder,
Hospitality · Booking confirmation. All six are already in the structure above.
If none of them is close, use Describe the call and we draft it → Generate
script: a one-line brief comes back as a house-style prompt and opening line
to edit.
2
Call yourself on the web phone
The web phone in the right rail runs the agent without dialling a phone. Play
the customer you are afraid of: say no, correct a digit half-way through, ask
something that is not in FACTS, then go quiet and see what happens. Most prompt
bugs die here, for free.
3
Read the transcript, change one thing
4
Three real calls to your own number
The phone line is a different acoustic world from a browser mic: carrier codecs,
background noise, a caller who is walking. Prompts that pass on the web phone and
fail on a real handset are common, and they fail on numbers first.
5
A small campaign, then read it
Twenty to fifty contacts. Read the transcripts and the campaign report before
you scale — see Campaigns. Fix what you find, then go wide.
A worked example
The EMI reminder, rendered for theaishe voice with the agent named मीरा.
system_prompt:
first_message:
Create the agent
- cURL
- Python
- Node.js
emi-agent.json
end_call
is left at its defaults on purpose: confirmation on, no canned farewell, so the
धन्यवाद in the EXAMPLE EXCHANGE is the only one the caller hears.
Place the call
The variable values are already in spoken form. That is the point.Copy-paste skeleton
Fill the angle brackets, keep everything else.That is the whole method: one job, six blocks, numbers as words, one ending you wrote yourself. When a prompt still is not landing and the structure is right, the problem is usually a belief about what a call is — that is The Zen of Voice Agents.