×

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. 

POST

http://<API_Key>:<API_Token>@api.exotel.com/v1/Accounts/<account_sid>/Calls/<call_sid>/ExoVoiceAnalyze.json

  • Replace <account_sid> with your Tenant ID which can be seen here.
  • Replace <API_Key> and <API_Token> with the Key and Token found here
  • Replace the <call_sid> with the Call Reference Id. 

    The following are the POST parameters:

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 :-

  • summarization
  • sentiment
  • categorise
  • transcript

Any one task or all the tasks can be requested for in a single request. 

*Mandatory only if the “categoriseinsight_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:

  • On success, the HTTP response status code will be 200
  • Please note that this only signifies the acceptance of the request to generate the Insights and the response in itself are not the Insights. 
{
  "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. 

HTTP Code

Description

200

A successful acceptance of the request to generate the Insights. 

400

Invalid request parameter/Missing mandatory param

429

Too many requests

404

recording url not present/recording not uploaded

404

Call sid not found

405

Method not allowed

400

Call duration too big

400

Invalid Insight Task

400

Invalid callback url

400

Task ID too big

400

Mandatory parameter missing

401

Feature only available to selected account

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.