Post-Call Actions
Decide what a voice agent does on its own after each call: update the caller's contact, create a task or a support ticket, email a team member, send an approved WhatsApp template, or add a row to a Google Sheet, based on the answers the call analysis collected.
Overview
After a call ends, call analysis writes a summary, the caller's sentiment, the outcome and the answers your agent's analysis_variables ask for (for example star_rating, callback_requested). Post-call actions act on those answers automatically.
Each agent has an ordered list of rules. A rule is a set of conditions (all must pass) and one or more actions. A rule with no conditions runs after every analysed call.
| Example | Condition | Actions |
|---|---|---|
| Low rating follow-up | star_rating is at most 2 | Create a task for the manager, email the owner |
| Callback requested | callback_requested is yes | Create a task to call back within 4 hours |
| Ask for a review | star_rating is at least 4 | Send your approved WhatsApp template with your review link |
| Keep a log | none | Add a row to a Google Sheet |
| Remember answers | none | Save the rating and comment on the caller's contact |
Actions run in the background shortly after the analysis finishes. Each action runs at most once per call, its status is recorded per call, and temporary failures are retried with backoff.
Authentication
Authorization: Bearer cm_your_api_keyReading rules, options, recipes, test results and run history needs the bots:read scope. Creating, changing or deleting rules, and the on/off switches, need bots:write.
All paths below are under https://api.callmissed.com/api/v1/bots/{bot_id}/post-call.
Recipes
curl https://api.callmissed.com/api/v1/bots/{bot_id}/post-call/recipes \
-H "Authorization: Bearer cm_your_api_key"Ready-made rules, already filled in from this agent's own analysis variables. Each recipe has a key, a plain-language title and description, available (with unavailable_reason when not), needs (the blanks you still choose) and the rule it would save.
Recipe key | What it does | needs |
|---|---|---|
low_rating_followup | Low rating: create a follow-up task and email you | task_assignee, notify_user |
callback_task | Caller asked for a callback: create a callback task | task_assignee |
happy_review_whatsapp | High rating: send an approved WhatsApp template | whatsapp_template |
save_to_sheet | Add a row for every call to a Google Sheet | sheet |
save_on_contact | Save answers on the caller's contact | contact_fields |
issue_ticket | Caller reported a problem: open a high-priority ticket | none |
Save one with its blanks filled:
curl -X POST https://api.callmissed.com/api/v1/bots/{bot_id}/post-call/rules/from-recipe \
-H "Authorization: Bearer cm_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "recipe": "low_rating_followup",
"fills": { "assignee_user_id": "6f1c…", "notify_user_id": "6f1c…" } }'fills field | Used by |
|---|---|
assignee_user_id | The team member who gets the task or ticket |
notify_user_id | The team member who gets the email. Omit for the workspace owner |
template_id, template_variables | The approved WhatsApp template, and the text for each of its inputs |
integration_id, spreadsheet_id, sheet | The Google Sheets connection, spreadsheet and tab |
contact_field_ids | {answer name: contact field id}. Answers left out get a new contact field |
name | Optional new rule name |
Building blocks
curl https://api.callmissed.com/api/v1/bots/{bot_id}/post-call/options \
-H "Authorization: Bearer cm_your_api_key"Returns everything a rule can use for this agent: variables (its analysis variables with their types), call_fields, operators per type, tokens for text, team, contact_fields, sendable whatsapp_templates with their inputs, and shared Google sheets. Use these ids; a rule that names anything else is refused.
Rules
| Method | Path | What it does |
|---|---|---|
GET | /rules | The agent's rules, in order |
POST | /rules | Add a rule |
PATCH | /rules/{rule_id} | Change a rule; only the fields sent change. {"enabled": false} pauses it |
DELETE | /rules/{rule_id} | Delete a rule. What it already did stays in the history |
GET / PUT | /settings | {"enabled": true}: the agent-wide switch for all its rules |
curl -X POST https://api.callmissed.com/api/v1/bots/{bot_id}/post-call/rules \
-H "Authorization: Bearer cm_your_api_key" \
-H "Content-Type: application/json" \
-d '{
"name": "Low rating follow-up",
"conditions": [ { "field": "star_rating", "op": "lte", "value": 2 } ],
"actions": [
{ "type": "create_task",
"config": { "title": "Low rating ({{star_rating}}) from {{caller_number}}",
"description": "{{summary}}", "due_in_hours": 24 } },
{ "type": "notify",
"config": { "subject": "Low rating from {{caller_number}}", "message": "{{feedback_comment}}" } }
]
}'A rule is checked when it is saved: every condition must name one of the agent's analysis variables (or a call field) with an operator that suits its type, every {{token}} must exist, and every team member, contact field, template and spreadsheet must belong to your workspace. A problem returns 422 with a message saying what to fix.
| Limit | Value |
|---|---|
| Rules per agent | 20 |
| Conditions per rule | 10 |
| Actions per rule | 1 to 5 |
Conditions
{ "field": "...", "op": "...", "value": ... }. field is one of the agent's analysis variable names, or call.sentiment, call.disposition, call.goal_met or call.direction.
| Field type | Operators |
|---|---|
number | eq, ne, lt, lte, gt, gte, between (value: [low, high]), is_empty, is_not_empty |
boolean | is_true, is_false, is_empty |
enum | is, in (value is a list of options), is_empty, is_not_empty |
string | contains, is, is_empty, is_not_empty |
An unanswered variable never matches a comparison, only is_empty. If a variable is later removed from the agent, conditions on it stop matching.
Actions
{ "type": "...", "config": { ... } }. Text fields take {{tokens}}: any analysis variable, plus summary, sentiment, disposition, goal_met, caller_number, contact_name, agent_name, call_date, call_time, call_duration, call_direction and call_link.
type | config | Notes |
|---|---|---|
set_contact_fields | fields: [{field_def_id or create_field: {label, field_type}, value}], create_contact (default true) | Writes custom fields on the contact with the caller's number, creating the contact if needed. Only when the number is verified: outbound calls and WhatsApp calls always are; inbound phone calls only when the agent trusts caller ID |
create_task | title, description, assignee_user_id, due_in_hours (0-720) | Linked to the caller's contact when there is one |
create_ticket | subject, description, priority (low, normal, high, urgent), assignee_user_id | Your ticket routing rules apply |
notify | user_id (omit for the workspace owner), subject, message | An email to an active member of your workspace |
send_whatsapp_template | template_id, variables: {input key: text} | An approved template without a media header, from a connected number on its WhatsApp account |
append_sheet_row | integration_id, spreadsheet_id, sheet, columns: [{header, value}] (1-30) | Missing header cells are added to the tab first |
WhatsApp consent. A message is never sent to a number that opted out of your WhatsApp messages or is on your do-not-contact list. A marketing template is sent only to contacts who agreed to receive WhatsApp messages. The action is recorded as skipped, with the reason, when either applies. WhatsApp messages are billed as usual.
Test a rule
curl -X POST https://api.callmissed.com/api/v1/bots/{bot_id}/post-call/dry-run \
-H "Authorization: Bearer cm_your_api_key" \
-H "Content-Type: application/json" \
-d '{ "session_id": "…" }'Runs the agent's saved rules (or one rule_id, or an unsaved rule) against a past call of this agent. For each rule: matched, each condition with the call's actual value and passed, and for each action a plain-language would and a blocked_reason when it would be held back. Nothing is sent, saved or created. GET /recent-calls?limit=20 (1-50) lists the agent's latest analysed calls to pick from. A call without a finished analysis returns 409.
Run history
curl "https://api.callmissed.com/api/v1/bots/{bot_id}/post-call/runs?session_id=…" \
-H "Authorization: Bearer cm_your_api_key"One entry per action per call, newest first (limit 1-100, default 50; offset 0-10000): rule_name, action_type, status (pending, running, succeeded, failed, skipped), attempts, error (why it failed or was skipped) and result (for example task_id, ticket_id, contact_id, send_id).
From an AI assistant
The Account MCP server can set all of this up: list_post_call_recipes, get_post_call_options, create_post_call_rule_from_recipe, create_post_call_rule, update_post_call_rule, toggle_post_call_rule, set_post_call_actions_enabled, delete_post_call_rule, list_post_call_recent_calls, dry_run_post_call_rule and list_post_call_action_runs. The post_call_actions playbook (get_playbook) walks an assistant through interviewing you first.
Call Notes & Scoring
Turn a finished call or chat into structured notes, push them to your CRM, and grade the conversation against a QA scorecard you write — with a transcript quote behind every score.
Voice Data Retention
Delete an agent's call transcripts and recordings after a set number of days, or run it with zero data retention so no call content is kept at all.