analysis on an agent and every call it finishes is read
once more after the hangup. You get a summary, a success verdict against your
own criteria, the fields you asked for in output_schema and, if you give the
agent a list of message templates, the template to send next with its slots
filled in from the conversation.
Analysis runs after the call, so it never slows the conversation down. The
result is on the call, on its own endpoint and in the
call.processed webhook.
Base URL https://sandbox.voice.miraiminds.co. All endpoints require
Authorization: Bearer sk_live_….
Turn it on
Send
analysis on POST /v2/agents or
PATCH /v2/agents/{id}. A PATCH replaces the
whole analysis object, so send every field you want to keep.
"analysis": null turns analysis off. A call runs the analysis settings of the
agent revision it was placed with, so a change applies to calls placed after
it.
Where the result appears
On the call object, inGET /v2/calls/{id} and in data.call of
call.processed:
status is done, failed or skipped. A call that never connected is
skipped, because there is no conversation to read. The same result, with what
we know about sending it to you, is at its own endpoint:
200 OK
state is pending until the analysis has run. If it ends failed, retry it
with POST /v2/calls/{id}/analysis/retry and the body
{"if_generation": <the generation you read>}. The retry runs as the next
generation.
A post-call tool can
read the result as {{ analysis.summary }}, {{ analysis.success }} and
{{ analysis.data.<field> }}.
Pick a follow-up message
Many calls end with a message, such as a WhatsApp template with a payment link or an SMS confirming a date.analysis.templates gives the agent the list of
messages you can send. After each call it picks the one that fits, or none,
and fills in the template’s variables from what was said.
The choice is one extra call to the analysis model, made after the analysis
finishes. It reads your template list, the analysis and the transcript. The
model is told to fill a variable only with a value the conversation or the
analysis established, and every slot it leaves empty is listed as missing.
Choosing a template costs nothing extra.
Give the list in one of two ways:
items: the templates written on the agent. Use this for a short, fixed list, such as approved SMS templates.fetch: a request we send to your system after each call to read the current list. Use this when templates are added and approved outside Mirai, as they usually are for WhatsApp.
templates requires analysis.enabled: true.
The templates object
Each template in
items:
Declare only the slots the conversation can fill. A payment link, a ticket
number or a fixed sender name are yours to fill when you send the message.
Your
instructions reach the model as instructions. The template list and
the transcript reach it as data, and the model is told not to follow
instructions that appear inside them.
Templates from your system
Withfetch, we read your template list after every call, so a template you
add or retire is used from the next call without editing the agent.
The request is written like a post-call HTTP tool’s request and
follows the same rules:
{{ }}placeholders can readvars.*(the call’s variables),call.*(such ascall.id,call.agent_id,call.toandcall.metadata.<key>),now.*,analysis.*(the analysis that just finished) andsecrets.*. Insidebody,"{{= call.metadata }}"sends the whole object with its JSON type.tools.*is refused, because the fetch runs before the post-call tools.- Keep credentials in workspace secrets
and reference them as
{{ secrets.<name> }}. A secret that does not exist is refused when you save the agent, and a secret the fetch uses cannot be deleted until you remove it from the agent (409 secret_in_use). - The same outbound network policy applies: public addresses only, no
redirects. The request carries the
X-Mirai-Call-Idheader. - Each attempt has 5 seconds. A timeout, a network error or a
5xxis retried once. Your answer must be JSON and at most 256 KB.
Answers we can read
We read the list leniently, so most template APIs work as they are.- With
items_path, the list is at that path. - Without it, the answer itself can be the list, or we take the first list we
find under
templates,data,Dataoritems.
name, language, description and variables,
and ignore every other field. variables can be objects with key and
description, or plain strings or numbers that are the keys. An entry can also
be a bare string, which is a template with no variables. An entry without a
name, or with a name already seen, is dropped, and we use the first 200
templates.
All of these answers work:
- Under a key
- A bare list
- Nested
The result: analysis.template
The choice arrives as template inside the analysis, wherever the analysis
appears: the call object, GET /v2/calls/{id}/analysis and call.processed.
A template was chosen
No template fits
The choice could not be made
Check
missing before you send. A template with an empty slot usually cannot
be sent as it is, so decide on your side whether to fill it yourself, send
another template or pass the call to a person.
template is present only when the agent revision the call ran with had
analysis.templates and the analysis completed. Calls of other agents carry no
template key at all.
A template problem never fails the analysis
When the choice cannot be made, whether the fetch timed out or the model named a template that is not in the list, you gettemplate.status: "failed" with its
code. The summary, success and data still arrive, the analysis status is
still done, and post-call tools still run.
Choosing again
POST /v2/calls/{id}/post_call/rerun chooses
again before it sends the new call.processed version, and a fetch reads
your list again. Use it after you fix a template endpoint that was down. The
rerun uses the templates settings the call ran with. If the new choice cannot
be made, the rerun still runs and publishes the template it had.
A retried analysis chooses a template when the
retry completes.
Send the message from a post-call tool
A post-call tool can read the choice as{{ analysis.template.name }},
{{ analysis.template.language }} and {{ analysis.template.variables.<key> }}.
Inside a body, "{{= analysis.template.variables }}" sends the whole map.
missing before it sends. If you would rather
decide in your own backend, skip the tool and act on call.processed.
Example: WhatsApp follow-up
An order confirmation agent ends some calls with a WhatsApp message. The approved templates live in your messaging system, and each brand you serve has its own set, so the agent reads the list for the call’s brand after every call. Store the key for your template API once:analysis on the agent:
- cURL
- Python
- Node.js
metadata, for
example "metadata": { "brand_id": "brand_42" }. After the call, we send your
template API:
call.processed carries:
data.call.analysis.template
payment_link_hi to data.call.to with those two values and adds the
payment link itself.
Example: SMS from a fixed list
An EMI reminder agent ends calls with one of three registered SMS templates. SMS templates registered with Indian operators (DLT) mark each slot as{#var#} and change rarely, so the list lives on the agent. Number the slots
in the order they appear in the text and describe each one, with the format
your template needs.
data.call.analysis.template
3 is in missing because no date was agreed. Your system can hold the
SMS and schedule a call back, or send another template that needs no date.
Errors
A problem inanalysis.templates is a 400 invalid_request when you save the
agent, and the message names the field. The common ones:
Unknown fields inside
templates, a template or a slot are refused too.
Failures after the call never produce an error response. They show up as
template.status: "failed" with the codes above.