Post-Call Webhook

View as Markdown

Add a webhook URL to the request in order to receive information after the call.

Setting up a Webhook

  • Specify the Webhook URL: In your API request body, include the external_webhook_url key with the URL of your webhook receiver.
  • Test with the webhook: For development and testing purposes, you can use webhook.site to simulate receiving webhook data.

API Request Example

Include the following key-value pair in your API request body:

1"external_webhook_url": "www.exmaple.com/webhool_url"

Webhook Response Example

Upon completion of the call, the webhook URL will receive a response like the following. In this case, the agent has three information extractor actions to get information after the call is completed.

1{
2 "status": "completed",
3 "error_message": "",
4 "lead": {
5 "name": "test",
6 "phone_number": "XXXXXXXX",
7 "prompt_variables": {}
8 },
9 "call": {
10 "status": "completed",
11 "end_call_reason": "agent_goodbye",
12 "model_id": "[UUID]",
13 "timezone": "Europe/Berlin",
14 "call_id": "[UUID]",
15 "duration": 113,
16 "start_time": "2025-10-27T10:59:46+01:00",
17 "transcript": "\nbot: Hello, thank you for calling [Summit Valley College]! This is [Brian], the virtual receptionist. How can I assist you today? \nhuman: Hi. I'm\nhuman: what are you? A receptionist of what?\nbot: Hey! I'm the virtual receptionist for Summit Valley College. Basically, I help answer questions, guide you to the right department, or assist with anything related to the college. What can I help you with today? \nhuman: Yeah. Well, I am very busy right now, but\nhuman: I would like to book an appointment.\nbot: Got it! You'd like to meet with an academic adviser tomorrow. Do you have a preferred time, or should I look for the earliest available slot? \nhuman: An academic.\nhuman: An academic adviser, please, and tomorrow if it's possible.\nhuman: Look for the earliest slot, please.\nbot: Alright, I'll check for the earliest available slot with an academic adviser tomorrow. Can I get your full name and a phone number to confirm the appointment? \nhuman: My name is Julian\nhuman: and phone number is the same one I'm calling with.\nbot: Perfect, Julian! I'll use the number you're calling from. Just to confirm, you want the earliest appointment tomorrow with an academic adviser. Is there anything specific you'd like to discuss during your meeting? \nhuman: That would be all. Thank you.\nbot: No worries, Julian! If you think of anything else or need to change your appointment, just let me know. I'm here whenever you need. Have a good one! \nhuman: Same. But, like,",
18 "recording_sid": null,
19 "recording_url": "[REDACTED]",
20 "call_sid": "",
21 "agents_used": [],
22 "diversion": null,
23 "external_id": ""
24 },
25 "executed_actions": {
26 "extract_info_user email": {
27 "name": "extract_info_user email",
28 "action_type": "extract_info_action_type",
29 "call_id": "[UUID]",
30 "model_id": "[UUID]",
31 "workspace_id": "[UUID]",
32 "description": "Get information with question: What is the user's best email for follow ups?",
33 "parameters_hard_coded": {
34 "identifier": "user",
35 "condition": "What is the user's best email for follow ups?",
36 "choices": null,
37 "examples": [
38 "daniel.wasserlauf@paigo.tech",
39 "matt.sun@trychamp.co",
40 "johnSmith@gmail.com",
41 "alice.johnson13@outlook.com"
42 ]
43 },
44 "parameters_from_llm": {},
45 "error_message": null,
46 "speak_on_failure": "",
47 "return_value": {
48 "user email": null
49 },
50 "is_relevant_action": true,
51 "run_action_before_call_start": false,
52 "timestamp": 1761559301.6653843,
53 "timestamp_datetime": "2025-10-27T10:01:41.665384",
54 "parameters_schema": {},
55 "message_before_action": "",
56 "use_hard_coded_message": true,
57 "delay_message_time_seconds": 3,
58 "delay_message": "",
59 "action_failed_timeout": 7,
60 "real_time_action": false,
61 "is_interruptible": true,
62 "action_id": "[UUID]"
63 },
64 "extract_info_zip code": {
65 "name": "extract_info_zip code",
66 "action_type": "extract_info_action_type",
67 "call_id": "[UUID]",
68 "model_id": "[UUID]",
69 "workspace_id": "[UUID]",
70 "description": "Get information with question: What is the user's zip code for their records?",
71 "parameters_hard_coded": {
72 "identifier": "zip",
73 "condition": "What is the user's zip code for their records?",
74 "choices": null,
75 "examples": [
76 "Example 1",
77 "Example 2"
78 ]
79 },
80 "parameters_from_llm": {},
81 "error_message": null,
82 "speak_on_failure": "",
83 "return_value": {
84 "zip code": null
85 },
86 "is_relevant_action": true,
87 "run_action_before_call_start": false,
88 "timestamp": 1761559301.4698737,
89 "timestamp_datetime": "2025-10-27T10:01:41.469874",
90 "parameters_schema": {},
91 "message_before_action": "",
92 "use_hard_coded_message": true,
93 "delay_message_time_seconds": 3,
94 "delay_message": "",
95 "action_failed_timeout": 7,
96 "real_time_action": false,
97 "is_interruptible": true,
98 "action_id": "[UUID]"
99 },
100 "extract_info_annual income": {
101 "name": "extract_info_annual income",
102 "action_type": "extract_info_action_type",
103 "call_id": "[UUID]",
104 "model_id": "[UUID]",
105 "workspace_id": "[UUID]",
106 "description": "Get information with question: What is the user's approximate annual income?",
107 "parameters_hard_coded": {
108 "identifier": "annual",
109 "condition": "What is the user's approximate annual income?",
110 "choices": null,
111 "examples": [
112 "Example 1",
113 "Example 2"
114 ]
115 },
116 "parameters_from_llm": {},
117 "error_message": null,
118 "speak_on_failure": "",
119 "return_value": {
120 "annual income": null
121 },
122 "is_relevant_action": true,
123 "run_action_before_call_start": false,
124 "timestamp": 1761559301.0049357,
125 "timestamp_datetime": "2025-10-27T10:01:41.004936",
126 "parameters_schema": {},
127 "message_before_action": "",
128 "use_hard_coded_message": true,
129 "delay_message_time_seconds": 3,
130 "delay_message": "",
131 "action_failed_timeout": 7,
132 "real_time_action": false,
133 "is_interruptible": true,
134 "action_id": "[UUID]"
135 }
136 },
137 "analysis": {
138 "persona": "true",
139 "style": "true",
140 "steps": "true",
141 "no_repetition": "true",
142 "objections": "not_applicable",
143 "objection_not_defined": "not_applicable",
144 "knowledge": "not_applicable",
145 "goal": "partial",
146 "appointment": "true",
147 "user_sentiment": "partial",
148 "agent_sentiment": "true",
149 "call_completion": "true",
150 "answered_by_human": "true",
151 "opted_in": "true",
152 "no_opt_out": "true",
153 "call_summary": "true",
154 "persona_feedback": "",
155 "style_feedback": "",
156 "steps_feedback": "",
157 "no_repetition_feedback": "",
158 "objections_feedback": "",
159 "objection_not_defined_feedback": "",
160 "knowledge_feedback": "",
161 "goal_feedback": "User didn't specify the exact time for the appointment, but the agent proceeded with booking the earliest available slot.",
162 "appointment_feedback": "",
163 "user_sentiment_feedback": "The user seemed busy and did not engage much beyond booking the appointment.",
164 "agent_sentiment_feedback": "",
165 "call_completion_feedback": "",
166 "answered_by_human_feedback": "",
167 "opted_in_feedback": "",
168 "no_opt_out_feedback": "",
169 "call_summary_feedback": "The user called to book an appointment with an academic adviser for the earliest available slot tomorrow. The agent confirmed the details and completed the booking.",
170 "judge_found_partial_or_error": true,
171 "judge_found_full_error": false,
172 "all_feedback": "User didn't specify the exact time for the appointment, but the agent proceeded with booking the earliest available slot. The user seemed busy and did not engage much beyond booking the appointment."
173 },
174 "metadata": {},
175 "collected_variables": {
176 "user_name": {
177 "value": "Julian",
178 "collected": true
179 },
180 "appointment_date": {
181 "value": "2025-10-28",
182 "collected": true
183 }
184 }
185}

Call Status options

The call object in the webhook response contains a status field which can have various values, each indicating a different state of the phone call. Below is a table explaining these statuses:

Status CodeDescription
pendingPhone call is queued and will be executed.
ringingPhone call is ringing the recipient.
in-progressPhone call is currently active.
completedPhone call was successful.
no-answerPhone call has not been answered.
busyRecipient’s line is occupied with another call.
failedPhone call failed.
canceledPhone call was canceled before completion.
hangup_on_voicemailVoicemail was detected and the call was terminated.
left_voicemailVoicemail was detected and the agent left a voicemail message.
spamCall was flagged as spam.
pausedPhone call is put on hold.
registeredCall has been registered in the system.

End Call Reason options

This end_call_reason parameter provides insight into the reason why a call ended:

Reason CodeDescription
voicemailThe call was answered by voicemail.
voicemail_message_leftThe agent detected voicemail and left a voicemail message.
human_goodbyeThe call was answered by a human, and the human was the first to say goodbye.
agent_goodbyeThe call was answered by a human, and the agent was the first to say goodbye.
human_pick_up_cut_offThe call was answered by a human but was cut off abruptly without a proper goodbye.
max_durationThe call exceeded the maximum set duration.
custom_end_callThe call was ended because a custom end-call reason was triggered. Check custom_end_call_reason for the specific reason.
undefinedThe reason for the call ending is not specified.

When a call ends due to a custom end-call reason, the response also includes a custom_end_call_reason field with the specific condition that triggered the termination (e.g., "Customer is being abusive").

Post-Call Analytics

The analysis object contains automated quality assessments generated after every call. Each field evaluates a specific aspect of the conversation and returns one of the following values:

  • true — the criterion was met
  • false — the criterion was not met
  • partial — the criterion was partially met (only for fields that support it)
  • not_applicable or null — the criterion does not apply to this call

Every field also has a corresponding _feedback field (e.g. persona_feedback) that provides a short explanation when the result is not true. Feedback is empty when the criterion is fully met or not applicable.

FieldPossible ValuesDescription
personatrue / false / not_applicable / nullWhether the agent presented itself according to the persona defined in its prompt.
styletrue / false / not_applicable / nullWhether the conversation tone and wording matched the style defined in the prompt (e.g. professional, casual, friendly).
stepstrue / false / not_applicable / nullWhether the agent followed the steps defined in its prompt in the correct order.
no_repetitiontrue / falseWhether the agent avoided unnecessary repetition. Returns true if the agent did not repeat information the caller had already heard or acknowledged.
objectionstrue / false / not_applicable / nullWhether the agent handled caller objections according to the specific instructions in the prompt. Returns not_applicable when no objections occurred.
objection_not_definedtrue / false / not_applicable / nullHow the agent handled objections that were not covered in the prompt. Returns not_applicable when no such objections occurred.
knowledgetrue / false / not_applicable / nullWhether the agent applied relevant domain knowledge beyond what was provided in its prompt. Returns not_applicable when no outside knowledge was needed.
goaltrue / partial / falseWhether the agent achieved the call objective defined in the prompt. Returns partial when the objective was only partly achieved.
appointmenttrue / false / not_applicable / nullWhether the date, time, and timezone were handled correctly when the caller wanted to book an appointment. Returns not_applicable when no appointment was requested.
user_sentimenttrue / partial / falseWhether the caller’s sentiment was positive during the call.
agent_sentimenttrue / partial / falseWhether the agent’s sentiment was positive during the call.
call_completiontrue / falseWhether the call ended normally with a goodbye. Returns false if the call was cut off mid-conversation.
answered_by_humantrue / falseWhether the call was answered by a human. Returns false if answered by voicemail or another machine, or not answered at all.
opted_intrue / falseWhether the caller expected the call and remembered opting in. Returns false for cold calls without prior opt-in.
no_opt_outtrue / falseWhether the caller did not request to opt out of future communication. Returns false if the caller asked to be removed.
call_summarytrueAlways true. The corresponding call_summary_feedback field contains a concise summary of the call (under 500 characters).

Aggregate Fields

FieldTypeDescription
judge_found_partial_or_errorbooleantrue if any field returned false or partial.
judge_found_full_errorbooleantrue if any field returned false.
all_feedbackstringCombined feedback from all fields that returned partial or false.

Collected Variables

The collected_variables field contains the collected variables (slots) from your conversation flow. This allows you to access user-provided information programmatically.

FieldTypeDescription
collected_variablesobject | nullCollected variables from the conversation flow. Only variables with collected: true are included. May be null if not available.

The object contains the variable names as keys, with each variable having:

FieldTypeDescription
valueanyThe collected value of the variable (string, number, boolean, or null if not collected)
collectedbooleanWhether this variable was successfully collected during the conversation

Example:

1{
2 "collected_variables": {
3 "user_name": {
4 "value": "Julian",
5 "collected": true
6 },
7 "appointment_date": {
8 "value": "2025-10-28",
9 "collected": true
10 }
11 }
12}

Only variables with collected: true are included in the response. System variables and variables with collected: false are filtered out.