# Answering Machine Detection

## Answering Machine Detection

Answering Machine Detection (AMD) enables you to determine the receiving side of an outgoing call and tailor your call flow accordingly. With AMD you can determine if a human, answering machine or fax machine has picked up an outbound voice API call. Once AMD has executed and made its decision, the caller is connected to the callee.

AMD can also be executed asynchronously: the callee is connected immediately and AMD is executed in the background.

Twilio's AMD operates in two modes, depending on whether you need to leave a voicemail as part of your call flow. The default AMD mode tries to balance recognition speed and accuracy. You may also tune the performance of the engine based on your use case via optional API parameters.

Please see the following API parameters for configuring AMD on your outbound calls.

## Making a call with AMD

AMD can be enabled on calls generated via [`POST` to the Calls API](/docs/voice/api/call-resource#create-a-call-resource), [`POST` to the Participants API](/docs/voice/api/conference-participant-resource#create-a-participant), [`<Dial><Number>`](/docs/voice/twiml/number), or [`<Dial><Sip>`](/docs/voice/twiml/sip).

The following AMD parameters as well as [Optional tuning parameters](#optional-api-tuning-parameters) can be specified on the requests.

### API parameters

| Parameter Name                                                | Allowed Values                 | Default Value |
| :------------------------------------------------------------ | :----------------------------- | :------------ |
| [MachineDetection](#machinedetection)                         | `Enable` or `DetectMessageEnd` | none          |
| [AsyncAmd](#asyncamd)                                         | `true` or `false`              | `false`       |
| [AsyncAmdStatusCallbackMethod](#asyncamdstatuscallbackmethod) | `POST`                         | `POST`        |
| [AsyncAmdStatusCallback](#asyncamdstatuscallback)             | Absolute or relative URL       | none          |

#### MachineDetection \[#machinedetection]

Use `Enable` if you would like Twilio to return an [AnsweredBy](#webhook-parameters) value as soon as it identifies the called party. This is useful if you would like to take a specific action — for example, connect to an agent, or leave a message in voicemail with `<Say>` and [Text-To-Speech capabilities](voice/twiml/say/text-speech) — for a human but hang up on a machine.

If you would like to leave a voicemail on an answering machine, specify `DetectMessageEnd`. In this case, Twilio will return an [AnsweredBy](#webhook-parameters) immediately when a human is detected but for an answering machine, [AnsweredBy](#webhook-parameters) is returned only once the end of the greeting is reached, usually indicated by a beep.

#### AsyncAmd \[#asyncamd]

Select whether to detect an answering machine in the background.

* When you set `AsyncAmd` to `true`, the call continues. The AMD service determines if an answering machine exists in the background.
* When you set `AsyncAmd` to `false` (the default), Twilio blocks the call. The call resumes when the AMD service completes answering machine detection.

#### AsyncAmdStatusCallbackMethod \[#asyncamdstatuscallbackmethod]

The HTTP method that we should use to send the results of the AMD.

#### AsyncAmdStatusCallback \[#asyncamdstatuscallback]

The absolute or relative URL that we should call using the AsyncAmdStatusCallbackMethod to notify whether the call was answered by a human, machine, or fax. When AMD makes a decision, Twilio will make a request to this URL with the following parameters:

| **Parameter**            | **Description**                                                                                                                                                                                                                                                                  |
| ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| CallSid                  | A unique identifier for this call, generated by Twilio                                                                                                                                                                                                                           |
| AccountSid               | Your Twilio account ID. It is 34 characters long, and always starts with the letters `AC`                                                                                                                                                                                        |
| AnsweredBy               | The result of answering machine detection. If `Enable` was specified, results can be: `machine_start`, `human`, `fax`, `unknown`. If `DetectMessageEnd` was specified, results can be: `machine_end_beep`, `machine_end_silence`, `machine_end_other`, `human`, `fax`, `unknown` |
| MachineDetectionDuration | Time in milliseconds that AMD took to reach a verdict                                                                                                                                                                                                                            |

### Optional API tuning parameters

AMD uses an algorithm that isolates human speech audio and measures periods between speech and silence in the greeting, and then uses this data to determine the answering party. Since not all humans and not all voicemail greetings follow similar patterns in answering calls, it's possible that AMD will not always return the right answer. The AMD engine may, for example, interpret a very short two-second voicemail greeting as a human picking up.

There are four optional parameters that allow customers to tune the performance of the AMD engine, the diagram below illustrates how each property relates to media utterances:

![Answering Machine Detection optional properties diagram.](https://docs-resources.prod.twilio.com/9ad46996c4dd82b49b35e5ffd865e0b373d89841737195dd4322818bac98e2c5.png)

| Parameter Name                                                                           | Allowed Values             | Default Value |
| :--------------------------------------------------------------------------------------- | :------------------------- | :------------ |
| [MachineDetectionTimeout](#parameters-machine-detection-timeout)                         | Between `3` and `59`       | `30`          |
| [MachineDetectionSpeechThreshold](#parameters-machine-detection-speech-threshold)        | Between `1000` and `6000`  | `2400`        |
| [MachineDetectionSpeechEndThreshold](#parameters-machine-detection-speech-end-threshold) | Between `500` and `5000`   | `1200`        |
| [MachineDetectionSilenceTimeout](#parameter-machine-detection-silence-timeout)           | Between `2000` and `10000` | `5000`        |

#### MachineDetectionTimeout \[#parameters-machine-detection-timeout]

The number of seconds that Twilio should attempt to perform answering machine detection before timing out. If `MachineDetectionTimeout` is reached, [AnsweredBy](#webhook-parameters) will return `unknown`.

**Increasing** this value will provide the engine more time to make a determination. For example, you may increase the default value when `MachineDetection=DetectMessageEnd` and there is an expectation of long answering machine greetings that can exceed 30 seconds.

**Decreasing** this value will reduce the amount of time the engine has to make a determination. For example, you may decrease the default value when `MachineDetection=Enabled` if you have time constraints for taking an action based on answering machine detection determination, hence you prioritize a (best effort) *quick* response of human/machine or Unknown result. However, not giving enough time will result in more `unknown` results.

Note that when `MachineDetection=DetectMessageEnd`, setting low values for `MachineDetectionTimeout` may return `unknown` result even if a machine answered the call and the engine would be able to determine so, because the timeout was triggered without waiting until the end of machine greeting, which instead would have returned `machine_end_beep`, `machine_end_silence`, or `machine_end_other`.

#### MachineDetectionSpeechThreshold \[#parameters-machine-detection-speech-threshold]

The number of milliseconds that is used as the measuring stick for the length of the speech activity. Durations lower than this value may be interpreted as a human, longer as a machine.

**Increasing** this value will reduce the chance of a *False Machine* (detected machine, actually human) for a long human greeting (e.g., a business greeting) but increase the time it takes to detect a machine.

**Decreasing** this value may reduce the chances of a *False Human* (detected human, actually machine) for short voicemail greetings. For example, the value of this parameter may need to be reduced by more than 1000 ms to detect very short voicemail greetings. However, a reduction of that significance can result in increased *False Machine* detections and adjusting the `MachineDetectionSpeechEndThreshold` is likely the better approach for short voicemails.

#### MachineDetectionSpeechEndThreshold \[#parameters-machine-detection-speech-end-threshold]

The number of milliseconds of silence after speech activity at which point the speech activity is considered complete.

**Increasing** this value is typically used to better address the short voicemail greeting scenarios. For short voicemails, there is typically 1000-2000 ms of audio followed by 1200-2400 ms of silence and then additional audio before the beep. Increasing the `MachineDetectionSpeechEndThreshold` to \~2500 ms will treat the 1200-2400 ms of silence as a gap in the greeting but not the end of the greeting and will result in a machine detection. The downsides of such a change include:

1. Increasing the delay for human detection by the amount you increase this parameter, e.g., a change of 1200 ms to 2500 ms increases human detection delay by 1300ms.
2. Cases where a human has two utterances separated by a period of silence (e.g. a "Hello", then 2000 ms of silence, and another "Hello") may be interpreted as a machine.

**Decreasing** this value will result in faster human detection. The consequence is that it can lead to increased *False Human* (detected human, actually machine) detections because a silence gap in a voicemail greeting (not necessarily just in short voicemail scenarios) can be incorrectly interpreted as the end of speech.

#### MachineDetectionSilenceTimeout \[#parameter-machine-detection-silence-timeout]

The number of milliseconds of initial silence after which an `unknown` [AnsweredBy](#webhook-parameters) result will be returned.

**Increasing** this value will result in waiting for a longer period of initial silence before returning an `unknown` AMD result.

**Decreasing** this value will result in waiting for a shorter period of initial silence before returning an `unknown` AMD result.

Make a call with AMD

```js
// Download the helper library from https://www.twilio.com/docs/node/install
const twilio = require("twilio"); // Or, for ESM: import twilio from "twilio";

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
const accountSid = process.env.TWILIO_ACCOUNT_SID;
const authToken = process.env.TWILIO_AUTH_TOKEN;
const client = twilio(accountSid, authToken);

async function createCall() {
  const call = await client.calls.create({
    from: "+18180000000",
    machineDetection: "Enable",
    to: "+1562300000",
    url: "https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16",
  });

  console.log(call.sid);
}

createCall();
```

```python
# Download the helper library from https://www.twilio.com/docs/python/install
import os
from twilio.rest import Client

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = os.environ["TWILIO_ACCOUNT_SID"]
auth_token = os.environ["TWILIO_AUTH_TOKEN"]
client = Client(account_sid, auth_token)

call = client.calls.create(
    machine_detection="Enable",
    url="https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16",
    to="+1562300000",
    from_="+18180000000",
)

print(call.sid)
```

```csharp
// Install the C# / .NET helper library from twilio.com/docs/csharp/install

using System;
using Twilio;
using Twilio.Rest.Api.V2010.Account;
using System.Threading.Tasks;

class Program {
    public static async Task Main(string[] args) {
        // Find your Account SID and Auth Token at twilio.com/console
        // and set the environment variables. See http://twil.io/secure
        string accountSid = Environment.GetEnvironmentVariable("TWILIO_ACCOUNT_SID");
        string authToken = Environment.GetEnvironmentVariable("TWILIO_AUTH_TOKEN");

        TwilioClient.Init(accountSid, authToken);

        var call = await CallResource.CreateAsync(
            machineDetection: "Enable",
            url: new Uri("https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16"),
            to: new Twilio.Types.PhoneNumber("+1562300000"),
            from: new Twilio.Types.PhoneNumber("+18180000000"));

        Console.WriteLine(call.Sid);
    }
}
```

```java
// Install the Java helper library from twilio.com/docs/java/install

import java.net.URI;
import com.twilio.Twilio;
import com.twilio.rest.api.v2010.account.Call;

public class Example {
    // Find your Account SID and Auth Token at twilio.com/console
    // and set the environment variables. See http://twil.io/secure
    public static final String ACCOUNT_SID = System.getenv("TWILIO_ACCOUNT_SID");
    public static final String AUTH_TOKEN = System.getenv("TWILIO_AUTH_TOKEN");

    public static void main(String[] args) {
        Twilio.init(ACCOUNT_SID, AUTH_TOKEN);
        Call call = Call.creator(new com.twilio.type.PhoneNumber("+1562300000"),
                            new com.twilio.type.PhoneNumber("+18180000000"),
                            URI.create("https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16"))
                        .setMachineDetection("Enable")
                        .create();

        System.out.println(call.getSid());
    }
}
```

```go
// Download the helper library from https://www.twilio.com/docs/go/install
package main

import (
	"fmt"
	"github.com/twilio/twilio-go"
	api "github.com/twilio/twilio-go/rest/api/v2010"
	"os"
)

func main() {
	// Find your Account SID and Auth Token at twilio.com/console
	// and set the environment variables. See http://twil.io/secure
	// Make sure TWILIO_ACCOUNT_SID and TWILIO_AUTH_TOKEN exists in your environment
	client := twilio.NewRestClient()

	params := &api.CreateCallParams{}
	params.SetMachineDetection("Enable")
	params.SetUrl("https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16")
	params.SetTo("+1562300000")
	params.SetFrom("+18180000000")

	resp, err := client.Api.CreateCall(params)
	if err != nil {
		fmt.Println(err.Error())
		os.Exit(1)
	} else {
		if resp.Sid != nil {
			fmt.Println(*resp.Sid)
		} else {
			fmt.Println(resp.Sid)
		}
	}
}
```

```php
<?php

// Update the path below to your autoload.php,
// see https://getcomposer.org/doc/01-basic-usage.md
require_once "/path/to/vendor/autoload.php";

use Twilio\Rest\Client;

// Find your Account SID and Auth Token at twilio.com/console
// and set the environment variables. See http://twil.io/secure
$sid = getenv("TWILIO_ACCOUNT_SID");
$token = getenv("TWILIO_AUTH_TOKEN");
$twilio = new Client($sid, $token);

$call = $twilio->calls->create(
    "+1562300000", // To
    "+18180000000", // From
    [
        "machineDetection" => "Enable",
        "url" =>
            "https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16",
    ]
);

print $call->sid;
```

```ruby
# Download the helper library from https://www.twilio.com/docs/ruby/install
require 'rubygems'
require 'twilio-ruby'

# Find your Account SID and Auth Token at twilio.com/console
# and set the environment variables. See http://twil.io/secure
account_sid = ENV['TWILIO_ACCOUNT_SID']
auth_token = ENV['TWILIO_AUTH_TOKEN']
@client = Twilio::REST::Client.new(account_sid, auth_token)

call = @client
       .api
       .v2010
       .calls
       .create(
         machine_detection: 'Enable',
         url: 'https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16',
         to: '+1562300000',
         from: '+18180000000'
       )

puts call.sid
```

```bash
# Install the twilio-cli from https://twil.io/cli

twilio api:core:calls:create \
   --machine-detection Enable \
   --url https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16 \
   --to +1562300000 \
   --from +18180000000
```

```bash
curl -X POST "https://api.twilio.com/2010-04-01/Accounts/$TWILIO_ACCOUNT_SID/Calls.json" \
--data-urlencode "MachineDetection=Enable" \
--data-urlencode "Url=https://handler.twilio.com/twiml/EH8ccdbd7f0b8fe34357da8ce87ebe5a16" \
--data-urlencode "To=+1562300000" \
--data-urlencode "From=+18180000000" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "account_sid": "ACXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "answered_by": null,
  "api_version": "2010-04-01",
  "caller_name": null,
  "date_created": "Tue, 31 Aug 2010 20:36:28 +0000",
  "date_updated": "Tue, 31 Aug 2010 20:36:44 +0000",
  "direction": "inbound",
  "duration": "15",
  "end_time": "Tue, 31 Aug 2010 20:36:44 +0000",
  "forwarded_from": "+141586753093",
  "from": "+18180000000",
  "from_formatted": "(415) 867-5308",
  "group_sid": null,
  "parent_call_sid": null,
  "phone_number_sid": "PNaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "price": "-0.03000",
  "price_unit": "USD",
  "sid": "CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "start_time": "Tue, 31 Aug 2010 20:36:29 +0000",
  "status": "completed",
  "subresource_uris": {
    "notifications": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Notifications.json",
    "recordings": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Recordings.json",
    "payments": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Payments.json",
    "events": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Events.json",
    "siprec": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Siprec.json",
    "streams": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Streams.json",
    "transcriptions": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Transcriptions.json",
    "user_defined_message_subscriptions": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/UserDefinedMessageSubscriptions.json",
    "user_defined_messages": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/UserDefinedMessages.json"
  },
  "to": "+1562300000",
  "to_formatted": "(415) 867-5309",
  "trunk_sid": null,
  "uri": "/2010-04-01/Accounts/ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Calls/CAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.json",
  "queue_time": "1000"
}
```

### Webhook parameters

AMD results are returned in the `AnsweredBy` parameter of the webhook issued to the URL you provide in the outbound call request.

| Parameter  | Description                                                                                                                                                                                                                                                                    |
| :--------- | :----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| AnsweredBy | The result of answering machine detection.If `Enable` was specified, results can be:`machine_start`, `human`, `fax`, `unknown`.If `DetectMessageEnd` was specified, results can be: `machine_end_beep`, `machine_end_silence`, `machine_end_other`, `human`, `fax`, `unknown`. |

> \[!WARNING]
>
> When you don't use `AsyncAmd`, your API call can use one of two parameters to send instructions. You can include instructions in either the `url` or `twiml` parameters. Using either parameter, Twilio awaits a decision from the AMD service. The next action depends on the parameter your API call uses to pass instructions.
>
> If your API call uses in the `url` parameter, Twilio sends a webhook to the URL with the decision.
>
> If your API call uses in the `twiml` parameter, Twilio executes the instructions.

## Pricing

Answering Machine Detection will be charged at **$.0075** per call where enabled and the called party picks up. Busy or Failed calls may engage our AMD system but will not be charged.

## AMD Optimization

See also: [Answering Machine Detection FAQ and best practices](/docs/voice/answering-machine-detection-faq-best-practices)

The life cycle of a call using AMD is shown below. The user experience of a recipient of a call using AMD is impacted if there is a delay from the time they pick up the phone to the first packet of audio they hear. Twilio has optimized our AMD system to quickly classify calls, but it's also important that you optimize your application to respond quickly.

![Twilio AMD Call Progress.](https://docs-resources.prod.twilio.com/291fdb9597647ef9e3841e62693b7f7884c88a75b2d4017f15d2bed2165308e2.png)

### Optimize TwiML responses

To minimize delay, ensure that you benchmark your application to ensure that webhooks from Twilio are processed and responded to in a timely manner. In test applications running in EC2, we can get this time under 150 ms. TwiML served from TwiMLBins typically comes in under 100 ms.

### Cache static TwiML and media for play verbs

If you are using `<Play>` verbs, we recommend hosting your media in AWS S3 in us-east-1, eu-west-1, or ap-southeast-2 depending on which [Twilio Region](/docs/global-infrastructure/understanding-twilio-regions) you are using. No matter where you host your media files, always ensure that you're setting appropriate Cache Control headers. Twilio uses a caching proxy in its webhook pipeline and will cache media files that have cache headers. Serving media out of Twilio's cache can take 10ms or less. Keep in mind that we run a fleet of caching proxies so it may take multiple requests before all of the proxies have a copy of your file in cache.

Alternatively, you can use `<Say>` to leave a message with [Text-To-Speech capabilities](voice/twiml/say/text-speech) which provides more flexibility with low latency, without the overhead of recording, storing, and maintaining the media files.

### Benchmark response time with the Request Inspector

To help you benchmark your server's response time to Twilio, we expose the request duration in milliseconds for every request in the Request Inspector. You can view these clicking into the **Call Details** page in the Console:

![Fetch Time with the Request Inspector.](https://docs-resources.prod.twilio.com/dd6661223191db6517e3681b58d6c0a23cb8a63fae53fba0d0d4d383b02714f9.png)
