# Authy One-Time Passwords (OTP)

> \[!WARNING]
>
> As of November 2022, Twilio no longer provides support for Authy SMS/Voice-only customers. Customers who were also using Authy TOTP or Push prior to March 1, 2023 are still supported. The Authy API is now closed to new customers and will be fully deprecated in the future.
>
> For new development, we encourage you to use the [Verify v2 API](/docs/verify/api).
>
> Existing customers will not be impacted at this time until Authy API has reached End of Life. For more information about migration, see [Migrating from Authy to Verify for SMS](https://www.twilio.com/blog/migrate-authy-to-verify).

Before sending a One-Time Password:

1. **Create an Authy Application** ([see Applications documentation](/docs/authy/api/applications))
2. **Create a User** ([see Users documentation](/docs/authy/api/users))

Once a user has been registered with your Twilio Authy application and receives an AuthyID, you can now implement 2FA, passwordless login or protect an in-application high-value transaction. Using the Authy API, you can send one-time passwords over `voice` or `SMS` channels.

Users can also install the free [Authy app](https://authy.com) or use our SDK to generate offline [TOTP](https://en.wikipedia.org/wiki/Time-based_One-time_Password_algorithm) codes (`soft tokens`). Soft tokens do not require wireless connectivity to issue and verify.

The Authy API is used to verify a user has access to the right phone number (for SMS and Voice channels) or has access to the right trusted device (for TOTP via the Authy App or use of the SDK).

Twilio's Authy API follows the algorithms described in [RFC 6238](https://datatracker.ietf.org/doc/html/rfc6238) and [RFC 4226](https://datatracker.ietf.org/doc/html/rfc4226) to generate TOTP (Time-Based One-Time Passwords) passwords. It is also possible to use your own hardware tokens, please [contact us](https://www.twilio.com/en-us/v2-help/sales) for information on how to enable this type of 2FA.

## Request a One-Time Password

When you call the API to start either an SMS or voice-based authentication, it automatically checks to see if that user has previously downloaded the Authy app or has an app installed that uses our SDK. **If the user has the Authy App, by default, the API will not send the 2FA code via SMS or voice. Instead, a push notification will go to the device** , prompting the user to start their app to get the code.

If a user has no record of installing a device, then the API will continue to send the code via SMS or voice. You can override the default behavior to force the sending of code via SMS or voice every time. This is a useful override if a user is specifically selecting "Send SMS" or "Get code via voice call" in your application UI.

For information on timing and other constraints like rate limiting, see our [two-factor authentication best practices](/docs/verify/developer-best-practices).

```bash
GET https://api.authy.com/protected/{FORMAT}/sms/{AUTHY_ID}
```

### URL

| Name               | Description                                                                                                                                                                                                               |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `FORMAT` String    | The format to expect back from the REST API call. `json` or `xml`.                                                                                                                                                        |
| `AUTHY_ID` Integer | The Authy ID of the user to send an SMS TOTP. Create an Authy ID by [registering a user](/docs/authy/api/users). Note that password delivery may be upgraded to use the Authy application; see response parameters below. |

### Parameters \[#request-one-time-password-parameters]

| Name                               | Description                                                                                                                                                                                                                                                                                                                     |
| :--------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `force` Boolean (optional)         | Default is `false`. Set to `true` to send one-time passwords over the SMS channel even if the user has an Authy or SDK enabled app installed. Configure default behavior in the console. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                  |
| `action` String (optional)         | The optional action or context we are trying to validate. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                                 |
| `action_message` String (optional) | Optional message for the specific action. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                                                 |
| `locale` String (optional)         | The language of the message received by user. If no locale is given, Twilio will try to autodetect it based on the country code. English is used if no locale is autodetected. [More details below](#supported-languages) ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) ) |

### Response \[#request-one-time-password-response]

| Name               | Description                                                                                                                                                                                                                                                                                                    |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `success` Boolean  | Returns `true` if the request was successful. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                            |
| `message` String   | A message indicating what happened with the request. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                     |
| `cellphone` String | The country code and last two digits of phone number used to send the message with the rest obfuscated. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                  |
| `ignored` Boolean  | `True` if we detected an Authy or SDK enabled app installed and we upgraded the OTP delivery channel from 'SMS' to Push Notification. Authy or SDK users are redirected directly to the requested token. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) ) |
| `device` String    | The type of the last device used by the user. This is only returned when we upgraded delivery from SMS. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                  |

### Supported Languages

Supported languages are: Afrikaans (`af`), Arabic (`ar`), Catalan (`ca`), Chinese (`zh`), Chinese (Mandarin) (`zh-CN`), Chinese (Cantonese) (`zh-HK`), Croatian (`hr`), Czech (`cs`), Danish (`da`), Dutch (`nl`), English (`en`), Finnish (`fi`), French (`fr`), German (`de`), Greek (`el`), Hebrew (`he`), Hindi (`hi`), Hungarian (`hu`), Indonesian (`id`), Italian (`it`), Japanese (`ja`), Korean (`ko`), Malay (`ms`), Norwegian (`nb`), Polish (`pl`), Portuguese - Brazil (`pt-BR`), Portuguese (`pt`), Romanian (`ro`), Russian (`ru`), Spanish (`es`), Swedish (`sv`), Tagalog (`tl`), Thai (`th`), Turkish (`tr`), Vietnamese (`vi`). We support the format country-region as described in [IETF's BPC 47](https://www.rfc-editor.org/rfc/bcp/bcp47.txt). If no region is given (or supported), there will be a [default by country](/docs/verify/default-phone-verification-languages).

## Send a One-time Password Via SMS

Send a One-time Password Via SMS

```py
# Download the SDK from https://github.com/twilio/authy-python
from authy.api import AuthyApiClient

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
authy_api = AuthyApiClient('api_key')

sms = authy_api.users.request_sms(authy_id)

if sms.ok():
    print sms.content
```

```cs
using System;
using System.Net.Http;
using System.Collections.Generic;


class Program
{

    static void Main(string[] args)
    {
        // Your API key from twilio.com/console/authy/applications
        // DANGER! This is insecure. See https://twil.io/secure
        var AuthyAPIKey = "your_api_key";

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("X-Authy-API-Key", AuthyAPIKey);

            var authy_id = 1234;

            HttpResponseMessage response = client.GetAsync(
                $"https://api.authy.com/protected/json/sms/{authy_id}").Result;

            HttpContent responseContent = response.Content;
            Console.WriteLine(responseContent.ReadAsStringAsync().Result);
        }
    }
```

```java
// Install the Authy Java SDK from github.com/twilio/authy-java

import com.authy.AuthyApiClient;
import com.authy.api.*;

public class Example {
    // Your API key from twilio.com/console/authy/applications
    // DANGER! This is insecure. See https://twil.io/secure
    public static final String API_KEY = "your_api_key";

    public static void main(String[] args) {
        AuthyApiClient client = new AuthyApiClient(API_KEY);

        Users users = client.getUsers();
        Hash response = users.requestSms(authyId);

        if (response.isOk()) {
            System.out.println(response.getMessage());
        } else {
            System.out.println(response.getError());
        }
    }
}
```

```php
<?php

// Download the SDK from https://github.com/twilio/authy-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';

// Your API key from twilio.com/console/authy/applications
// DANGER! This is insecure. See https://twil.io/secure
$authy_api = new Authy\AuthyApi('api_key');

$sms = $authy_api->requestSms($authy_id);

if ($sms->ok()) {
    printf($sms->message());
} else {
    print_r($sms->errors());
}
```

```rb
# Download the SDK from https://github.com/twilio/authy-ruby
require 'authy'

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
Authy.api_key = 'your_api_key'
Authy.api_uri = 'https://api.authy.com'

response = Authy::API.request_sms(:id => authy_id)

puts response.message
```

```bash
# create a user first to get their Authy ID
# https://www.twilio.com/docs/authy/api/users

curl -i "https://api.authy.com/protected/json/sms/{AUTHY_ID}" \
    -H "X-Authy-API-Key: d57d919d11e6b221c9bf6f7c882028f9"
```

```json
{
    "success":true,
    "message":"SMS token was sent",
    "cellphone":"+1-XXX-XXX-XX02"
}
```

### Default Behavior for Users with the Authy App Installed

If the user has the Authy App, by default, the API will not send the 2FA code via SMS or voice. Instead, a push notification will go to the device, prompting the user to start their app to get the code. The user's notification will look like this:

![Authy notification: Tap to get your Demo Authy App security code.](https://docs-resources.prod.twilio.com/6a98ac99d887a7f2fb86e78d60ab45f2c2acfff30a32adfb16296788d5b80cd7.png)

If the user has the Authy app installed the API response will look like this:

```json
{
  "message": "Ignored: SMS is not needed for smartphones. Pass force=true if you want to actually send it anyway.",
  "cellphone": "+1-XXX-XXX-XX02",
  "device": "android",
  "ignored": true,
  "success": true
}
```

### Override Default Behavior and Force Sending SMS

You can override this behavior and **force** sending an SMS or Voice call. This is a useful override if a user is specifically selecting "Send SMS" or "Get code via voice call" in your application UI.

Send a One-time Password Via SMS (Forced)

```py
# Download the SDK from https://github.com/twilio/authy-python
from authy.api import AuthyApiClient

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
authy_api = AuthyApiClient('api_key')

sms = authy_api.users.request_sms(authy_id, {'force': True})

if sms.ok():
    print sms.content
```

```cs
using System;
using System.Net.Http;
using System.Web;
using System.Collections.Generic;


class Program
{
    // send SMS - forced
    static void Main(string[] args)
    {
        // Your API key from twilio.com/console/authy/applications
        // DANGER! This is insecure. See https://twil.io/secure
        var AuthyAPIKey = "your_api_key";

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("X-Authy-API-Key", AuthyAPIKey);

            var query = HttpUtility.ParseQueryString(string.Empty);
            query["force"] = "true";

            var authy_id = 1234;

            HttpResponseMessage response = client.GetAsync(
                $"https://api.authy.com/protected/json/sms/{authy_id}?{query.ToString()}").Result;

            HttpContent responseContent = response.Content;
            Console.WriteLine(responseContent.ReadAsStringAsync().Result);
        }
    }
}
```

```java
// Install the Authy Java SDK from github.com/twilio/authy-java

import com.authy.AuthyApiClient;
import com.authy.api.*;

public class Example {
    // Your API key from twilio.com/console/authy/applications
    // DANGER! This is insecure. See https://twil.io/secure
    public static final String API_KEY = "your_api_key";

    public static void main(String[] args) {
        AuthyApiClient client = new AuthyApiClient(API_KEY);

        Users users = client.getUsers();
        
        Map<String, String> options = new HashMap<String, String>();
        options.put("force", "true");

        Hash response = users.requestSms(authyId, options);

        if (response.isOk()) {
            System.out.println(response.getMessage());
        } else {
            System.out.println(response.getError());
        }
    }
}
```

```php
<?php

// Download the SDK from https://github.com/twilio/authy-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';

// Your API key from twilio.com/console/authy/applications
// DANGER! This is insecure. See https://twil.io/secure
$authy_api = new Authy\AuthyApi('api_key');

$sms = $authy_api->requestSms($authy_id, array("force" => "true"));

if ($sms->ok()) {
    printf($sms->message());
} else {
    print_r($sms->errors());
}
```

```rb
# Download the SDK from https://github.com/twilio/authy-ruby
require 'authy'

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
Authy.api_key = 'your_api_key'
Authy.api_uri = 'https://api.authy.com'

response = Authy::API.request_sms(:id => authy_id, :force => true)

puts response.message
```

```bash
# create a user first to get their Authy ID
# https://www.twilio.com/docs/authy/api/users

curl "https://api.authy.com/protected/json/sms/{AUTHY_ID}?force=true" \
    -H "X-Authy-API-Key: d57d919d11e6b221c9bf6f7c882028f9"
```

```json
{
    "success":true,
    "message":"SMS token was sent",
    "cellphone":"+1-XXX-XXX-XX02"
}
```

### Custom Actions (Optional)

Optionally, you can limit a specific token to a single action, for example coupling a one-time password to a specific login request or transaction. Most implementations will not need this feature.

You can pass `action=` and `action_message=` (optional) to send a code that is only valid for the given action. This is useful if you require codes to perform different actions on your app, for example, you can pass `action=login&action_message="Login code"`when sending a login code.

When using this option you **must** pass the same `action` when verifying the code.

> \[!WARNING]
>
> * Sending an SMS with **custom actions** will always send the SMS even if the
>   user has the Authy app installed. Sending `force=true` isn't necessary.
> * Codes generated through regular SMS and the Authy app won't work when sending the custom actions parameters to the **verify** endpoint.
> * Custom actions isn't supported for voice calls.

Send a One-time Password Via SMS with a Custom Action

```py
# Download the SDK from https://github.com/twilio/authy-python
from authy.api import AuthyApiClient

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
authy_api = AuthyApiClient('api_key')

sms = authy_api.users.request_sms(
    authy_id, 
    {'action': 'login', 'action_message': 'Login code'})

if sms.ok():
    print sms.content
```

```cs
using System;
using System.Net.Http;
using System.Web;
using System.Collections.Generic;


class Program
{

    static void Main(string[] args)
    {
        // Your API key from twilio.com/console/authy/applications
        // DANGER! This is insecure. See https://twil.io/secure
        var AuthyAPIKey = "your_api_key";

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("X-Authy-API-Key", AuthyAPIKey);

            var query = HttpUtility.ParseQueryString(string.Empty);
            query["action"] = "login";
            query["action_message"] = "Login code.";

            var authy_id = 1234;

            HttpResponseMessage response = client.GetAsync(
                $"https://api.authy.com/protected/json/sms/{authy_id}?{query.ToString()}").Result;

            HttpContent responseContent = response.Content;
            Console.WriteLine(responseContent.ReadAsStringAsync().Result);
        }
    }
}
```

```java
// Install the Authy Java SDK from github.com/twilio/authy-java

import com.authy.AuthyApiClient;
import com.authy.api.*;

public class Example {
    // Your API key from twilio.com/console/authy/applications
    // DANGER! This is insecure. See https://twil.io/secure
    public static final String API_KEY = "your_api_key";

    public static void main(String[] args) {
        AuthyApiClient client = new AuthyApiClient(API_KEY);

        Users users = client.getUsers();
        
        Map<String, String> options = new HashMap<String, String>();
        options.put("action", "login");
        options.put("action_message", "Login code.");

        Hash response = users.requestSms(authyId, options);

        if (response.isOk()) {
            System.out.println(response.getMessage());
        } else {
            System.out.println(response.getError());
        }
    }
}
```

```php
<?php

// Download the SDK from https://github.com/twilio/authy-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';

// Your API key from twilio.com/console/authy/applications
// DANGER! This is insecure. See https://twil.io/secure
$authy_api = new Authy\AuthyApi('api_key');

$sms = $authy_api->requestSms($authy_id, array("action" => "login", "action_message" => "Login code"));

if ($sms->ok()) {
    printf($sms->message());
} else {
    print_r($sms->errors());
}
```

```rb
# Download the SDK from https://github.com/twilio/authy-ruby
require 'authy'

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
Authy.api_key = 'your_api_key'
Authy.api_uri = 'https://api.authy.com'

response = Authy::API.request_sms(:id => authy_id, :action => "login", :action_message => "Login code.")

puts response.message
```

```bash
# create a user first to get their Authy ID
# https://www.twilio.com/docs/authy/api/users

curl "https://api.authy.com/protected/json/sms/{AUTHY_ID}?action=login" \
    -H "X-Authy-API-Key: d57d919d11e6b221c9bf6f7c882028f9"
```

```json
{
    "success":true,
    "message":"SMS token was sent",
    "cellphone":"+1-XXX-XXX-XX02"
}
```

## Send a One-Time Password via Voice

For users that don't own a smartphone or are having trouble with SMS Tokens, Authy allows you to use phone calls instead. Like SMS, by default this call will be ignored if the user is using the Authy Mobile app. You can override the default behavior with the `force` parameter.

```bash
GET https://api.authy.com/protected/{FORMAT}/call/{AUTHY_ID}
```

### URL

| Name               | Description                                                                                                                                                                                                               |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `FORMAT` String    | The format to expect back from the REST API call. `json` or `xml`.                                                                                                                                                        |
| `AUTHY_ID` Integer | The Authy ID of the user to send an SMS TOTP. Create an Authy ID by [registering a user](/docs/authy/api/users). Note that password delivery may be upgraded to use the Authy application; see response parameters below. |

### Parameters \[#send-one-time-password-voice-parameters]

| Name                               | Description                                                                                                                                                                                                                                                                                                                      |
| :--------------------------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `force` Boolean (optional)         | Default is `false`. Set to `true` to send one-time passwords over the Voice channel even if the user has an Authy or SDK enabled app installed. Configure default behavior in the console. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                 |
| `action` String (optional)         | The action or context we are trying to validate. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                                           |
| `action_message` String (optional) | Message for the specific action. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                                                           |
| `locale` String (optional)         | The language of the message received by user. If no locale is given, Twilio will try to autodetect it based on the country code. English is used if no locale is autodetected. [More details above.](#supported-languages) ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) ) |

### Response \[#send-one-time-password-voice-response]

| Name               | Description                                                                                                                                                                                                                                                                                                         |
| :----------------- | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `success` Boolean  | Returns true if the request was successful. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                                   |
| `message` String   | A message indicating what happened with the request. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                          |
| `cellphone` String | The country code and last two digits of phone number used to send the message, with the rest obfuscated. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                      |
| `ignored` Boolean  | `True` if we detected an Authy or an SDK enabled app installed and we upgraded the OTP delivery channel from 'Voice' to Push Notification. Authy or SDK users are redirected directly to the requested token. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) ) |
| `device` String    | The type of the last device used by the user. This is only returned when we upgraded delivery from a voice call. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                              |

Send a One-time Password Via Voice Call

```py
# Download the SDK from https://github.com/twilio/authy-python
from authy.api import AuthyApiClient

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
authy_api = AuthyApiClient('api_key')

call = authy_api.users.request_call(authy_id)

if call.ok():
    print call.content
```

```cs
using System;
using System.Net.Http;
using System.Collections.Generic;


class Program
{

    static void Main(string[] args)
    {
        // Your API key from twilio.com/console/authy/applications
        // DANGER! This is insecure. See https://twil.io/secure
        var AuthyAPIKey = "your_api_key";

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("X-Authy-API-Key", AuthyAPIKey);

            var authy_id = 1234;

            HttpResponseMessage response = client.GetAsync(
                $"https://api.authy.com/protected/json/call/{authy_id}").Result;

            HttpContent responseContent = response.Content;
            Console.WriteLine(responseContent.ReadAsStringAsync().Result);
        }
    }
}
```

```java
// Install the Authy Java SDK from github.com/twilio/authy-java

import com.authy.AuthyApiClient;
import com.authy.api.*;

public class Example {
    // Your API key from twilio.com/console/authy/applications
    // DANGER! This is insecure. See https://twil.io/secure
    public static final String API_KEY = "your_api_key";

    public static void main(String[] args) {
        AuthyApiClient client = new AuthyApiClient(API_KEY);

        Users users = client.getUsers();
        Hash response = users.requestCall(authyId);

        if (response.isOk()) {
            System.out.println(response.getMessage());
        } else {
            System.out.println(response.getError());
        }
    }
}
```

```php
<?php

// Download the SDK from https://github.com/twilio/authy-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';

// Your API key from twilio.com/console/authy/applications
// DANGER! This is insecure. See https://twil.io/secure
$authy_api = new Authy\AuthyApi('api_key');

$call = $authy_api->phoneCall($authy_id);

if ($call->ok()) {
    printf($call->message());
} else {
    print_r($call->errors());
}
```

```rb
# Download the SDK from https://github.com/twilio/authy-ruby
require 'authy'

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
Authy.api_key = 'your_api_key'
Authy.api_uri = 'https://api.authy.com'

response = Authy::API.request_phone_call(:id => authy_id)

puts response.message
```

```bash
# create a user first to get their Authy ID
# https://www.twilio.com/docs/authy/api/users

curl -i "https://api.authy.com/protected/json/call/{AUTHY_ID}" \
    -H "X-Authy-API-Key: d57d919d11e6b221c9bf6f7c882028f9"
```

```json
{
    "success":true,
    "message":"Call started...",
    "cellphone":"+1-XXX-XXX-XX02"
}
```

### Default Behavior for Users with the Authy App Installed

If the user has the Authy App, by default, the API will **not** call the user. [See above](/docs/authy/api/one-time-passwords#default-behavior-for-users-with-the-authy-app-installed) for more details. The API response will look like this:

```json
{
  "message": "Call ignored. User is using  App Tokens and this call is not necessary. Pass force=true if you still want to call users that are using the App.",
  "cellphone": "+1-XXX-XXX-XX02",
  "device": "android",
  "ignored": true,
  "success": true
}
```

Like SMS, you can pass `force=true` as a parameter to this API. This will force the phone call to start even if the user is using the Authy app.

## Verify a One-Time Password

To verify a one-time password pass in the user provided `token` and the user `authy_id`. Twilio will use HTTP status codes for the response.

```bash
GET https://api.authy.com/protected/{FORMAT}/verify/{TOKEN}/{AUTHY_ID}
```

### URL

| Name              | Description                                                                                                      |
| :---------------- | :--------------------------------------------------------------------------------------------------------------- |
| `FORMAT` String   | The format to expect back from the REST API call. `json`, or `xml`.                                              |
| `TOKEN` Integer   | The token you are verifying.                                                                                     |
| `AUTHY_ID` String | The Authy ID of the user validating the TOTP. Create an Authy ID by [registering a user](/docs/authy/api/users). |

### Responses \[#verify-one-time-password-responses]

| Name  | Description                                                                                                                        |
| :---- | :--------------------------------------------------------------------------------------------------------------------------------- |
| `200` | Valid token (see note below)\*                                                                                                     |
| `401` | Invalid token. If you wish to verify the token anyway, pass `force=true`. See the force verification section below for an example. |

**Note**: Until you successfully verify a token for a new user, this call will return `200`.

### Response \[#verify-one-time-password-response]

| Name             | Description                                                                                                                                                                                                                                                                                                                                                                                                 |
| :--------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `token` String   | Either "is valid" or "is invalid" ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                                                                                                                                     |
| `success` String | "true" if the code was valid. **Note**: This field is a String and not a Boolean. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                                                                                                                                                                                                     |
| `device` Object  | An object including some details about the device used to get or generate the token. The fields included in the `device` object are: city, region, country, ip, registration\_city, registration\_region, registration\_country, registration\_ip, registration\_date, os\_type, last\_account\_recovery\_at and id. ([📇 PII](/docs/glossary/what-is-personally-identifiable-information-pii#pii-fields) ) |

When the TOTP token is generated in the Authy app or in the SDK, additional device information and registration data are provided in the response.

Verify a Token

```py
# Download the SDK from https://github.com/twilio/authy-python
from authy.api import AuthyApiClient

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
authy_api = AuthyApiClient('api_key')

verification = authy_api.tokens.verify(authy_id, token='1234567')
print(verification.ok())
```

```cs
using System;
using System.Net.Http;
using System.Collections.Generic;


class Program
{
    static void Main(string[] args)
    {
        // Your API key from twilio.com/console/authy/applications
        // DANGER! This is insecure. See https://twil.io/secure
        var AuthyAPIKey = "your_api_key";

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("X-Authy-API-Key", AuthyAPIKey);

            var authy_id = 1234;
            var token = 1234567;

            HttpResponseMessage response = client.GetAsync(
                $"https://api.authy.com/protected/json/verify/{token}/{authy_id}").Result;

            HttpContent responseContent = response.Content;
            Console.WriteLine(responseContent.ReadAsStringAsync().Result);
        }
    }
}
```

```java
// Install the Authy Java SDK from github.com/twilio/authy-java

import com.authy.AuthyApiClient;
import com.authy.api.*;

public class Example {
    // Your API key from twilio.com/console/authy/applications
    // DANGER! This is insecure. See https://twil.io/secure
    public static final String API_KEY = "your_api_key";

    public static void main(String[] args) {
        AuthyApiClient client = new AuthyApiClient(API_KEY);

        Tokens tokens = client.getTokens();
        Token response = tokens.verify(authyId, "1297431");

        if (response.isOk()) {
            System.out.println(response.toMap());
        } else {
            System.out.println(response.getError());
        }
    }
}
```

```php
<?php

// Download the SDK from https://github.com/twilio/authy-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';

// Your API key from twilio.com/console/authy/applications
// DANGER! This is insecure. See https://twil.io/secure
$authy_api = new Authy\AuthyApi('api_key');

$token_entered_by_user = '1234567';
$verification = $authy_api->verifyToken($authy_id, $token_entered_by_user);

if ($verification->ok()) {
    // correct token
}
```

```rb
# Download the SDK from https://github.com/twilio/authy-ruby
require 'authy'

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
Authy.api_key = 'your_api_key'
Authy.api_uri = 'https://api.authy.com'

response = Authy::API.verify(:id => authy_id, :token => '1234567')

if response.ok?
  # correct token
else
  # incorrect token
end
```

```bash
curl -i "https://api.authy.com/protected/json/verify/{TOKEN}/{AUTHY_ID}" \
    -H "X-Authy-API-Key: d57d919d11e6b221c9bf6f7c882028f9"
```

```json
{
  "message": "Token is valid.",
  "token": "is valid",
  "success": "true",
  "device": {
    "city": "San Francisco",
    "country": "United States",
    "ip": "97.20.126.156",
    "region": "California",
    "registration_city": "San Francisco",
    "registration_country": "United States",
    "registration_device_id": 456456,
    "registration_ip": "97.34.234.11",
    "registration_method": "push",
    "registration_region": "California",
    "os_type": "android",
    "last_account_recovery_at": null,
    "id": 83372911,
    "registration_date": 1490996931
  }
}
```

The same API is used to verify tokens from TOTP, sms, and voice channels. However when the OTP token is delivered via [SMS](/docs/authy/api/one-time-passwords#send-a-one-time-password-via-sms) or [voice call](/docs/authy/api/one-time-passwords#send-a-one-time-password-via-voice), no additional device details are provided and the response will look like:

```json
{
  "message": "Token is valid.",
  "token": "is valid",
  "success": "true",
  "device": {
    "id": null,
    "os_type": "sms",
    "registration_date": 1490996931,
    "registration_method": null,
    "registration_country": null,
    "registration_region": null,
    "registration_city": null,
    "country": null,
    "region": null,
    "city": null,
    "ip": null,
    "last_account_recovery_at": null,
    "last_sync_date": null
  }
}
```

### Force One-Time Password Validation for Unregistered User

Use `force=true` to force verification of a one-time password from a new user.

```bash
curl -i "https://api.authy.com/protected/json/verify/{TOKEN}/{AUTHY_ID}" \
  -H "X-Authy-API-Key: d57d919d11e6b221c9bf6f7c882028f9"
```

### Response if `force=false` or Not Set

```bash
{
  "token":"Not checked. User has not yet finished the registration process. Pass force=true to this API to check regardless (more secure)."
}
```

### Response if `force=true`

```bash
{
  "errors": {
    "token":"is invalid"
  }
}
```

### Verify Tokens when using Authy Custom Actions

When using custom actions to send SMS you have to pass `action=` to validate the one-time password.\
For more information [see Custom Actions](/docs/authy/api/one-time-passwords#custom-actions-optional).

```bash
{
  "token": "is valid"
}
```

### Invalid Tokens

A verification attempt with an invalid token will return a `401 Unauthorized` with the following Response body:

```bash
{
  "message": "Token is invalid",
  "token": "is invalid",
  "success": false,
  "errors": {
    "message": "Token is invalid"
  },
  "error_code": "60020"
}
```

## Authenticator App Generated Time-based One-Time Passwords

Create a Generic Authenticator App QR Code

```py
# Download the SDK from https://github.com/twilio/authy-python
from authy.api import AuthyApiClient

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
authy_api = AuthyApiClient('api_key')

# Available in version 2.2.4+
response = api.users.generate_qr(authy_id, size=200, label="My Example App")

print(response.content['qr_code'])
```

```cs
using System;
using System.Net.Http;
using System.Collections.Generic;


class Program
{
    // Authenticator app create qr
    static void Main(string[] args)
    {
        // Your API key from twilio.com/console/authy/applications
        // DANGER! This is insecure. See https://twil.io/secure
        var AuthyAPIKey = "your_api_key";

        using (var client = new HttpClient())
        {
            client.DefaultRequestHeaders.Add("X-Authy-API-Key", AuthyAPIKey);

            var requestContent = new FormUrlEncodedContent(new[] {
                new KeyValuePair<string, string>("label", "My Example App"),
                new KeyValuePair<string, string>("qr_size", "300")
            });

            var authy_id = 1234;

            HttpResponseMessage response = client.PostAsync(
                $"https://api.authy.com/protected/json/users/{authy_id}/secret",
                requestContent).Result;

            HttpContent responseContent = response.Content;
            Console.WriteLine(responseContent.ReadAsStringAsync().Result);
        }
    }
}
```

```rb
# Download the SDK from https://github.com/twilio/authy-ruby
require 'authy'

# Your API key from twilio.com/console/authy/applications
# DANGER! This is insecure. See https://twil.io/secure
Authy.api_key = 'your_api_key'
Authy.api_uri = 'https://api.authy.com'
response = Authy::API.request_qr_code(id: authy_id, qr_size: 250, label: "My Example App")

puts response.qr_code
```

```bash
curl -XPOST "https://api.authy.com/protected/json/users/2/secret" \
-H "X-Authy-API-Key: d57d919d11e6b221c9bf6f7c882028f9" \
-d label="AppName(myuser@example.com)" \
-d qr_size="300"
```

```json
{
  "label": "AppName(myuser@example.com)",
  "Issuer": "AppName",
  "qr_code": "https://[qr_code]",
  "success": true
}
```

### Authy App

When you enroll a user, they will automatically be able to generate Soft Token TOTP codes in the Authy App if they register for Authy with the same phone number that you used to enroll them. You do not need to do anything additional to take advantage of the Authy app. You can disable this behavior with the 'Sync tokens in Authy app' setting in the [Authy settings in the Twilio Console](https://www.twilio.com/console/authy).

To validate these One-Time Passwords, see [Verify a One-Time Password](/docs/authy/api/one-time-passwords#verify-a-one-time-password) below.

### Other Authenticator Apps

To support other Authenticator apps, like Google Authenticator, display a QR code to your users that contain a compatible OTP secret. The API will return a link to a valid QR code.

To customize the QR label and give the final user context about the token like account name or email, you can include the `label` param in the QR generation endpoint. That way many Authenticator apps will automatically render the label in the token list.

To enable, browse to your Authy application in the Twilio Console. Click on your App's Settings and scroll to the bottom.

**Note**: Each QR code request will generate a unique TOTP seed. You can only have a single active QR code per user per protected site. Requesting an additional QR code for a user will invalidate the previous secret and generate a new QR code.

When providing a QR code to a user, be sure to have them validate the code before applying 2FA protection to their account.

> \[!NOTE]
>
> QR codes expire in 24 hours.

```bash
POST https://api.authy.com/protected/{FORMAT}/users/{AUTHY_ID}/secret
```

### URL

| Name               | Description                                                                                                      |
| :----------------- | :--------------------------------------------------------------------------------------------------------------- |
| `FORMAT` String    | The format to expect back from the REST API call. `json` or `xml`.                                               |
| `AUTHY_ID` Integer | The Authy ID of the user to send an SMS TOTP. Create an Authy ID by [registering a user](/docs/authy/api/users). |

### Parameters \[#other-authenticator-apps-parameters]

| Name                         | Description                                                                                                                                                                                                                                                            |
| :--------------------------- | :--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `qr_size` Integer (optional) | Dimension of the QR code that will be returned. Square, so only one number required. Default value is 256. Max value is 320. ([🏢 not PII](/docs/glossary/what-is-personally-identifiable-information-pii#fields-marked-not-pii) )                                     |
| `label` String (optional)    | A custom label for the QR code, this field will be shown by the Authenticator app, it gives context to the user, like the account email. Default value is the application name. ([📇 PII](/docs/glossary/what-is-personally-identifiable-information-pii#pii-fields) ) |
