Guides
Voice agent
An agent is only as good as its system prompt. This page shows you how to write one, gives you three ready-made samples to copy, and covers the limits you need to plan around.
1systemPrompt structure
A good prompt has four parts. Skip any one of them and the agent will eventually get stuck and not know what to do next - it either goes quiet or makes something up.
- Who I am - one or two sentences: company name, role, tone of voice. The agent needs to establish this identity in its very first line.
- What I can do - the concrete tasks the agent actually handles (orders, appointments, information) - not a vague "I can help with anything".
- What I NEVER do - the boundaries: what the agent must never invent, promise or disclose. This part gets skipped most often, and it's exactly what separates an agent that makes up prices from one that fairly says "I don't know, call...".
- How to end the call - when and how to close the call (summary, goodbye) and what to do when the caller wants something out of scope.
Longer instructions slow the response down by roughly a tenth of a second for every two thousand characters - the agent editor flags this from 3000 characters. The hard limit is 6000 characters.
Three complete samples - copy them and adapt to your case:
Cafe receptionist
You are the voice receptionist for Nula Cafe in Vinohrady. You speak
calmly, warmly and briefly - the way an experienced staff member would,
not a robot.
WHAT YOU CAN DO
- Take pickup orders (coffee, tea, croissants, sandwiches).
- Tell callers the current opening hours: Monday to Friday 8am-6pm,
weekends 9am-3pm.
- At the end of an order, repeat it back in full and confirm the pickup
time (at least 15 minutes from now).
WHAT YOU NEVER DO
- Never make up prices or items that aren't on the menu - say that
staff will confirm the exact price on site.
- Never promise delivery, the cafe doesn't deliver.
- Never pretend to be human when a caller asks you directly - say
you're the cafe's voice assistant.
HOW TO END THE CALL
Summarize the order and pickup time, wish them a good day, and end the
call. If the caller wants something you can't handle (complaints,
catering), tell them to call again during business hours and speak to
the owner directly.Satisfaction survey
You're calling on behalf of Botanika, an online store, for a short
satisfaction survey after a recent order. You're polite, get straight
to the point, and don't drag the call out.
WHAT YOU CAN DO
- Ask if the customer has a minute for three quick questions.
- Question 1: how would they rate their satisfaction with the order,
on a scale of 1-5.
- Question 2: did the package arrive on time?
- Question 3: is there anything we could improve?
- Remember the answers and summarize them briefly at the end of the
call.
WHAT YOU NEVER DO
- Never push a customer who declines or says they have no time - end
the call politely right away.
- Never handle complaints or returns - that belongs on the customer
support line, which you can read out on request.
- Never offer discounts or coupons, you don't have that authority.
HOW TO END THE CALL
Thank them for their time and feedback, wish them a good day. If the
customer says at any point they don't want to continue, end the call
politely right away with no further questions.Front desk / gatehouse
You are the voice front desk for Nordwex, an office building in
Pankrac. Couriers, visitors and suppliers call this number.
WHAT YOU CAN DO
- Find out who's calling and why (a courier with a package, a visitor
for a meeting, a supplier).
- For a visitor, get their name and who they're meeting, then tell
them to check in at the ground-floor reception and wait until
someone comes for them.
- For a courier, tell them to leave the package at reception and write
the company name and recipient on it.
- Take a short message when the person they're calling for isn't
available right now.
WHAT YOU NEVER DO
- Never give out employees' private mobile numbers - offer to
transfer to reception or take a message.
- Never let anyone go "up alone" - all visitors go through reception.
- Never share who is currently in the building or when - say they
need to check with reception.
HOW TO END THE CALL
Repeat back what was agreed (message, waiting at reception, transfer),
wish them a good day, and end the call.2Industry templates
Do not want to write a prompt from scratch? The website has ready-made templates for six industries (dental practice, auto repair shop, restaurant, e-commerce, real estate agency, tradespeople) - a complete system prompt, a sample dialogue, and an example of what such a receptionist would cost. Copy and adjust it, just like the samples above.
3firstMessage
firstMessage is the first sentence the customer hears - right after they pick up for an inbound call, or right after the callee answers for an outbound one.
- Short, spoken English - the way a person would say it, not the way they'd write an email.
- Say right away who or what is calling/answering - the customer needs to know who they're talking to within three seconds.
- End with an open question ("how can I help", "got a minute") - not a long monologue.
- Read it out loud - text that looks fine written down can sound clumsy spoken.
- For outbound calls, introduce yourself and the reason for calling right at the start - people are wary of picking up unknown numbers.
4Tools
A tool is the address of your API, which the agent calls in the middle of a call and uses the response right away in speech. Without a tool the agent can only talk; with one it can verify an order, find an open slot, or log a booking.
Tools are created in the portal at /en/agent/tools (or via POST /v1/tools), then turned on for an agent with a checkbox on its detail page (the toolIds field in the API). A tool belongs to the account, not to an agent - the same tool can be used by multiple agents. You specify four things for it:
- Name - a readable one ("Verify order"). The name the model sees is derived from it automatically (
overit_objednavku) and shown under the field. - When the agent should use it - the only thing the model bases its decision to call the tool on at all. Write it as an instruction: "Use when the caller asks where their order is."
- Address and method -
httpsonly, publicly reachable.GETsends parameters in the query string,POSTin the JSON body. Plus headers, typicallyAuthorization. - Parameters - for each one you say where its value comes from: the model pulls it from the call, the caller's or called number is filled in automatically, or it's a fixed value.
This is what the request that arrives at your endpoint during the call looks like:
POST https://api.yourapp.com/orders
Content-Type: application/json
Authorization: Bearer your_key
{
"order_number": "A-42",
"phone": "+420777123456"
}And this is the response the agent can work with - a short JSON payload it can turn into a single sentence:
{
"status": "shipped",
"delivery": "tomorrow morning"
}Try the tool before you save it
The form has a Try it button: it sends a real request to the given address with sample values and shows the status, response time, and the start of the response. Nothing is saved in the process. It's worth doing - an endpoint that responds slowly is heard by the caller as silence during the call.
Limits: at most 10 tools per account, 10 parameters and 5 headers per tool, response timeout 5 to 30 seconds (default 20) - that's exactly how long the agent waits, saying a bridging phrase in the meantime so the caller doesn't hear silence. We show header values back to you masked (Bear***) only - the full value can't be read back from the account.
5Handoff to a human
The agent can hand the call off to your number when the caller asks for a person or runs into something the agent can't resolve. It's turned on in the agent's detail page (the transferTo field in the API); you write the condition as an instruction to the model in transferCondition. Without one, we use a default sentence.
On volai's own voice engine
On volai's own voice engine, transfer is bridged: the agent says it's connecting you, the caller hears ringing, and the human at your number sees the agent's number. Once you pick up, the agent goes silent and the call continues between the two of you over volai. If either of you hangs up, the call ends for both. If you don't answer within 25 seconds, the agent apologizes to the caller, offers to take a message, and continues.
Two things worth knowing up front
We don't pass a call summary to the human. The caller hears that they're being transferred, but the person on the other end picks up the caller directly - there's no "warm transfer" where the agent briefs the human first; the phone network doesn't support that. Plan for it in your instructions: have the agent tell the caller they may need to repeat themselves.
A handoff is a regular outbound call, and it's billed as one: 0.92 CZK/min from pickup to hangup, no agent surcharge (the agent is no longer on this leg). You can spot it in the call history by its transfer kind, and the original call's detail page carries a Transfer card linking to this leg. The inbound leg keeps running and is billed separately.
The standard platform (ElevenLabs)
On the standard platform (ElevenLabs), transfer doesn't work - the SIP operator never completes it. After you enable transfer, volai attempts to move the agent to its own voice engine right after saving. The attempt may be paused, the engine may be unavailable, or the switch may fail; check the returned provider field to verify that the agent is actually on the engine. Transfer does not work while it remains on ElevenLabs. A successful switch may change the agent's voice; the engine's default voice is Milena.
You can't transfer to your own volai number - the call would loop back on itself until the credit ran out. Premium-rate lines (90x) are banned for the same reason.
6Data captured from calls
Instead of reading the full transcript, you can specify exactly what you want out of a call - a name, an item count, whether it's urgent. The agent fills it in after the call, and you get it back as JSON.
Each field has a key, a type, and a description. Up to ten fields per agent:
- Key (
key) - lowercase letters, digits and underscores, up to 40 characters - must start with a lowercase letter. You'll find the value under this name in the result. - Type (
type) -string,number, orboolean. - Description (
description) - exactly what the model should pull out, 5 to 500 characters. Also say what it should do when the call doesn't mention it. - Options (
enumValues) - an optional list, for text fields only. The model then only picks from the offered values, so the result can be filtered directly. At most 20 options, each up to 60 characters.
curl -X PATCH https://volai.cz/v1/agents/ag_kx91fa2b \
-H "Authorization: Bearer vk_YOUR_KEY" \
-H "Content-Type: application/json" \
-d '{
"dataFields": [
{"key": "name", "type": "string", "description": "The caller's name, as they stated it. Leave empty if not mentioned."},
{"key": "coffee_count", "type": "number", "description": "How many coffees the caller ordered."},
{"key": "urgency", "type": "string", "description": "How urgent the request was.", "enumValues": ["low", "normal", "high"]}
]
}'The result shows up in three places: on the call's detail page in the portal as a "Captured data" card, in the data field on the call (both GET /v1/calls and GET /v1/calls/{id}), and in the call.completed webhook body.
{
"call": {
"id": "c_8f2ac1d4",
"status": "completed",
"hasRecording": true,
"data": {
"name": "Jane Smith",
"coffee_count": 2,
"urgency": "normal"
}
}
}A null value means "not mentioned in the call" - the same applies if the model returns an empty string. If an agent has no fields configured, the data key isn't in the response at all.
7Agent goal and evaluation
A goal is one sentence describing what the call should achieve - "book a viewing", "find out if the customer is interested in the offer". You fill it into the "Agent goal" field in the portal (when you create the agent or any time later when you edit it), or over the REST API and MCP via the goal field on POST/PATCH /v1/agents and create_agent/update_agent (up to 300 characters).
The goal goes to the agent as a criterion for evaluating the call: once the call ends, a model reads the transcript over it and decides whether the goal was met, not met, or cannot be determined from the call. You'll see the result on the call in the portal - on the call detail page and in the call list - and also in the email after the call, next to the summary.
It is a model's estimate, not a fact
The evaluation only reads the call transcript, not what happened afterwards (whether the customer actually showed up). Honest caveat: the agent's goal (goal) can be set and read over the REST API and MCP, but the evaluation RESULT of a specific call stays in the portal and the post-call email only - GET /v1/calls and get_call don't return it. Evaluation also only runs for agents on volai's new voice engine - which platform an agent runs on is shown by the provider field (GET /v1/agents, list_agents, and the agent's detail page in the portal); volai handles the switch. Older agents that stay on the original platform will get it only after being moved over to this engine.
What the agent knows (background material)
Beyond the instructions you can give the agent background material - opening hours, a price list, an FAQ. Fill it into the "What the agent knows" field in the portal (Advanced section), or the knowledge field on POST/PATCH /v1/agents. The text is appended to the end of the prompt, fits in 20000 characters, and a PATCH with an empty value clears it. Unlike a tool, this material never changes during a call - anything that does change (order status, open slots) belongs in a tool, not here.
8Email after the call
After a call with the agent ends, volai sends you an email with the summary and a link to the call detail in the portal - the same summary you see in the API in the summary field. It goes out for agents running on volai's own voice engine (provider: "engine"); an agent on ElevenLabs (provider: "elevenlabs") does not get it yet.
The "Email after every call" toggle is on the Settings page - turning it off stops the email for the whole account at once. To stop it for a single agent, use the "Email me after every call" checkbox on that agent's detail page (the notifyEmail: false field in the API). You get at most one email per call, and a call with nothing to report (no summary, no collected data and no end reason) does not trigger one.
9Recordings
Agent calls are recorded, and you can play them straight from the call's detail page in the portal - clicking in the transcript jumps to the matching point in the recording. To download or play it elsewhere, use GET /v1/calls/{id}/recording (same API key) - the format follows the response's content-type header: audio/mpeg (MP3) for an agent on ElevenLabs, audio/ogg today for an agent on volai's engine. The hasRecording field tells you whether a call has one.
- We keep them for 90 days after the call, then delete them. The transcript and summary are kept separately and aren't deleted along with the recording. After ninety days, the endpoint returns
recording_expired. - You can turn it off per agent with a toggle on its detail page, or the
recordCalls: falsefield in the API. From that point on, no recording is made. - Only calls handled by the built-in agent are recorded. A direct bridge between two numbers, a relay call, and a SIP call are never recorded.
Informing the caller is your responsibility
Recording a call is processing personal data. When it's on, volai automatically appends a short line to the agent's first message saying the call is recorded - it happens on its own, you don't need to add anything to the prompt or the opening line. Making sure the disclosure meets the law for your situation is still your responsibility as the data controller.
Every API error carries cause (who fixes it) and action (what to do) - see Error format in the REST API reference.
10Limits
- A call lasts at most 10 minutes (600 seconds), then the agent ends it itself.
- If the caller stays silent for 20 seconds, the agent treats it as the end of the call and hangs up.
- The agent responds roughly 1 second after you finish speaking - in real traffic this varies slightly with load.
11Languages
The agent can speak five languages - Czech (the default), Slovak, English, German and Polish - you set the language on the agent's detail page (the language field in POST/PATCH /v1/agents, create_agent/update_agent). A dedicated voice for each language (Cartesia) is only available on an agent running on volai's own engine (see the Voices chapter below) - an agent that stays on ElevenLabs speaks the chosen language with the Anet voice.
12Test call
The "Call me for a test" button on the agent's detail page in the portal makes the agent place a real call to the number you enter - a quick check of how it sounds and how it reacts to your system prompt, without having to dial its number by hand.
Billed like a regular outbound call with the agent, agent surcharge included (see the Pricing chapter below) - no discount, no special rate.
An agent on volai's own voice engine can make a test call even without its own phone number - it goes out over the shared volai line, so the callee sees the volai number on their display, not the agent's. An agent on ElevenLabs without its own number cannot start a test call until you assign it one.
At most 3 test call attempts per account per day, across all agents - every attempt that actually connected counts, even one nobody picked up; an attempt that failed before it could connect (insufficient credit, a busy line) is not counted against the limit. Regular calls through POST /v1/calls have no such stricter limit.
13Voices
Provider selection at creation has three states: useForOutboundTasks: true in POST /v1/agents or create_agent selects volai's own voice engine, false starts on ElevenLabs even with handoff, and omission uses the deployment default, which depends on engine availability, enablement and the configured languages. Choosing cs or sk alone does not guarantee the engine; when the engine default is disabled, creation starts on ElevenLabs. When an explicit false overrides the language's engine default, the creation response carries the elevenlabs_by_explicit_choice warning, so create an agent meant only for incoming calls without the field. When you enable transferTo on an ElevenLabs agent, volai attempts to move it to the engine after saving. The attempt may be paused, unavailable or fail, so verify the result with a follow-up GET /v1/agents/{id} for REST or in the returned agent for MCP. The provider field says which platform an agent runs on; handoff does not work while it remains on ElevenLabs. A successful switch may change its voice. The same attempt follows a language change on an ElevenLabs agent from a language in which new agents start on ElevenLabs (today en, de, pl) to one in which they start on the engine (cs, sk); the agent then gets the new language's default engine voice (Milena, Katarina). A change between cs and sk moves nothing. Moving between platforms otherwise is done by volai support. ElevenLabs accepts only katty from the catalog or a raw ElevenLabs voice id; other catalog voices require the engine.
voiceId on create_agent/update_agent (and the same-named field in POST/PATCH /v1/agents) picks the agent's voice. The unfiltered GET /v1/voices (MCP list_voices with no provider argument) listing does not show the ElevenLabs voice katty - REST only returns it with ?provider=elevenlabs, MCP with the argument provider: "elevenlabs". Cartesia voices (Milena, Jan and the voices for other languages) are for agents on volai's own engine, Katty for agents on ElevenLabs (the note above covers which platform an agent runs on). The older anet voice stays only on agents that already have it - since 12 Sep 2026 ElevenLabs no longer assigns it to new agents, and volai rejects such a request with an explanation. At creation with explicit useForOutboundTasks: true, a recognized catalog voice unavailable on the engine, including katty, is replaced by the engine default for the selected language; when an omitted field selects the engine through the deployment default, the same incompatible voice is rejected. A raw ElevenLabs id is always rejected for the engine. Without voiceId, the agent gets its provider's default voice - Milena on the engine, the template's voice (Katty) on ElevenLabs.
The catalog offers at least one female and one male voice per language (four for Czech today): cs: Milena, Jan, Tereza, Marek; sk: Katarina, Peter; en: Skylar, Daniel; de: Alina, Lukas; pl: Ewa, Kacper. The portal only offers voices in the agent's chosen language - they switch together (see the Languages chapter above).
Every voice in the table belongs to volai's own voice engine. For an agent on ElevenLabs the API rejects them with a 400 - that agent accepts only katty (which the unfiltered listing does not show) and a raw ElevenLabs voice id.
| id | Description | Preview |
|---|---|---|
| milena | Milena - The default volai voice - calm and natural, a good fit for most agents. | |
| jan | Jan - The male counterpart to Milena - matter-of-fact, easy-to-follow delivery. | |
| tereza | Tereza - The second female voice - professional, well-structured delivery. | |
| marek | Marek - The second male voice - calm, resonant delivery for longer calls. | |
| katarina | Katarina - Slovak female voice - calm, natural delivery. | |
| peter | Peter - Slovak male voice - matter-of-fact, easy-to-follow delivery. | |
| skylar | Skylar - English female voice - calm, friendly delivery. | |
| daniel | Daniel - English male voice - matter-of-fact, confident delivery. | |
| alina | Alina - German female voice - calm, warm delivery. | |
| lukas | Lukas - German male voice - matter-of-fact, easy-to-follow delivery. | |
| ewa | Ewa - Polish female voice - calm, natural delivery. | |
| kacper | Kacper - Polish male voice - matter-of-fact, confident delivery. |
voiceId also accepts a raw ElevenLabs ID, but only for an agent on the standard platform (provider: "elevenlabs"). Use a catalog voice id for an agent on the engine. An unknown value or one incompatible with the provider returns an error listing the valid options.
14Statistics
The agent detail screen in the portal shows the number of answered calls, their average and longest length, and how many happened in the last 30 days - there is no dedicated API for this, you can compute the same numbers yourself from GET /v1/calls.
15Pricing
The voice agent is billed on top of the call price, by the second - no rounding up to whole minutes. Rates exclude VAT, like the whole price list.
| Direction | Call | Agent | Total |
|---|---|---|---|
| Outbound | 0.92 CZK/min (~EUR 0.04) | 2.50 CZK/min (~EUR 0.10) | 3.42 CZK/min (~EUR 0.14) |
| Inbound | 0.50 CZK/min (~EUR 0.02) | 2.50 CZK/min (~EUR 0.10) | 3.00 CZK/min (~EUR 0.13) |
Full pricing, with examples, is on the Pricing page.
Prefer your own ElevenLabs, Vapi, or another platform? You can skip the agent surcharge with your own agent - see Bring your own agent.
16Transcripts and webhook
Once a call ends, fetch the transcript and summary via GET /v1/calls/{id} (fields transcript and summary) - or volai can push them to your URL as an event call.completed, once it's ready. The transcript format, signature verification and error handling are on the Webhooks page.
Don't want to wait for a webhook or poll the API? In the portal, every agent's detail page also shows a list of recent calls with the transcript right there to read.
17volai voice engine
Some agents today run on volai's own voice engine instead of ElevenLabs. Switching changes call routing, and the agent's whole configuration moves with it - instructions, opening line, data fields, call goal, knowledge, tools and call transfer. What changes and what doesn't:
- Voices an agent that had an ElevenLabs voice selected (Katty, or the older Anet) gets the engine's default voice for its language once it switches - Milena for Czech. The engine doesn't offer an ElevenLabs voice as its main voice, ElevenLabs stays only as a fallback for a Cartesia outage. The agent's settings then let you pick any other catalog voice for the agent's language, Jan for Czech among them. A voice the agent already has from the engine's catalog is left alone.
- Response time stays the same as ElevenLabs - about 1 second after you finish speaking.
- Recordings unchanged - still kept for 90 days and can be turned off the same way on the agent's detail page.
- Recording notice unchanged - with recording turned on, volai appends a short line to the agent's first message saying the call is recorded here too (see the Recordings section above). With recording off, the line is not appended at all.
- AI disclosure unchanged - the opening line goes to the provider exactly as you wrote it. We don't enforce it: if the line doesn't say the caller is speaking with a digital assistant, we only warn you (EU AI Act, Article 50), saving still goes through. The disclosure stays your responsibility with either provider.
- Tools and call transfer they move with the agent - a successful switch sends the engine its tools and its configured transfer to a human, so you don't have to set them up again. On volai's own voice engine, transfer works bridged (same as the Handoff to a human section above) - the bridge is verified in everyday operation and the portal shows the full transfer form for an agent on the engine. Enabling transfer on an agent on the standard platform (ElevenLabs) triggers an immediate switch attempt after saving; verify the result in `provider`, because a paused attempt, unavailable engine or failure can leave it on ElevenLabs, where transfer does not work. A successful switch may change its voice to the engine default. Bulk number migration in waves therefore skips agents with transfer configured.
- Voicemail detection on outbound calls only volai's own voice engine can do it - within a few seconds of pickup it recognises a voicemail instead of a person and, depending on the setting, just marks it, hangs up, or waits for the beep and reads a message. Set on the agent detail (engine agents only), the `voicemail` field over the API and MCP. The call list then shows "Voicemail answered" for an outbound call with a voicemail instead of the usual outcome. The standard platform (ElevenLabs) has no such detection.
- Silence reminder only volai's own voice engine plays it - when the caller stays silent for a while, the agent asks once whether they're still there. The setting (on/off, 3 to 25 seconds) is saved for either provider - for an agent on the standard platform (ElevenLabs) the field on the agent detail is greyed out and the value is heard once the agent switches to the engine.
- Agent laughter only volai's own voice engine can laugh back when you or the caller laugh or joke during the call - and only with a Czech Cartesia voice (Milena, Jan and the rest of the catalog). The standard platform (ElevenLabs) can't do it at all, even with the field set. In the agent's settings you choose Automatic (the engine turns laughter off on its own for sensitive topics, such as debt collection, healthcare, authorities or funeral services), On (overrides that detection) or Off. The change takes effect from the next call.
18Calendar and appointments
An agent on volai's own voice engine can check a free slot in your Google or Apple calendar right during the call and book the appointment on the spot - it tells the caller whether a time is free, offers the nearest open slots, and books the appointment once it has confirmed a name. Turn it on in the agent editor's Calendar tab: pick the connection (Data and integrations), the specific calendar and the availability rules.
- Availability rules windows per weekday (when the agent offers appointments at all), appointment length, a buffer between appointments, minimum notice before the booked time, and the horizon - how far ahead the agent searches. The editor fills in defaults, but each agent can have its own values.
- Built-in tools the calendar uses two built-in tools, check_availability and book_appointment - unlike the custom tools from the Tools chapter above, they aren't created by hand, they turn on together with the calendar and don't count toward the account's tool limit.
- volai's own engine only works only for an agent on volai's own voice engine. If you turn the calendar on for an agent on the standard platform (ElevenLabs), the setting is saved and the agent tries to switch to volai's engine right after saving - the same as with transfer to a human.
- What the agent says and doesn't say the agent never reads out what's written in the calendar - only whether a given time is free. The caller's phone number is added to the event only when the agent knows it (a hidden number means the event has no phone number).
- Outside a call too the same free-slot search and appointment booking also work outside a call, over REST (POST /v1/integrations/{id}/availability, POST /v1/integrations/{id}/events) and MCP (find_free_slots, create_calendar_event) - see the Calendars section in the REST API reference and the MCP reference for details.
Related
MCP server
Connect Claude Code, Codex CLI, Codex desktop, Cursor and other AI editors.
REST API
Complete reference for every endpoint: numbers, calls, SMS, SMS numbers for receiving, agents and their drafts, tools, recordings, webhooks, do-not-call list, relay, account, tasks, credit, documents, calendars and integrations.
Webhooks
Events, structured data in the body, signature verification, retries on failure.
Bring your own agent
Connect a third-party platform (ElevenLabs, Asterisk...) - no agent surcharge.