×

To make a call connecting agent to customer, you will need to make a HTTP POST request to

POST

https://<your_api_key>:<your_api_token><subdomain>/v2/accounts/<your_sid>/calls

Example (For Singapore Stamp)-

POST

https://<your_api_key>:<your_api_token>@ccm-api.exotel.com/v2/accounts/<your_sid>/calls

Example (For Mumbai Stamp)

POST

https://<your_api_key>:<your_api_token>@ccm-api.in.exotel.com/v2/accounts/<your_sid>/calls

  • Replace <your_api_key> and <your_api_token> with the API key and token created by you OR use Basic Authentication.
  • Replace <your_sid> with your “Account sid”
  • Replace <subdomain> with the region of your account
    1. <subdomain> of Singapore cluster is @ccm-api.exotel.com
    2. <subdomain> of Mumbai cluster is @ccm-api.in.exotel.com
  • Replace <user_id> with the user's unique identifier and device identifier as present in GET user details API.

<your_api_key> , <your_api_token> and <your_sid> are available in the API settings page of your Exotel Dashboard

The following are the POST parameters supported with Content-Type: application/json set in the header

Parameter Name

Mandatory / Optional

Value

from

Mandatory

JSON block indicating the number to be dialed first (leg1). API will allow the call to made only if the user device is available (turned ON) and free (not busy on another call).

Possible inputs-

  • user_contact_uri - Phone Number in E.164 format of an agent (user) in your account or SIP URI if VOIP calling is enabled. If more than 1 agent matches with the same contact_uri, the first agent by default will be selected. Example -

    "from": {
       "user_contact_uri": "+9199XXXXXXX",
    }

    OR

  • user_id - UUID of the user (agent) as added in the account. Replace <user_id> with the user's unique identifier as present in GET user details API. Example -

    "from": {
       "user_id": "4t8ya6b29ce9a5XXXXXXXXXXXX"
    }

to

Mandatory

JSON block containing the phone number of the customer (leg2) to be connected to agent.

  • customer_contact_uri - Phone Number in E.164 format which will be dialed if Leg1 (agent) picks up.

Example -
"to": {
    "customer_contact_uri": "+9199XXXXXXX"
}

virtual_number

Mandatory

ExoPhone (Virtual Number) present in your account in E.164 format or local format for Indian virtual numbers. This will be the number that will be used to make the call to both agent (leg1) and customer (leg2).

Example -

"virtual_number": "+911454XXXX"

recording

Optional

Boolean; Record the conversation of your call. The RecordingUrl will be sent to the StatusCallback URL if this is set to 'true' and the call conversation happens. Can be:

  • true - Call conversation will be recorded.
  • false (default) - Call conversation will not be recorded.

recording_channels

Optional

String; Number of audio channels to be present in the final recording. This parameter works if Record is set to 'true'. Can be:

  • single (default) - Record both legs of the call in a single channel of the recording file.
  • dual - Record the caller and the callee into separate channels of the recording file.

wait_audio_url

Optional

String; Play this audio to the caller. When the first leg (From) has to wait for the other leg (To) to pick up the call, the audio file specified in this parameter will be played.

Please refer this article to understand the format specifications of the audio file to be played (wav is only supported).

Guidelines on usage:

  • The audio file size is recommended to be less than 2MB. Please note, Exotel will cache the wav file. During the first few call attempts of setting this parameter, user might hear normal ringing tone for first 5 seconds (for a ~2MB file). This is only temporary for initial few calls and once the audio file is cached, audio will be played out smoothly.
  • In case you decide to change the audio file later, the WaitUrl should be different (as Exotel will cache audio file based on URL). You can do so by hosting the audio file with a different name.
  • When using this parameter, it is recommended to set the TimeOut parameter as well.

Example: "http://{your_hosted_endpoint}/{audio file name}.wav"

max_time_limit

Optional

Integer; The time limit (in seconds) that you want this call to last. The call will be cut after this time

attempt_time_out

Optional

Integer; The time (in seconds) to ring the called parties (both first and second call leg)

custom_field

Optional

String; Any application specific value like order id that will be passed back as a parameter in StatusCallback

status_callback

Optional

Array; StatusCallback events to be received against the call. Answered/Terminal or both events can be subscribed.

  • Supported Events
    • answered - This will be triggered for each leg (agent and customer) if and when they answer the call.
    • terminal - This will be triggered once the call is over.
  • Refer to event payloads in next section. 

Request example-


[
   {
      "event": "answered",
      "url": "<webhook-url>"
   },
   {
      "event": "terminal",
      "url": "<webhook-url>"
    }
]

StatusCallback

Refer to the StatusCallback different event payloads that'll be received by your endpoint

{
  "event_details": {
    "event_type": "answered"
  },
  "call_details": {
    "call_sid": "906960925ec65c4bf46b90101b98156u",
    "direction": "outbound",
    "virtual_number": "+91804568XXXX",
    "call_state": "active",
    "call_status": null,
    "assigned_agent_details": {
      "user_id": "12898c52573645739e64864ad308f0a9",
      "user_name": null,
      "contact_uri": "+9199531XXXXX",
      "group_id": null,
      "group_name": null,
      "status": "in-progress"
    },
    "customer_details": {
      "contact_name": null,
      "contact_uri": "+9199531XXXXX",
      "status": null
    },
    "created_time": "2021-06-30T02:43:13+05:30",
    "updated_time": "2021-06-30T02:43:19+05:30",
    "start_time": "2021-06-30T02:43:19+05:30",
    "end_time": null,
    "total_duration": null,
    "total_talk_time": null,
    "custom_field": "12130y124b2f142",
    "app_id": null,
    "app_name": null,
    "digits": null,
    "recordings": null
  }
}
{
  "event_details": {
    "event_type": "answered"
  },
  "call_details": {
    "call_sid": "906960925ec65c4bf46b90101b98156u",
    "direction": "outbound",
    "virtual_number": "+91804568XXXX",
    "call_state": "active",
    "call_status": null,
    "assigned_agent_details": {
      "user_id": "12898c52573645739e64864ad308f0a9",
      "user_name": null,
      "contact_uri": "+9199531XXXXX",
      "group_id": null,
      "group_name": null,
      "status": "in-progress"
    },
    "customer_details": {
      "contact_name": null,
      "contact_uri": "+919953XXXXX",
      "status": "in-progress"
    },
    "created_time": "2021-06-30T02:43:13+05:30",
    "updated_time": "2021-06-30T02:43:24+05:30",
    "start_time": "2021-06-30T02:43:19+05:30",
    "end_time": null,
    "total_duration": null,
    "total_talk_time": null,
    "custom_field": "12130y124b2f142",
    "app_id": null,
    "app_name": null,
    "digits": null,
    "recordings": null
  }
}
{
  "event_details": {
    "event_type": "terminal"
  },
  "call_details": {
    "call_sid": "906960925ec65c4bf46b90101XXXXXX",
    "direction": "outbound",
    "virtual_number": "+91804568XXXXX",
    "call_state": "terminal",
    "call_status": "completed",
    "assigned_agent_details": {
      "user_id": "12898c52573645739e64864ad308f0a9",
      "user_name": "Sarthak XXXX",
      "contact_uri": "+9199531XXXX",
      "group_id": null,
      "group_name": null,
      "status": "completed"
    },
    "customer_details": {
      "contact_name": "Sarthak XXXX",
      "contact_uri": "+919953XXXXX",
      "status": "completed"
    },
    "created_time": "2021-06-30T02:43:13+05:30",
    "updated_time": "2021-06-30T02:43:32+05:30",
    "start_time": "2021-06-30T02:43:19+05:30",
    "end_time": "2021-06-30T02:43:32+05:30",
    "total_duration": null,
    "total_talk_time": 5,
    "custom_field": "12130y124b2f142",
    "app_id": null,
    "app_name": null,
    "digits": null,
    "recordings": [
      {
        "url": "https://s3-ap-southeast-1.amazonaws.com/exotelrecordings/Exotel/906960925ec65c4bf46b901XXXXX.mp3"
      }
    ]
  }
}
curl -X POST 
  https://<your_api_key>:<your_api_token><subdomain>/v2/accounts/<your_sid>/calls 
  -H 'content-type: application/json' 
  -d '{
    "from": {
        "user_contact_uri": "+91995312XXXX"
    },
    "to": {
        "customer_contact_uri": "+91995312XXXX"
    },
    "virtual_number": "+91804568XXXX",
    "recording": true,
    "custom_field": "12130y124b2f142",
    "status_callback": [
    	 {
            "event": "answered",
            "url": "https://your-server.com"
        },
        {
            "event": "terminal",
            "url": "https://your-server.com"
        }
    ]
  }'
var request = require("request");

var options = { method: 'POST',
  url: 'https://<your_api_key>:<your_api_token><subdomain>/v2/accounts/<your_sid>/calls',
  headers: 
   { 'content-type': 'application/json',
  body: 
   { from: { user_contact_uri: '0995312XXXX' },
     to: { customer_contact_uri: '0995312XXXX' },
     virtual_number: '+91804568XXXX',
     recording: true,
     custom_field: '12130y124b2f142',
     status_callback: 
      [ { event: 'answered',
          url: 'https://your-server.com' },
        { event: 'terminal',
          url: 'https://your-server.com' } ] },
  json: true };

request(options, function (error, response, body) {
  if (error) throw new Error(error);

  console.log(body);
});
<?php

$request = new HttpRequest();
$request->setUrl('https://<your_api_key>:<your_api_token><subdomain>/v2/accounts/<your_sid>/calls');
$request->setMethod(HTTP_METH_POST);

$request->setHeaders(array(
  'content-type' => 'application/json',
));

$request->setBody('{
    "from": {
        "user_contact_uri": "0995312XXXX"
    },
    "to": {
        "customer_contact_uri": "0995312XXXX"
    },
    "virtual_number": "+91804568XXXX",
    "recording": true,
    "custom_field": "12130y124b2f142",
    "status_callback": [
    	 {
            "event": "answered",
            "url": "https://your-server.com"
        },
        {
            "event": "terminal",
            "url": "https://your-server.com"
        }
    ]
}');

try {
  $response = $request->send();

  echo $response->getBody();
} catch (HttpException $ex) {
  echo $ex;
}
import requests

url = "https://<your_api_key>:<your_api_token><subdomain>/v2/accounts/<your_sid>/calls"

payload = '{ "from": { "user_contact_uri": "0995312XXXX" }, "to": { "customer_contact_uri": "0995312XXXX" }, "virtual_number": "+91804568XXXX", "recording": true, "custom_field": "12130y124b2f142", "status_callback": [ { "event": "answered", "url": "https://your-server.com" }, { "event": "terminal", "url": "https://your-server.com" } ] }'
headers = {
'content-type': "application/json"
    }

response = requests.request("POST", url, data=payload, headers=headers)

print(response.text)
package main

import (
"fmt"
"strings"
"net/http"
"io/ioutil"
)

func main() {

url := "https://<your_api_key>:<your_api_token><subdomain>/v2/accounts/<your_sid>/calls"

payload := '{ "from": { "user_contact_uri": "0995312XXXX" }, "to": { "customer_contact_uri": "0995312XXXX" }, "virtual_number": "+91804568XXXX", "recording": true, "custom_field": "12130y124b2f142", "status_callback": [ { "event": "answered", "url": "https://your-server.com" }, { "event": "terminal", "url": "https://your-server.com" } ] }'

req, _ := http.NewRequest("POST", url, payload)

req.Header.Add("content-type", "application/json")


res, _ := http.DefaultClient.Do(req)

defer res.Body.Close()
body, _ := ioutil.ReadAll(res.Body)

fmt.Println(res)
fmt.Println(string(body))

}

HTTP Response:

  • On success, the HTTP response status code will be 200. Please note that a 200 OK isn’t a confirmation of a call being successfully placed/answered. Refer to the StatusCallBack or the GET Call Details API to understand the status of the call.
  • the HTTP body will contain an JSON similar to the one below:
{
    "request_id": "9e5761038e104704b684d6791178481c",
    "method": "POST",
    "http_code": 200,
    "metadata": null,
    "response": {
        "code": 200,
        "error_data": null,
        "status": "success",
        "data": {
            "call_sid": "9133c5d2ad930f4c7ca43645e535157d",
            "direction": "outbound",
            "virtual_number": "+91804568XXXX",
            "call_state": "active",
            "call_status": null,
            "assigned_agent_details": {
                "user_id": "12898c52573645739e64864ad308f0a9",
                "user_name": null,
                "contact_uri": "+91995312XXXX",
                "group_id": null,
                "group_name": null,
                "status": null
            },
            "customer_details": {
                "contact_name": null,
                "contact_uri": "+9199531XXXX",
                "status": null
            },
            "created_time": "2021-07-13T17:56:47+05:30",
            "updated_time": "2021-07-13T17:56:48+05:30",
            "start_time": "2021-07-13T17:56:48+05:30",
            "end_time": null,
            "total_duration": null,
            "total_talk_time": null,
            "custom_field": "12130y124b2f142",
            "app_id": null,
            "app_name": null,
            "digits": null,
            "recordings": null
        }
    }
}
Parameter Name Type & Value
request_id This indicates the unique id of the request. Useful for debugging and tracing purposes.
method This indicates the HTTP method for the request such as GET/POST/PUT etc.
http_code This indicates the HTTP code for the request such as 200, 400, 500 etc.
response

Response block contains the user device record matching the request URI. The block contains

  • code - This indicates the http code for the particular record in the response array like 200, 400 etc.
  • error_data - This block will be null if there is no error else contain error information for the response with following fields
    • code - This would be the error code useful for Exotel's team to debug and can be highlighted in case of unexpected errors.
    • description - This describes the details of the error.
    • message - This is the error message corresponding to the error code useful for Exotel's team to debug and can be highlighted in case of unexpected errors.
  • status - This field would indicate status of the response (success/failure).
  • data - This block will contain the information corresponding to the response array element and will contain the fields for a user record as explained below. 

Description of parameters under 'data' block:

Parameter Name Description
call_sid

string; an alpha-numeric unique identifier of the call

direction
  • inbound - Incoming call to a virtual number (Exophone)
  • outbound - Outbound calls (Initiated by the agent via Dashboard or API)
virtual_number

The virtual number (ExoPhone) where the call landed (Incoming) or was used to initiate the call (Outgoing)

call_state
  • active: call is not yet over OR post call processing data is yet to be processed
  • terminal: call is over and data is processed against it
call_status
  • completed - Call is completed and agent/customer had a conversation.
  • agent_unanswered - Agent leg was unanswered due to various reasons such as switched off, not reachable, no-answer, busy, connection failed etc.
  • customer_unanswered - Customer leg was unanswered due to various reasons such as switched off, not reachable, no-answer, busy, connection failed etc.
  • agent_canceled - Agent canceled the call while customer was dialed. This could happen during ringing, blank calls or during an operator message such as switched off, no-answer, busy etc.
  • customer_no_dial - There was no dial initiated to customer (rare scenario)
  • agent_no_dial - There was no dial initiated to agent (rare scenario)
assigned_agent_details

assigned_agent_details will be the details of the agent who is the primary agent assigned for the call. In case of-

  • Outbound Connecting 2 numbers: Assigned agent is corresponding to user_contact_uri as provided in 'from'  for outbound call connecting 2 numbers (Leg1)
  • Inbound / Outbound flow calls: Assigned agent is corresponding to the last agent that was attempted in the call flow (including transfer) who may or may not have answered (Leg2)

Fields

  • "user_id": unique UUID of the agent
  • "name": Name of the agent
  • "contact_uri": Phone Number or SIP device URI of the agent’s device
  • "group_id":  group id of which agent was part of as per the call attempt else set to null (in case of outgoing or direct transfer to agent)
  • "group_name": Name corresponding to the group id
  • "call_status": Indicates the call status of the agent leg
    • in-progress - The call was answered and is currently in progress
    • completed - The call was answered and has ended normally
    • failed - The call could not be completed as dialled, most likely because the phone number was non-existent
    • busy - The caller received a busy signal
    • no-answer - The call ended without being answered
customer_details

This is the number the caller called from (for inbound calls), or the number the call was placed to (for outbound calls), and is equal to

  • leg2 (outbound call connecting 2 numbers)
  • leg1 (inbound calls / outbound call connecting to flow)

Fields-

  • "contact_name": Customer Name as stored in Address Book otherwise set as null
  • "contact_uri": Customer Phone Number
  • "call_status": Indicates the call status of the customer leg
    • in-progress - The call was answered and is currently in progress
    • completed - The call was answered and has ended normally
    • failed - The call could not be completed as dialled, most likely because the phone number was non-existent
    • busy - The caller received a busy signal
    • no-answer - The call ended without being answered
    • null - customer leg was not dialled or N/A
created_time

DateTime as per ISO 8601 date format at which the user initiated the call via API.
Eg- 2021-07-28T02:59:34+05:30

updated_time DateTime as per ISO 8601 date format at which the call data was last updated in our system
Eg- 2021-07-28T02:59:34+05:30
start_time DateTime as per ISO 8601 date format when the call request was initiated to the operator
Eg- 2021-07-28T02:59:34+05:30
end_time DateTime as per ISO 8601 date format when the call ended
Eg- 2021-07-28T02:59:34+05:30
total_duration Total call duration in seconds (From start_time to end_time)
total_talk_time

Total time a customer was on call. If there were more than one conversation, it would be the sum of all conversations.

Eg- Agent 1 spoke to Customer for 5 minutes and transferred to Agent 2 and spoke to customer for 10 minutes, total_talk_time for the call would be 15 minutes.

custom_field The value that was passed in the custom_field parameter of the API (if set during the request) will be populated here.
app_id

Flow ID which was used at the start of the call. Null if flow was not used.

app_name Flow Name which was used at the start of the call. Null if flow was not used.
digits

DTMF digits pressed during the call separated by “-” for different applets. Similar to how it is represented in Call Reports.

recordings

Array; It will contain all recordings associated with the call. Each array will contain

  • url - This will represent the playable URL for the corresponding recording

*Some of the above parameters can be null for POST response as they'll be not set immediately after call creation

Possible error scenarios in case of this POST API - 

HttpCode Code Description
401 1010
Authentication failed
404 10731
User not found
409 1012
User device is unavailable
409 10705
User device is unverified
409 10706
User device is currently busy
404 10806
No device found for user
404 1017
AccountSid not found
404 10702
User Device not found
409 10705
User device is unverified
404 1021
Call not found / unsupported in this API
404 1022
Call not found / unsupported in this API
400 1001
account_sid is mandatory
400 1002
Valid values for RecordingChannels are single, dual
500 1100
Internal Server Error
500 1101
Internal Server Error
500 1200
Internal Server Error
404 10703
Device is currently unavailable (turned off)
500 1203
Internal Server Error
500 1300
Internal Server Error
405 10712
VOIP calls are not allowed
500 1500
Internal Server Error
500 1600
Internal Server Error
500 1601
Internal Server Error
500 1800
Internal Server Error
500 3040
Internal Server Error
500 3042
Internal Server Error
404 3043
Call not found / unsupported in this API
404 3044
Call not found / unsupported in this API
404 3045
Call not found / unsupported in this API
500 3046
Internal Server Error
500 3075
Internal Server Error
500 3080
Internal Server Error
500 4060
Internal Server Error
404 10716
Given virtual_number not found
404 10706
User device is currently busy

*These will be populated under the `error_data` block of response