Answering Machine/Voicemail Detection

    Answering machine or voicemail detection can be enabled by including the machine_detection parameter when making an outbound call using the Call API. Plivo will run the machine detection in the background and on a successful match, would make an HTTP request to the machine_detection_url. On positive detection, Plivo will send a Machine parameter with the value true to the machine_detection_url. You can now make a decision based on this parameter. Ideally you should then use the Transfer API to change the flow of the call. You can checkout Asynchronous Machine Detection for futher details on the parameters sent.

    Prerequisites

    1. Sign up for a free Plivo trial account.
    2. Check out our server SDKs page and install the right helper based on the programming language you want to use.
    3. Buy a Plivo phone number (optional).
    4. Use a web hosting service to host your web application. There are many inexpensive cloud hosting providers that you can use for just a few dollars a month. Follow the instructions of your hosting provider to host your web application.

    Implementation

    1. Copy the relevant code below into a text file and save it.
    2. Replace Your_AUTH_ID and Your_AUTH_TOKEN with the AUTH ID and AUTH TOKEN found on your Plivo dashboard.
    3. Add your from (source) phone number. This will show up as your Sender ID. Be sure that all phone numbers include country code, area code, and phone number without spaces or dashes (e.g., 14153336666).
    4. Add your to (destination) phone numbers. These are the phone numbers to which you will make a call. To place calls in bulk, separate your destination phone numbers with the "<" character (e.g., 14156667777<14157778888<14158889999). Be sure that all phone numbers include country code, area code, and phone number without spaces or dashes (e.g., 14153336666).
      Note: If you are using a trial account, your destination number needs to be verified with Plivo. Phone numbers can be verified at the Sandbox Numbers page.
    5. Edit the answer_url field with a URL to be requested by Plivo when the call is answered which tells Plivo what to do with the call.
    6. Edit the answer_method field with either GET or POST.
    7. Edit the machine_detection_url field with a URL to be requested by Plivo if an answering machine or voicemail is detected on the call.
    8. Edit the machine_detection_method field with either GET or POST.

    Code

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    
    from plivo import plivoxml
    from flask import request, Response
    
    import plivo
    
    client = plivo.RestClient ('YOUR_AUTH_ID', 'YOUR_AUTH_TOKEN')
    
    # Machine detection using Call API
    
    response = client.calls.create (
        from_='14152224444',  # The phone number to be used as the caller id
        to_=' 14152223333',  # The phone numer to which the all has to be placed
        answer_url='http://s3.amazonaws.com/static.plivo.com/answer.xml',  # The URL invoked by Plivo when the outbound call is answered
        answer_method='GET',  # The method used to call the answer_url
        machine_detection='true',  # Used to detect if the call has been answered by a machine. The valid values are true and hangup.
        machine_detection_time='10000',  # Time allotted to analyze if the call has been answered by a machine. The default value is 5000 ms.
        machine_detection_url='http://www.foo.com/machine_detection',  # A URL where machine detection parameters will be sent by Plivo.
        machine_detection_method='GET',  # The method used to call the machine_detection_url
    )
    print(response)
    
    # As soon as the voicemail finishes and there is a silence for minSilence
    # milliseconds, the next element in the XML is processed, without waiting for
    # the whole period of length seconds to pass
    
    @app.route('/detect/', methods=['GET','POST'])
    def detect():
        response = plivoxml.ResponseElement ().add(plivoxml.WaitElement(
            silence=True, # When silence is set to true, if no voice or sound is detected for minSilence milliseconds, end the wait and continue to the next element in the XML immediately
            min_silence='500'  # Time to wait in milliseconds
        ).set_length (10)  # Time to wait in seconds
        ).add (plivoxml.SpeakElement ('Hello Voicemail!'))
        return Response (response.to_string (), mimetype='application/xml')
    
    # Machine Detection URL example
    
    @app.route('/machine_detection/',methods=['POST', 'GET'])
    def machine_detection():
        from_number = request.args.get ('From')  # The From number which is used to make the call.
        machine = request.args.get ('Machine')  # This parameter will be true if a machine has been detected on the call.
        to_number = request.args.get ('To')  # The number which is being called.
        call_uuid = request.args.get ('CallUUID')  # The ID of the call.
        event = request.args.get (
            'Event')  # The event of the notification. This parameter will always have the value MachineDetection.
        call_status = request.args.get ('CallStatus')  # The status of the call. This will hold the value of in-progress.
    
        print ('From : %s To : %s  Machine : %s Call UUID : %s Event : %s Call Status : %s ' % (from_number, to_number, machine, call_uuid, event, call_status))
        return 'OK'
            
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    
    require 'rubygems'
    require 'sinatra'
    require 'plivo'
    include Plivo
    
    api = RestClient.new("YOUR_AUTH_ID", "YOUR_AUTH_TOKEN")
    
    # Machine detection using Call API
    
    begin
        response = api.calls.create(
          '+14151234567', # The phone number to use as the caller id
          ['+15671234567'], # The phone number to which the call will be placed
          'http://s3.amazonaws.com/static.plivo.com/answer.xml', # The URL requested by Plivo when the outbound call is answered
          'GET' # The method used to request the answer_url
          { 
              machine_detection: true, # Used to detect if the call has been answered by a machine. The valid values are true and hangup.
              machine_detection_time:'10000', # Time allotted to analyze if the call has been answered by a machine. The default value is 5000 ms.
              machine_detection_url:'https://www.foo.com/machine_detection', # A URL where machine detection parameters will be sent by Plivo.
              machine_detection_method:'GET' # Method used to invoke machine_detection_url
          },
        )
        puts response
      rescue PlivoRESTError => e
        puts 'Exception: ' + e.message
    end
    
    # As soon as the voicemail finishes speaking, and there is a silence for minSilence milliseconds,
    # the next element in the XML is processed, without waiting for the whole period of length seconds to pass
    
    get '/detect/' do
        begin
    		response = Response.new
    		params = {
    			length: '10', # Time to wait in seconds
    			silence:'true', # When silence is set to true, if no voice or sound is detected for minSilence milliseconds, end the wait and continue to the next element in the XML immediately 
    			minSilence:'3000' # Only used when silence is set to true. The minimum length in milliseconds of silence that needs to be present to qualify as silence
    		}
    		response.addWait(params)   
    		speak_body = 'Hello Voicemail'
    		response.addSpeak(speak_body)
    				xml = PlivoXML.new(response)
    		return xml.to_xml
    	rescue PlivoXMLError => e
    		puts 'Exception: ' + e.message
    	end
    end
    
    # Machine Detection URL example
    
    get '/machine_detection/' do
        from_number = params[:From]
    	to_number = params[:To]
    	machine = params[:Machine]
    	call_uuid = params[:CallUUID]
    	event = params[:Event]
    	status = params[:CallStatus]
    
    	puts "From : #{from_number}, To : #{to_number}, Machine : #{machine}, Call UUID : #{call_uuid}, Event : #{event}, Status : #{status}"
        return "OK"
    end
            
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    
    var plivo = require('plivo');
    var express = require('express');
    var app = express();
    
    app.set('port', (process.env.PORT || 5000));
    app.use(express.static(__dirname + '/public'));
    
    (function main() {
        'use strict';
        var client = new plivo.Client("YOUR_AUTH_ID","YOUR_AUTH_TOKEN");
        client.calls.create(
            "+14151234567", // The phone number to be used as the caller id
            "+15671234567", // The phone numer to which the all has to be placed
            "http://s3.amazonaws.com/static.plivo.com/answer.xml", // The URL invoked by Plivo when the outbound call is answered
            {
                answerMethod: "GET", // The method used to call the answer_url
                machineDetection: true, // Used to detect if the call has been answered by a machine. The valid values are true and hangup.
                machineDetectionTime: "10000", // ime allotted to analyze if the call has been answered by a machine. The default value is 5000 ms.
                machineDetectionUrl: "http://www.foo.com/machine_detection", // A URL where machine detection parameters will be sent by Plivo.
                machineDetectionMethod: "GET" // The method used to call the machineDetectionUrl
            },
        ).then(function (response) {
            console.log(response);
        }, function (err) {
            console.error(err);
        });
    })();
    
    // As soon as the voicemail finishes speaking, and there is a silence for minSilence milliseconds, 
    // the next element in the XML is processed, without waiting for the whole period of length seconds to pass
    
    app.post('/detect/', function(request, response) {
        var r = plivo.Response();
    
        var params = {
            'length' : "1000", // Time to wait in seconds
            'silence' : 'true', // When silence is set to true, if no voice or sound is detected for minSilence milliseconds, end the wait and continue to the next element in the XML immediately
            'minSilence' : '3000' // Only used when silence is set to true. The minimum length in milliseconds of silence that needs to be present to qualify as silence
        };
    
        r.addWait(params);
        r.addSpeak("Hello Voicemail!");
        console.log (r.toXML());
    
        response.set({'Content-Type': 'text/xml'});
        response.end(r.toXML());
    });
    
    app.post('/machine_detection/', function(request, response){
        
        var from_number = request.param('From'); // The From number which is used to make the call.
        var machine = request.param('Machine'); // This parameter will be true if a machine has been detected on the call.
        var to_number = request.param('To'); // The number which is being called.
        var call_uuid = request.param('CallUUID'); // The ID of the call.
        var events = request.param('Event');// The event of the notification. This parameter will always have the value MachineDetection.
        var call_status = request.param('CallStatus'); // The status of the call. This will hold the value of in-progress.
    
        console.log ('From :' + from_number + ' To : ' + to_number + ' Machine : ' + machine + ' Call UUID : ' + call_uuid + ' Event : ' + events + ' Call Status : ' + call_status);
    
        response.send("OK");
    });
    
    app.listen(app.get('port'), function() {
        console.log('Node app is running on port', app.get('port'));
    });
            
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    
    <!-- machine_detection_call.php -->
    
    <?php
    require 'vendor/autoload.php';
    use Plivo\RestClient;
    use Plivo\Exceptions\PlivoRestException;
    $client = new RestClient("YOUR_AUTH_ID", "YOUR_AUTH_TOKEN");
    try {
        $response = $client->calls->create(
            '+14151234567', # The phone number to use as the caller id
            ['+15671234567'], # The phone numer to which the call will be placed
            'http://s3.amazonaws.com/static.plivo.com/answer.xml', # The URL requested by Plivo when the outbound call is answered
            'GET', # The method used to request the answer_url
            [
                'machine_detection' => "true", # Used to detect if the call has been answered by a machine. The valid values are true and hangup.
                'machine_detection_time' => "10000", # Time allotted to analyze if the call has been answered by a machine. The default value is 5000 ms.
                'machine_detection_url' => "https://example.com/machine_detect.php", # A URL where machine detection parameters will be sent by Plivo.
                'machine_detection_method' => "GET" # Method used to request machine_detection_url
            ]
        );
        print_r($response);
    }
    catch (PlivoRestException $ex) {
        print_r($ex);
    }
    
    <!-- detect.php-->
    
    <?php
        require 'vendor/autoload.php';
        use Plivo\XML\Response;
    
        $r = new Response();
        // Add Wait tag
        $params = array(
            'length' => "1000", # Time to wait in seconds
            'silence' => "true", # When silence is set to true, if no sound is detected for minSilence milliseconds, end the wait and continue to the next element in the XML immediately
            'minSilence' => "3000" # Only used when silence is set to true. The minimum length in milliseconds of silence that needs to be present to qualify as silence
        );
        $r->addWait($params);
        $r->addSpeak("Hello Voicemail");
        Header('Content-type: text/xml');
        echo($r->toXML());
    ?>
    
    <!-- machine_detect.php-->
    
    <?php
        $from_number = $_REQUEST['From'];
        $to_number = $_REQUEST['To'];
        $machine = $_REQUEST['Machine'];
        $call_uuid = $_REQUEST['CallUUID'];
        $event = $_REQUEST['Event'];
        $call_status = $_REQUEST['CallStatus'];
        error_log("From: $from_number , To: $to_number , Machine: $machine , Call UUID: $call_uuid , Event: $event , Call Status: $call_status");
        echo "OK";
    ?>
            
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    
    // machineDetectionCall.java
    import com.plivo.api.Plivo;
    import com.plivo.api.exceptions.PlivoRestException;
    import com.plivo.api.models.call.Call;
    import com.plivo.api.models.call.CallCreateResponse;
    import java.io.IOException;
    import java.util.Collections;
    import static spark.Spark.*;
    
    public class MachineDetection {
        public static void main(String[] args) {
            get("/machine_detection_call", (request, response) -> {
                Plivo.init("YOUR_AUTH_ID", "YOUR_AUTH_TOKEN");
                try {
                    CallCreateResponse resp = Call.creator(
                        "+14151234567", // The phone number to be used as the caller id
                        Collections.singletonList("+15671234567"), // The phone number to which the call has to be placed
                        "http://www.foo.com/detect/" // The URL requested by Plivo when the outbound call is answered
                        )
                            .answerMethod("GET") // Method to request the answer_url
                            .machineDetectionUrl("http://www.foo.com/machine_detection/") // A URL where machine detection parameters will be sent by Plivo.
                            .machineDetectionTime(10000L) // Time allotted to analyze if the call has been answered by a machine. The default value is 5000 ms.
                            .machineDetectionMethod("GET") // Method to request the machineDetectionUrl
                            .machineDetection("true") // Used to detect if the call has been answered by a machine. The valid values are true and hangup.
                            .create();
    
                    System.out.println(resp);
                } catch (PlivoRestException | IOException e) {
                    e.printStackTrace();
                }
                return "Call attempted";
            });
        }
    }
    
    // As soon as the voicemail finishes speaking, and there is a silence for minSilence milliseconds, 
    // the next element in the XML is processed, without waiting for the whole period of length seconds to pass
    import com.plivo.api.xml.*;
    import static spark.Spark.*;
    
    public class Detect {
        public static void main(String[] args) {
            get("/detect", (request, response) -> {
                Response resp = new Response()
                        .children(
                                new Wait()
                                        .minSilence(3000) // Only used when silence is set to true. The minimum length in milliseconds of silence that needs to be present to qualify as silence
                                        .silence(true) // When silence is set to true, if no voice or sound is detected for minSilence milliseconds, end the wait and continue to the next element in the XML immediately
                                        .length(10), // Time to wait in seconds
                                new Speak("Hello Voicemail!")
                        );
                return resp.toXmlString();
            });
        }
    }
    
    
    // machineDetection.java
    import static spark.Spark.*;
    
    public class Event {
        public static void main(String[] args) {
            get("/event", (request, response) -> {
                String from_number = request.queryParams("From");
                String to_number = request.queryParams("To");
                String machine = request.queryParams("Machine");
                String call_uuid = request.queryParams("CallUUID");
                String event = request.queryParams("Event");
                String status = request.queryParams("CallStatus");
                return "From : " + from_number + " Machine : " + machine + " To : " + to_number + " Call UUID : " + call_uuid + " Event : " + event + " Call Status : " + status;
            });
        }
    }
            
    
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    
    using System;
    using System.Collections.Generic;
    using Microsoft.AspNetCore.Mvc;
    
    namespace MakeCall.Controllers {
      public class MakeCallController: Controller {
        // GET: /<controller>/
        public IActionResult Index() {
          var api = new PlivoApi("YOUR_AUTH_ID", "YOUR_AUTH_TOKEN");
          try {
            var response = api.Call.Create(
              from: "+14151234567", // The phone number to be used as the caller id
              to: new List < String > {"+15671234567"}, // The phone number to which the call has to be placed
              answerMethod: "GET", // Method to invoke the answer_url
              answerUrl: "http://s3.amazonaws.com/static.plivo.com/answer.xml", // The URL invoked by Plivo when the outbound call is answered
              machineDetection: "true", // Used to detect if the call has been answered by a machine. The valid values are true and hangup.
              machineDetectionTime: 1000, // Time allotted to analyze if the call has been answered by a machine. The default value is 5000 ms.
              machineDetectionUrl: "http://dotnettest.apphb.com/machine_detection", // A URL where machine detection parameters will be sent by Plivo.
              machineDetectionMethod: "GET" // Method used to invoke machine_detection_url
            );
            Console.WriteLine(response);
          } catch (PlivoRestException e) {
            Console.WriteLine("Exception: " + e.Message);
          }
          return this.Content(output, "text/xml");
        }
      }
    }
    
    // Example for answer_url and machine_detection_url
    
    using System;
    using System.Collections.Generic;
    using Microsoft.AspNetCore.Mvc;
    
    namespace Machinedetect.Controllers
    {
        public class MachinedetectController : Controller
        {
            // GET: /<controller>/
            public IActionResult Index(String From, String Machine, String To, String CallUUID, String Event, String CallStatus)
            {
    			Debug.WriteLine("From : {0}, Machine : {1}, To : {2}, Call UUID : {3}, Event : {4}, Call Status : {5}", From, Machine, To, CallUUID, Event, CallStatus);
                
                return "OK"
    		}
        }
    }
    
    // As soon as the voicemail finishes speaking, and there is a silence for minSilence milliseconds, 
    // the next element in the XML is processed, without waiting for the whole period of length seconds to pass
    
    using System;
    using System.Collections.Generic;
    using Microsoft.AspNetCore.Mvc;
    using Plivo;
    
    namespace Voicemail.Controllers
    {
        public class VoicemailController : Controller
        {
            // GET: /<controller>/
            public IActionResult Index(String From, String Machine, String To, String CallUUID, String Event, String CallStatus)
            {
    			Plivo.XML.Response resp = new Plivo.XML.Response();
            	resp.AddWait(new Dictionary < string, string > () {
              	{"length","1000"}, 
              	{"silence","true"}, 
              	{"minSilence","3000"}
            });
            resp.AddSpeak("Hello Voicemail!", new Dictionary < string, string > () {});
            var output = resp.ToString();
    		Console.WriteLine(output);
            return this.Content(output, "text/xml");
    		}
        }
    }
            
    

    Sample Response

    Make Outbound call
    {
        "message":"call fired",
        "request_uuid":"9834029e-58b6-11e1-b8b7-a5bd0e4e126f",
        "api_id":"97ceeb52-58b6-11e1-86da-77300b68f8bb"
    }
    
    XML returned by the answer_url
    <Response>
        <Wait length="10" silence="true" minSilence="3000"/>
        <Speak>Hello Voicemail!</Speak>
    </Response>
    
    Machine Detection URL output
    From : 2222222222
    To : 1111111111
    Machine : true
    Call UUID : 45704ba2-959f-11e4-802f-e9b058eeb9e5
    Event : MachineDetection
    Call Status : in-progress