The ExoVoiceAnalyze API can be used to derive the Transcript, Summary and Sentiment of a call. It can also be used to Categorise calls based on business-defined categories to help businesses bifurcate their calls (Inbound or Outbound) into the pre-defined categories.
This API can be used for calls that have been made using any Voice Product of exotel, including but not limited to: Click to Call API, Lead Assist, Campaigns, Dashboard Calls etc. The only underlying requirement is that the call_sid should have a call recording associated with it.
Note:- This is an Asynchronous API that accepts the request and provides the Insights via a WebHook hit in the form a POST method on the URL mentioned in the API request body.
This API is chargeable and is not accessible to all Exotel customers by default. Please reach out to your account manager to get this enabled.
http://<API_Key>:<API_Token>@api.exotel.com/v1/Accounts/<account_sid>/Calls/<call_sid>/ExoVoiceAnalyze.json
Parameter Name |
Mandatory/Optional |
Value / Description |
task_id |
Mandatory |
Customer defined identifier for the requested task. This can be any random string. This can be used to map the WebHook response against the request to uniquely identify the incoming POST hit on the WebHook. |
callback_url |
Mandatory |
The CallBack URL where the WebHook hit needs to be made. Only POST method will be used to hit this endpoint. |
categories |
Optional* |
The Business defined categories into which the call has to be categorised. |
insight_tasks |
Mandatory |
Set of AI Insights that can be requested for. Valid values are :-
Any one task or all the tasks can be requested for in a single request. |
*Mandatory only if the “categorise” insight_tasks is one of the tasks.
Note:- The sentiment task will produce only one of the three values of: Positive/Negative/Neutral.
curl --location --request POST 'http://<API_KEY>:<API_TOKEN>@api.exotel.com/v1/Accounts/<Account_SID>/Calls/<Call_SID>/ExoVoiceAnalyze.json' \ --header 'Content-Type: application/json' \ --data-raw '{ "callback_url": "https://WebHookURL.com", "insight_tasks": ["summarization","categorise","sentiment","transcript"], "task_id": "567664345678”, "categories": ["category 1","category 2","category 3","category 4","category 5"] }'
var axios = require('axios'); var data = JSON.stringify({ "callback_url": "https://WebHookURL.com", "insight_tasks": [ "summarization", "categorise", "sentiment", "transcript" ], "task_id": "testPRod", "categories": [ "summary", "insights", "sales" ] }); var config = { method: 'post', url: 'http://<API_KEY>:<API_TOKEN>@api.exotel.com/v1/Accounts/<Account_SID>/Calls/<Call_SID>/ExoVoiceAnalyze.json', headers: { 'Content-Type': 'application/json' }, data : data }; axios(config) .then(function (response) { console.log(JSON.stringify(response.data)); }) .catch(function (error) { console.log(error); });
<?php $curl = curl_init(); curl_setopt_array($curl, array( CURLOPT_URL => 'http://%3CAPI_KEY%3E:%3CAPI_TOKEN%3E@api.exotel.com/v1/Accounts/%3CAccount_SID%3E/Calls/%3CCall_SID%3E/ExoVoiceAnalyze.json', CURLOPT_RETURNTRANSFER => true, CURLOPT_ENCODING => '', CURLOPT_MAXREDIRS => 10, CURLOPT_TIMEOUT => 0, CURLOPT_FOLLOWLOCATION => true, CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1, CURLOPT_CUSTOMREQUEST => 'POST', CURLOPT_POSTFIELDS =>'{ "callback_url": "https://WebHookURL.com", "insight_tasks": ["summarization","categorise","sentiment","transcript"], "task_id": "testPRod", "categories": ["summary","insights","sales"] }', CURLOPT_HTTPHEADER => array( 'Content-Type: application/json' ), )); $response = curl_exec($curl); curl_close($curl); echo $response;
import http.client import json conn = http.client.HTTPSConnection("api.exotel.com") payload = json.dumps({ "callback_url": "https://WebHookURL.com", "insight_tasks": [ "summarization", "categorise", "sentiment", "transcript" ], "task_id": "testPRod", "categories": [ "summary", "insights", "sales" ] }) headers = { 'Content-Type': 'application/json' } conn.request("POST", "/v1/Accounts/<Account_SID>/Calls/<Call_SID>/ExoVoiceAnalyze.json", payload, headers) res = conn.getresponse() data = res.read() print(data.decode("utf-8"))
package main import ( "fmt" "strings" "net/http" "io/ioutil" ) func main() { url := "http://%3CAPI_KEY%3E:%3CAPI_TOKEN%3E@api.exotel.com/v1/Accounts/%3CAccount_SID%3E/Calls/%3CCall_SID%3E/ExoVoiceAnalyze.json" method := "POST" payload := strings.NewReader(`{ "callback_url": "https://WebHookURL.com", "insight_tasks": ["summarization","categorise","sentiment","transcript"], "task_id": "testPRod", "categories": ["summary","insights","sales"] }`) client := &http.Client { } req, err := http.NewRequest(method, url, payload) if err != nil { fmt.Println(err) return } req.Header.Add("Content-Type", "application/json") res, err := client.Do(req) if err != nil { fmt.Println(err) return } defer res.Body.Close() body, err := ioutil.ReadAll(res.Body) if err != nil { fmt.Println(err) return } fmt.Println(string(body)) }
HTTP Response:
{ "request_id": "11a32b11dd8f4257a5d576b6b1719202", "method": "POST", "http_code": 200, "success": true, "reason": "", "ExoVoiceAnalyze": { "job_id": "71191de3-b59c-4485-8372-e7d8139976f2", "task_id": "56775457ABVFRT", "call_sid": "554739565cXXXX5ed17bt", "status": "queued" } }
{ "request_id": "1cb631cbf412481ab91407be29e73bd6", "method": "POST", "http_code": 400, "ResponseData": { "Code": 400, "Message": "Invalid parameter", "Description": "Invalid insight task" } }
Description of parameters mentioned in the above success/failure responses:
Parameter Name | Type & Value | ||||||||||||||||||||||||||
request_id
|
A unique ID for the API request being made. | ||||||||||||||||||||||||||
http_code
|
HTTP response code of your request.
|
||||||||||||||||||||||||||
success | true or false. This shows whether the request succeeded or not. | ||||||||||||||||||||||||||
reason |
Explanation for success / failure |
||||||||||||||||||||||||||
job_id |
The unique identifier that ties an API response to a WebHook hit. |
||||||||||||||||||||||||||
task_id
|
Customer defined string passed in the API request. |
||||||||||||||||||||||||||
call_sid
|
The Call SID for which the Insights are generated. |
||||||||||||||||||||||||||
status
|
The status of the request submitted. The immediate value will by default be “queued” |
{ "success": true, "reason": "", "task_id": "8765Abgt678", "job_id": "5d1ca6b6-4f9b-4f4f-b411-826fcc29cade", "callSID": "2c6050f9cc6eb7f9aee2abd761fe17c7", "summary": { "summary": "Jason, a fresher with a supply chain and analytics background, called looking for a job in logistics or supply chain. The employer mentioned they are currently hiring for logistics but only for experienced candidates. Jason thanked the employer and ended the call.", "confidence": 0.9 }, "sentiment": { "sentiment": "NEUTRAL", "confidence": 0.8 }, "category": { "category": "Jobseeker mentioned they will not be able to move forward", "confidence": 0.7 }, "transcript": "Hello, where do you go?\nHello.\nHi, this is Jason.\nActually, I got your number from India.\nHi, Jason.\nGo ahead and help.\nYeah, actually, I'm looking for a job.\nI did my supply chain and analytics from IIT.\nActually, I'm a fresher.\nI'm looking for a job in logistics or supply chain.\nSo if you have any openings, I'll be really happy for that.\nCurrently, we are hiring for logistics space, but we're looking for somebody who\nbut you can surely send us your updated CV on the email id resume at waytogoconsulting.com I'm sure it's on the post that you found the name send us your CV we can definitely connect with you in case we have anything that's open for freshers okay so you don't have anything right now?\nwe do but nothing for freshers but for experience only\nOh, okay, okay.\nThat's fine then.\nThank you.\nYeah, thanks for calling.\n" }
{ "success": false, "reason": "Forbidden to access recording url of call", "job_id": "d2102824-e353-6765-aa9e-6bde866f2422", "callSID": "91126f1b80XXX88104cc4717bl" }
Description of parameters mentioned in the above success/failure WebHook hits:
Parameter Name | Type & Value |
success | Indicates whether the request succeeded or not. |
reason |
Explanation for success / failure |
job_id |
The unique identifier that ties an API response to a WebHook hit. |
callSID |
The Call SID for which the Insights are generated. |
summary |
The Summary of the conversation |
confidence |
A confidence score from 0 to 1 representing the confidence of the LLM(/s) in the generated insight. |
transcript |
The word to word transcript of the call. Please note that multilingual conversations are supported but the output is always given in English by default. |
categorise |
The category into which the call falls into, based on a best-fit scenario. |
sentiment |
The sentiment of the call. Values are fixed: Positive, Negative or Neutral. |
The ExoMind Tasker API is a cutting edge API that uses multiple language models, large and small, to help your business explore and exploit the benefits of Generative AI. This API allows you to do a host of tasks including but not limited to:
Please note that this API uses ExoML which is an XML based language to instruct the API on the tasks to be accomplished.
ExoML has Verbs and Nouns and both of them have their own attributes as well. Businesses can use these Verbs and Nouns with their relevant attributes to construct and instruct the ExoMind Tasker API to accomplish a host of tasks in a manner and priority of their choosing.
The Exomind Tasker API adapts to the specific context of each task, whether that demands maximised speed for real-time responsiveness, uncompromised accuracy for high-stakes data fidelity, or a balanced approach for general-purpose tasks. This customisation ensures that your application runs optimally, delivering the expected results tailored to the user experience you seek to provide.
This API is chargeable and is not accessible to all Exotel customers by default. Please reach out to your account manager to get this enabled.
Welcome to the forefront of intelligent task management—Exomind Tasker API. A solution that not only understands the requisites of agile and precise task handling but also provides the key to unlock the full potential of your application through a spectrum of optimization options.
Exomind Tasker API offers a range of optimization choices, ensuring that every task is executed with an approach that best suits its nature and your application's demands. This versatility is embedded within our unique optimization mechanism which includes options for various scenarios—each designed to enhance the overall functionality and efficiency of your application without delving into complexities.
Exomind Tasker API adapts to the specific context of each task, whether that demands maximized speed for real-time responsiveness, uncompromised accuracy for high-stakes data fidelity, or a balanced approach for general-purpose tasks. This customization ensures that your application runs optimally, delivering the expected results tailored to the user experience you seek to provide.
Interacting with the /exotasks endpoint is straightforward, ensuring your requirements are met with optimal execution. Below is a snapshot of what submitting a task entails:
https://exomind.exotel.com/api/v1/exotasks
{ "custom_params": "<any valid JSON>", "exoml": "<The ExoML doc containing the flow>" }
“custom_params” are any user defined parameters that need to be pushed as a part of the WebHook hit done on the endpoint. Please note that the “custom_params” are also returned in the Async API response as evidenced below in the Sample Response section.
HTTP Response:
{ "http_code": 2xx, "metadata": null, "method": "POST", "request_id": "<Random request ID generated by system>", "response": { "code": 202, "error_data": null, "status": "success", "data": { "task_sid": "task-SID: Example ab145jdk879", "custom_params": "custom parameter given by customer" } } }
{ "event_details": { "event_type": "verb_event", "event_name": "Verb event name - This depends on the verb that is executed - Example: gather_started, say_completed…", "event_timestamp": "Event timestamp", "task_sid": "<task_sid that was generated during ExoTask creation>", "custom_params": "< if this event is due to an action that was submitted, this should be filled with corresponding custom_params else null>", "event_data": { "<This totally depends on the verb and the event>" } }, "data": { "<Standard fields of ExoTask entity>" } }
{ "event_details": { "event_type": "action_event", "event_timestamp": "Event timestamp", "event_name": "action_failure", "task_sid": "<task_sid - must in this case>", "custom_params": "<the custom parameter that was passed when create ExoTask API was called>", "event_data" { "error_code": "<Indicating reason for failure>", "message": "<one line brief of failure>", "description": "<detailed explanation>" } }, "data": null }
The following are the ExoML Verbs:
We will go over each Verb, it’s attributes along with the associated Nouns and it’s relevant attributes below.
This verb converts media to text
Attribute Name |
Allowed Values |
Default Value |
Mandatory |
resourceFormat |
mp3, wav |
None |
Y |
resourceURL |
valid publicly accessible URL that returns resource file which is of type=resourceFormat |
None |
Y |
speakerDiarization |
True/False |
True |
N |
autoTagSpeakers |
True/False |
True |
N |
customSpeakerLabels |
comma separated labels as str for speakers in given media resource |
“” |
N |
customUniqueID |
any valid str |
“” |
N |
optimizeFor |
comma separated str of enums = [cost, latency] |
“” |
N |
verbEventSubscription |
transcribe_completed, transcribe_failed |
All |
N |
verbEventEndpoint |
Valid HTTP webhook |
None |
N |
verbEventCallbackMethod |
POST |
POST |
N |
This attribute specifies the file type that is either going to be returned when we make GET request on resourceURL OR the base64 encoded file passed in the Noun
This attribute specifies a valid URL that should return a valid file of type=resourceFormat given above, when our system makes a GET on /resourceURL
This attribute specifies a boolean whether to perform speaker diarization on the resource
This attribute specifies a boolean whether to automatically label the detected speakers in the resource using LLM based on diarized transcript
This attribute specifies a comma separated str of user-defined speaker labels that will be used by our system to pick and tag speakers ONLY from the user-defined keywords
This attribute specifies a user-defined unique ID as str so that it becomes useful to refer this ID in supported downstream Verbs / actions if the output of this Verb / action needs to be chained
This attribute specifies a comma separated str of key constraints (enums) => [cost, latency] which the user can pass in the order of decreasing priority. For eg: if optimizeFor=”latency,cost” then our system infers that it needs to optimizeFor latency first and then for cost. This can also be defined at ExoTask level and here the individual verb level values DONOT override the global ExoTask level optimizeFor attribute
This allows the user to specify which verb events should be notified to verbEventEndpoint.
<?xml version="1.0" encoding="UTF-8"?> <Flow> <Transcribe resourceURL="https://example.com/audio" resourceFormat="mp3"></Transcribe> </Flow>
{ "event_details": { "event_type": "verb_event", "event_name": "transcribe_completed", "event_timestamp": "2019-01-10T17:08:00+05:30", "task_sid": "ab145jdk879 - Same as what we returned in API", "custom_params": "abcdefghijklmn - same as what user passed in API request", "event_data" { "<Event related data>" } }, "data": { "<Standard fields of ExoTask entity>", } }
{ "event_data" { "transcript":"Hello World", "confidence":0.95, }, }
{ "event_data": { "error_code": "1234", "message": "asr_failed", "description": "<Reason for Transcribe failed>" } }
This verb converts text in source language to text in target language
Attribute Name |
Allowed Values |
Default Value |
Mandatory |
resourceFormat |
txt |
txt |
Y |
resourceURL |
valid publicly accessible URL that returns resource file which is of type=resourceFormat |
None |
Y |
sourceLanguage |
“auto” OR valid ISO-6391 language code |
“auto” |
N |
targetLanguage |
valid ISO-6391 language code |
“” |
Y |
customUniqueID |
any valid str |
“” |
N |
optimizeFor |
comma separated str of enums = [cost, latency] |
“” |
N |
verbEventSubscription |
transcribe_completed, transcribe_failed |
All |
N |
verbEventEndpoint |
Valid HTTP webhook |
None |
N |
verbEventCallbackMethod |
POST |
POST |
N |
This attribute specifies the file type that is either going to be returned when we make GET request on resourceURL OR the base64 encoded file passed in the Noun
This attribute specifies a valid URL that should return a valid file of type=resourceFormat given above, when our system makes a GET on /resourceURL
This attribute specifies a user-defined unique ID as str so that it becomes useful to refer this ID in supported downstream Verbs / actions if the output of this Verb / action needs to be chained
This attribute specifies a comma separated str of key constraints (enums) => [cost, latency] which the user can pass in the order of decreasing priority. For eg: if optimizeFor=”latency,cost” then our system infers that it needs to optimizeFor latency first and then for cost. This can also be defined at ExoTask level and here the individual verb level values DONOT override the global ExoTask level optimizeFor attribute
This allows the user to specify which verb events should be notified to verbEventEndpoint.
<?xml version="1.0" encoding="UTF-8"?> <Flow> <Translate exoResourceSID=”abcd-1234” targetLanguage=”hi”></Translate> </Flow>
{ "event_details": { "event_type": "verb_event", "event_name": "translate_completed", "event_timestamp": "2019-01-10T17:08:00+05:30", "task_sid": "ab145jdk879 - Same as what we returned in API", "custom_params": "abcdefghijklmn - same as what user passed in API request", "event_data" { "<Event related data>" } }, "data": { "<Standard fields of ExoTask entity>", } }
{ "event_data" { "translation":"வணக்கம் உலகம்", "confidence":0.95, }, }
{ "event_data" { "error_code":"1234", "message":"translator_failed", "description":"<Reason for Translate failed>" }, }
This verb has the ability to take in text as input (typically a natural language query) and output text (typically the answer to that query)
Attribute Name |
Allowed Values |
Default Value |
Mandatory |
customUniqueID |
any valid str |
“” |
N |
optimizeFor |
comma separated str of enums = [cost, latency, determinism, conversational] |
“” |
N |
verbEventSubscription |
query_completed, query_failed |
All |
N |
verbEventEndpoint |
Valid HTTP webhook |
None |
N |
verbEventCallbackMethod |
POST |
POST |
N |
This attribute specifies a user-defined unique ID as str so that it becomes useful to refer this ID in supported downstream Verbs / actions if the output of this Verb / action needs to be chained
This attribute specifies a comma separated str of key constraints (enums) => [cost, latency, determinism, conversational] which the user can pass in the order of decreasing priority. For eg: if optimizeFor=”cost,determinism,conversational” then our system infers that it needs to optimizeFor cost first and then ensure the response is deterministic and also try to make it sound more human-like (conversational). This can also be defined at ExoTask level and here the individual verb level values DONOT override the global ExoTask level optimizeFor attribute
This allows the user to specify which verb events should be notified to verbEventEndpoint.
<?xml version="1.0" encoding="UTF-8"?> <Flow> <Query optimizeFor="determinism">What is the capital of India?</Query> </Flow>
{ "event_details": { "event_type": "verb_event", "event_name": "query_completed", "event_timestamp": "2019-01-10T17:08:00+05:30", "task_sid": "ab145jdk879 - Same as what we returned in API", "custom_params": "abcdefghijklmn - same as what user passed in API request", "event_data" { "<Event related data>" } }, "data": { "<Standard fields of ExoTask entity>", } }
{ "event_data" { "answer":"The capital of India is New Delhi.", "confidence":0.95, }, }
{ "event_data" { "error_code":"1234", "message":"query_failed", "description":"<Reason for Query failed>" }, }
This verb has the ability to either take in text as input or encompass multiple actions like (Transcribe, Translate) and output a final summary as output text which condenses and captures the essence of all the input text passed into this verb
Attribute Name |
Allowed Values |
Default Value |
Mandatory |
customUniqueID |
any valid str |
“” |
N |
optimizeFor |
comma separated str of enums = [cost, latency, determinism, conversational] |
“” |
N |
withSentiment |
True/False |
False |
N |
withIntent |
True/False |
False |
N |
customIntents |
comma separated str of user-defined intents |
“” |
N |
maxWords |
>=1 |
150 |
|
verbEventSubscription |
summarize_completed, summarize_failed |
All |
N |
verbEventEndpoint |
Valid HTTP webhook |
None |
N |
verbEventCallbackMethod |
POST |
POST |
N |
This attribute specifies a user-defined unique ID as str so that it becomes useful to refer this ID in supported downstream Verbs / actions if the output of this Verb / action needs to be chained
This attribute specifies a comma separated str of key constraints (enums) => [cost, latency, determinism, conversational] which the user can pass in the order of decreasing priority. For eg: if optimizeFor=”cost,determinism,conversational” then our system infers that it needs to optimizeFor cost first and then ensure the response is deterministic and also try to make it sound more human-like (conversational). This can also be defined at ExoTask level and here the individual verb level values DONOT override the global ExoTask level optimizeFor attribute
This attribute specifies whether to extract the Natural Language Sentiment (Positive, Negative, Neutral) from the summary
This attribute specifies whether to extract the overall intent, which is the most important action that is conveyed in the summary
This attribute specifies a comma separated str of user-defined intents, which will be used ONLY when withIntent=True to map the extracted intent of the passage within the set of given customIntents
This attribute specifies the max number of words that shall be present in the final output summary
This allows the user to specify which verb events should be notified to verbEventEndpoint.
The only supported noun for the <Summarize> verb is <Input> which is defined below:
Noun |
Description |
<Input> |
Input is used when user wants to define a custom input to the verb or wants to chain the output of any of the previous supported verbs within the same flow as an input to the verb enclosing this noun |
Attribute Name |
Allowed Values |
Default Value |
Mandatory |
type |
verb, txt |
None |
Y |
weightage |
float between 0 to 1 |
0 |
N |
<?xml version="1.0" encoding="UTF-8"?> <Flow> <Summarize optimizeFor="cost" withIntent="True" customIntents="acknowledged_to_pay,refused_to_pay,payment_done_already"> <Input type="txt">Blob of plain text</Input> <Input type="txt">Blob of plain text</Input> </Summarize> </Flow>
<?xml version="1.0" encoding="UTF-8"?> <Flow> <Transcribe exoResourceSID="abc-123" customUniqueID="xyz"></Transcribe> <Transcribe exoResourceSID="abc-223" customUniqueID="pnr"></Transcribe> <Transcribe exoResourceSID="abc-323" customUniqueID="def"></Transcribe> <Summarize optimizeFor="latency,cost" withSentiment="True"> <Input type="verb">xyz</Input> <Input type="txt">Blob of plain text</Input> <Input type="verb">def</Input> </Summarize> </Flow>
{ "event_data" { "summary":"The conversation was between a customer and an agent. The customer enquired about a plan upgrade for which the agent responded courteously with necessary details before ending the conversation", "confidence":0.85, }, }
{ "event_data" { "error_code":"1234", "message":"summarize_failed", "description":"<Reason for Summarize failed>" }, }
Think of Exomind Tasker API as a maestro, orchestrating every aspect of task execution from initiation to completion with an expert's precision. It's not just about choosing an option—it's about harnessing the essence of tailored performance for every task your application handles.
By selecting the most appropriate optimization for each task, Exomind Tasker API:
Maximizes Efficiency: Choose speed when time is of the essence, and watch your application deliver results at a pace that keeps up with your users' expectations.
Ensures Precision: Opt for accuracy when details cannot be compromised, ensuring that the integrity of your data and results stands second to none.
Balances Dynamics: Find the perfect harmony between quick delivery and meticulous detail for everyday tasks, making your application a reliable tool for various use cases.
Exomind Tasker API acts as a natural extension to Exotel's existing communication platform, tapping into the power of voice and messaging services with optimized task management. This harmonization allows for unprecedented efficiency in tasks such as real-time transcription and analysis of calls, processing of customer interactions, and automation of communication-based workflows.
Exomind Tasker API complements the current array of Exotel APIs, providing additional layers of intelligence to smart communication solutions. It does so by leveraging its optimization capabilities to enhance API-driven tasks like sending tailored notifications, automating responses, and integrating with AI-powered customer service bots.
Exomind Tasker API is the strategic advantage in your toolkit, providing the innovation and adaptability that modern applications demand. With its flexible optimization, and an investment in efficiency and precision, this API is more than a feature—it's the cornerstone upon which you can build the next generation of intelligent applications.
Elevate your product to new heights with Exomind Tasker API, where every task is an opportunity for excellence.