Assistants
IVR router mode
Answer every call with a short router that works out what the caller needs, then transfers them or hands the call to the full assistant mid-conversation.
An assistant in IVR router mode does not answer its own calls. A small router picks up first, asks what the caller needs, and then does one of two things: transfers the caller straight to a person, or hands the call to the full assistant and steps out of the way. The endpoints used here are in the Assistants and Prompts API reference.
Overview#
The router is deliberately small. It greets the caller, listens, and routes. It has no tools, no knowledge base and no access to your business logic, so there is very little it can get wrong.
Two things can happen once the router knows what the caller wants:
- Transfer. The request matches one of the assistant's transfer reasons, and the router puts the caller through to the number that reason points at.
- Handoff. The request needs the real assistant. The full assistant introduces itself, acknowledges what the caller already said to the router, and carries on in its own voice, on its own model, with its own prompt and its whole toolset. The caller does not repeat themselves and the call is never restarted.
The handoff happens inside the same call. From the caller's side it sounds like being passed to a colleague who has already been briefed.
Prerequisites#
- An assistant you can update, with its voice, model and prompt already configured. See Create an assistant.
- Transfer reasons on that assistant, if you want the router to be able to transfer. The router routes on the assistant's configured reasons and has no destinations of its own.
Turn on the router#
Write the router prompt#
The router runs from its own prompt, created with type: "ivr". It is a separate prompt resource, so several assistants can share one router script while keeping their own main prompts. See Prompts for the rest of the resource.
Write it as a greeter rather than as a second assistant. Aim for two short turns: greet, find out what the caller needs, route.
curl -X POST https://core-api.heysadie.ai/prompts \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"name": "Front desk router",
"type": "ivr",
"prompt": "You are the first voice on a call for {assistant_name}. Greet the caller and ask what they need. Keep every turn to one sentence.\n\nIf the caller wants a person, use these rules:\n{transfer_instructions}\n\nFor anything else, call {handoff_tool_name} and pass a short note describing what the caller asked for."
}'Keep the returned id. That is the promptId you put in ivrSettings.
Router prompts are a normal prompt type, so GET /prompts?type=ivr lists only these and keeps them out of the way when you are picking a voice prompt.
Choose a voice, model and greeting#
All three are optional. Leave them out and the router uses the assistant's own voice, the assistant's model, and the assistant's firstMessage as its greeting, which is usually what you want for a router the caller should not notice.
Set them when the router should sound or open differently from the assistant. A distinct greetingMessage is the most common one, because a good router opening ("Thanks for calling. How can I help?") is shorter than a good assistant opening. llmModel is there for running the router on a lighter model than the assistant; leave it unset unless you have a specific model in mind.
The voice carries one constraint: it must come from the same text-to-speech provider as the assistant's voice, so the caller does not hear the speaker change on handoff. A voice from another provider is rejected when you save the settings. Both IDs come from GET /voices; see Choosing a voice, model, and transcriber.
Enable it on the assistant#
Everything lives in one object, ivrSettings, on POST /assistants and PATCH /assistants/{id}.
curl -X PATCH https://core-api.heysadie.ai/assistants/0195f1e2-0000-0000-0000-000000000000 \
-H "Authorization: ApiKey YOUR_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"ivrSettings": {
"ivrMode": true,
"promptId": "0195f1e2-0000-0000-0000-000000000001",
"voiceId": "0195f1e2-0000-0000-0000-000000000002",
"greetingMessage": "Thanks for calling. How can I help?",
"handoffAudioCueEnabled": true
}
}'promptId is checked as you save: it must be a prompt your tenant can see and its type must be ivr. A prompt that does not exist, belongs to another tenant, or is a voice prompt is refused rather than stored.
Call the number#
Ring the phone number on the assistant and ask for something a transfer reason covers. You should hear the greeting, one clarifying turn at most, and then the transfer.
Call again and ask for something no transfer reason covers. This time the assistant introduces itself and answers, with a short cue in between while the handoff completes. Set handoffAudioCueEnabled to false if you would rather that moment were silent.
What the router prompt can reference#
Three placeholders are filled in for you when the call starts. Write them exactly as shown, in single braces.
| Placeholder | Filled in with |
|---|---|
{assistant_name} | The assistant's name, so one router prompt can serve several assistants. |
{transfer_instructions} | The assistant's transfer reasons, written out as routing rules. |
{handoff_tool_name} | The name of the tool the router calls to hand the caller over. Name it in your prompt so the router knows what to reach for. |
What the router can and cannot do#
The router is scoped to routing. It can transfer using the assistant's transfer reasons, end the call, and hand off. That is the whole list.
Your tools and your knowledge base stay with the full assistant and are never exposed to the router. A caller who asks a question that needs either one is handed off, so the answer comes from the assistant that has the context rather than from a greeter guessing.
ivrSettings reference#
| Key | Type | Required | Description |
|---|---|---|---|
ivrMode | boolean | Yes, to run a router | Turns the router on. With false, the assistant answers its own calls as usual and the rest of the object is kept but unused. |
promptId | UUID | Yes, to run a router | A prompt of type ivr owned by or visible to your tenant. Validated on save. |
voiceId | UUID | No | A voice from GET /voices, from the same provider as the assistant's voice. Falls back to the assistant's voice. |
llmModel | string | No | The model the router reasons with, as a model identifier rather than a catalogue ID. GET /models publishes it as the model field on each entry. Falls back to the assistant's model. |
greetingMessage | string | No | The router's opening line. Falls back to the assistant's firstMessage. |
handoffAudioCueEnabled | boolean | No | Plays a short cue while the handoff completes. Defaults to true. |
A key set to null reads as unset, and the fallback in the table applies.
Update and clear the settings#
ivrSettings is its own field rather than part of settings, but it merges the same way.
ivrSettings merges per key
A PATCH that sends part of ivrSettings keeps every key you did not send. Switching the
router off is one key:
{ "ivrSettings": { "ivrMode": false } }The prompt, voice, model and greeting all survive that, so turning the router back on later
is the same single key with true. To drop the configuration entirely, send
"ivrSettings": null. To clear one key and take its fallback, send that key as null;
omitting it changes nothing.
If you would rather not depend on merge behavior at all, read the assistant with GET /assistants/{id}, change the object you get back, and send it whole. That is correct either way, and it is the safer habit when two people or two systems edit the same assistant.
When the configuration is incomplete#
Router mode fails open. Every path that could leave a caller talking to a broken router leaves them talking to the normal assistant instead.
| What is wrong | What the caller gets |
|---|---|
ivrMode is on but promptId is unset | A normal call, answered by the full assistant. |
The referenced prompt was deleted, or is not type ivr | A normal call. |
| The router voice was removed from the catalogue | A normal call. |
A misconfigured router is never a dead line or a silent answer. The cost of that is quietness: a call which skipped the router sounds entirely normal, so nothing tells you it happened. The reports below are where you check which path a call actually took.
What the reports show#
The end-of-call report always names the prompt that was actually live, which is what you need when a call did not sound the way you expected.
- A call the router handled on its own, by transferring or ending it, reports the router prompt.
- A call that handed off carries both system prompts, with the moment of handoff timestamped, so you can see how long the router held the caller and read each half of the conversation against the prompt that produced it.
Next steps#
- Transfer reasons: the rules the router transfers on, and the destinations each one points at.
- Prompts: the prompt resource, its types, and how prompts are shared across assistants.
- Create an assistant: the assistant the router hands the call to.
- End-of-call report: the payload that tells you which prompt ran.