# Twilio Verify Push Android Client Library Quickstart

Twilio Verify Push Client Library (SDK) helps you verify users by adding a low-friction, secure, cost-effective, push verification or device approval factor into your own mobile application. It works by registering your user's Android devices as a secure key via public-key cryptography. When your app backend needs to verify that the user is who they say they are, you challenge the user to prove that they still possess their secure key (Android device). This still works even if the user has disabled push notifications (FCM), as your mobile app can poll for challenges via the SDK.

You can also perform Silent Device Approval authentications from the Client Library, which are invisible to the end-user and don't require push notifications. See the [How to Implement Silent Device Approval](#how-to-implement-silent-device-approval) section for more information on implementing this strategy.

You can run the Verify Push Android Client Library in your existing Android app and verify a user using Verify Push API. This Quickstart will walk you through the entire process step-by-step, starting with setting up your Twilio account all the way through verifying a user using your existing Android app and backend.

In this Quickstart, you will learn how to:

1. Sign up for Twilio
2. Configure Push Credential and Verify Service
3. Embed the client SDK into your Android app
4. Setup your app backend
5. Register a user and their device in Verify Push
6. Configure webhooks
7. Verify a user

By the end of this Quickstart, you'll have a solid foundation for implementing Verify Push or Silent Device Approval within your app and backend to verify users at login, transaction, and other sensitive actions.

## Want a technical overview first?

[Technical Overview](https://www.twilio.com/docs/verify/push/technical-overview)

Check out the Verify Push SDK Technical Overview to view its data model, sequence diagrams, and security FAQs.

## Want to see an example?

[Compile Sample App](https://github.com/twilio/twilio-verify-android#running-the-sample-app)

If you don't want to setup Verify Push with your own app or backend immediately, we have built a [Sample App](https://github.com/twilio/twilio-verify-android#running-the-sample-app) embedded with the client Verify Push Android SDK and a [Sample Backend using Twilio functions](https://www.twilio.com/code-exchange/verify-push-backend) that you can compile to see Verify Push in action. These samples can also be helpful for troubleshooting.

## Want to start with iOS?

[iOS Quickstart](https://www.twilio.com/docs/verify/quickstarts/push-ios)

Add Verify Push to your iOS app with the iOS SDK quickstart.

## Sign up for - or sign in to - Twilio

> \[!NOTE]
>
> Already have a Twilio account? Go ahead and [skip this section](#verify-push-and-push-notification).

You can sign up for a free Twilio trial account [here](https://www.twilio.com/try-twilio).

* When you sign up, you'll be asked to verify your personal phone number. This helps Twilio verify your identity.
* Once you verify your number, you'll be asked to create a project. For the sake of this tutorial, you can click on the "Learn and Explore" template. Give your project a name, or just click "skip remaining steps" to continue with the default.
* Once you get through the project creation flow, you'll arrive at your project dashboard in the [Twilio Console](https://www.twilio.com/console). This is where you'll be able to access your Account SID, an authentication token, create a Push Credential, create a Verify Service and more.

> \[!NOTE]
>
> An understandable misconception is that Verify Push requires sending FCM/APNs push notifications to work. This isn't the case, because its critical flows will still work without relying on push notifications that may not be successfully delivered 100% of the time, due to issues like users turning it off, poor connectivity, OEM device manufacturer restrictions, and other factors that cut off the device from the notification service.
>
> However, the user experience of Verify Push can be greatly improved by sending a push notification to your user's device to prompt them on the lock screen to open up your mobile app to view and approve/deny the verification request (challenge). Therefore, we recommend setting up push notifications and the next section explains how.

## Set up FCM push notifications for your Android app (optional)

> \[!NOTE]
>
> Already configured push notifications for your Android app? Go ahead and [skip this section](#create-a-push-credential).

To configure push notifications, follow [these instructions](https://firebase.google.com/docs/cloud-messaging/android/client) to set up a Firebase Cloud Messaging client app on Android:

1. Create a Firebase project for your app
2. Register your app with Firebase
3. Add a Firebase configuration file
4. Add Firebase SDK to your app
5. Edit your app manifest

## Create a push credential

To let Verify Push send push notifications to your Android app, [create an Firebase Cloud Messaging (FCM) push credential](https://help.twilio.com/articles/20768292997147-Updating-Twilio-Push-for-FCM-HTTP-v1-API) that contains your FCM secret.

## Create a Verify Service and add the Push Credential

* Go to [Twilio Console > Verify > Services](https://www.twilio.com/console/verify/services) and create a new Service.

* Alternatively, you can select any existing Service. However, we recommend creating a new service for testing so you don't accidentally interfere with a production environment.

* From [Twilio Console > Verify > Services](https://www.twilio.com/console/verify/services), select your Service to access its Settings. Under the Push section, select the Push Credential SID(s) that you want this Service to use for sending push notifications. One SID can be selected for your Android app (FCM) and one for your iOS app (APN).

## Embed the SDK into your Android app

Follow the [installation steps in the README file of the Twilio Verify Android repo](https://github.com/twilio/twilio-verify-android#installation). The installation steps will explain how to add the Android library to your `build.gradle` file and setup your Android app to work with Firebase Cloud Messaging (FCM).

After you import the Twilio Verify Android library, you can start to integrate your existing app with Verify Push.

To get started, you will need to create an instance of the `TwilioVerify` class, using its `Builder.` Type or paste the sample code.

Embed the SDK into your app.

```java
TwilioVerify twilioVerify = new TwilioVerify.Builder(applicationContext).build();
```

```kotlin
val twilioVerify = TwilioVerify.Builder(applicationContext).build()
```

[Full Kotlin source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/kotlin/TwilioVerifyKotlinProvider.kt#L14)

[Full Java source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/java/TwilioVerifyJavaProvider.java#L17)

## Obtain a Verify Push API access token for your Android app

Your Android app needs to obtain an [Access Token](/docs/verify/api/access-token) (technically an Enrollment JWE, similar to a JSON Web Token (JWT)) to make direct requests to the Verify Push API in the future. This Access Token request needs to be brokered by your app backend. To do this, you need to:

1. Expose an API endpoint in your app backend for your Android app to request the Access Token
2. Have your app backend request an Access Token from Verify Push API
3. Return the Access Token, `identity` and `Verify Service SID` to the Android app

### Expose an API endpoint in your app backend for your app to request the Access Token

Check out our [Sample Backend using Twilio functions](https://github.com/twilio-labs/function-templates/blob/main/verify-push-backend/functions/access-token.js#L71) for an implementation example. In a production web application, you would restrict access token retrieval to the currently authenticated user, using whatever type of authentication your service already uses.

### Have your app backend request an Access Token from Verify Push API

In the sidebar to the right (or below) is sample code for requesting an access token from the Verify Push API in all languages supported by Twilio server-side SDKs. You will need the Verify `service_sid`, as well as the user id (such as a GUID or the user's primary key in your database table) you use as the `identity` with this Verify service.

Request an Access Token from Verify Push API

```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 createAccessToken() {
  const accessToken = await client.verify.v2
    .services("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    .accessTokens.create({
      factorType: "push",
      identity: "User_UUID",
    });

  console.log(accessToken.sid);
}

createAccessToken();
```

```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)

access_token = client.verify.v2.services(
    "VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
).access_tokens.create(factor_type="push", identity="User_UUID")

print(access_token.sid)
```

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

using System;
using Twilio;
using Twilio.Rest.Verify.V2.Service;
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 accessToken = await AccessTokenResource.CreateAsync(
            factorType: AccessTokenResource.FactorTypesEnum.Push,
            identity: "User_UUID",
            pathServiceSid: "VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX");

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

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

import com.twilio.Twilio;
import com.twilio.rest.verify.v2.service.AccessToken;

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);
        AccessToken accessToken =
            AccessToken.creator("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "User_UUID", AccessToken.FactorTypes.PUSH)
                .create();

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

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

import (
	"fmt"
	"github.com/twilio/twilio-go"
	verify "github.com/twilio/twilio-go/rest/verify/v2"
	"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 := &verify.CreateAccessTokenParams{}
	params.SetFactorType("push")
	params.SetIdentity("User_UUID")

	resp, err := client.VerifyV2.CreateAccessToken("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
		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);

$access_token = $twilio->verify->v2
    ->services("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    ->accessTokens->create(
        "User_UUID", // Identity
        "push" // FactorType
    );

print $access_token->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)

access_token = @client
               .verify
               .v2
               .services('VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
               .access_tokens
               .create(
                 factor_type: 'push',
                 identity: 'User_UUID'
               )

puts access_token.sid
```

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

twilio api:verify:v2:services:access-tokens:create \
   --service-sid VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
   --factor-type push \
   --identity User_UUID
```

```bash
curl -X POST "https://verify.twilio.com/v2/Services/VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/AccessTokens" \
--data-urlencode "FactorType=push" \
--data-urlencode "Identity=User_UUID" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "sid": "YKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "service_sid": "VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "entity_identity": "ff483d1ff591898a9942916050d2ca3f",
  "factor_type": "push",
  "factor_friendly_name": "John Doe iPhone",
  "ttl": 300,
  "date_created": "2015-07-30T20:00:00Z",
  "token": "eyJ6aXAiOiJERUYiLCJraWQiOiJTQVNfUzNfX19LTVNfdjEiLCJjdHkiOiJ0d2lsaW8tZnBhO3Y9MSIsImVuYyI6IkEyNTZHQ00iLCJhbGciOiJkaXIifQ..qjltWfIgQaTwp2De.81Z_6W4kR-hdlAUvJQCbwS8CQ7QAoFRkOvNMoySEj8zEB4BAY3MXhPARfaK4Lnr4YceA2cXEmrzPKQ7bPm0XZMGYm1fqLYzAR8YAqUetI9WEdQLFytg1h4XnJnXhgd99eNXsLkpKHhsCnFkchV9eGpRrdrfB0STR5Xq0fdakomb98iuIFt1XtP0_iqxvxQZKe1O4035XhK_ELVwQBz_qdI77XRZBFM0REAzlnEOe61nOcQxkaIM9Qel9L7RPhcndcCPFAyYjxo6Ri5c4vOnszLDiHmeK9Ep9fRE5-Oz0px0ZEg_FgTUEPFPo2OHQj076H1plJnFr-qPINDJkUL_i7loqG1IlapOi1JSlflPH-Ebj4hhpBdMIcs-OX7jhqzmVqkIKWkpPyPEmfvY2-eA5Zpoo08YpqAJ3G1l_xEcHl28Ijkefj1mdb6E8POx41skAwXCpdfIbzWzV_VjFpmwhacS3JZNt9C4hVG4Yp-RGPEl1C7aJHRIUavAmoRHaXbfG20zzv5Zu0P5PcopDszzoqVfZpzc.GCt35DWTurtP-QaIL5aBSQ",
  "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/AccessTokens/YKaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
}
```

> \[!WARNING]
>
> **Do not use Personally Identifiable Information for `identity`. Use an immutable user identifier like a UUID, GUID, or SID.**\
> Verify Push uses **`identity`** as a unique identifier of a user. You should not use directly identifying information (aka personally identifiable information or PII) like a **person's name, home address, email or phone number, etc., as `identity`** because the systems that will process this attribute assume it is not directly identifying information.

## Register a user and their device

> \[!WARNING]
>
> Do not store your `Verify Service SID` in your app. Get it from your backend, as well as the `identity.` You can find an example in the [Sample Backend using Twilio functions](https://github.com/twilio-labs/function-templates/blob/main/verify-push-backend/functions/access-token.js#L76)

Register a user and their device in Verify Push by creating and verifying a [`Factor`](/docs/verify/api/factor). Type or paste the code samples for both of these steps.

### Create a factor

> \[!NOTE]
>
> You don't need to make a separate Create Entity call, because the Create Factor call will create an Entity and a Factor at the same time, if the Entity didn't exist.

> \[!WARNING]
>
> You can add custom metadata associated with the factor on creation. This is added by the Device/SDK directly to allow for the inclusion of device information. Available in SDK version 0.8.0 and above.

> \[!WARNING]
>
> As [getting the device registration token for push](https://firebase.google.com/docs/cloud-messaging/android/client#sample-register) could happen in a different moment before creating the factor, please validate that your app has a registration token before using it as a `pushToken` in the create factor method. If you don't want to configure push notification for this factor, then set the `pushToken` to `null`.

Create a factor.

```java
Map<String,String> metadata = new HashMap<>(); // Custom metadata associated with the factor. Optional
metadata.put("os", "Android");
FactorPayload factorPayload = new PushFactorPayload(factorName, verifyServiceSid, identity, pushToken, accessToken, metadata);
twilioVerify.createFactor(factorPayload,
  new Function1<Factor, Unit>() {
    @Override public Unit invoke(Factor factor) {
      // Success
      return Unit.INSTANCE;
    }
  }, 
  new Function1<TwilioVerifyException, Unit>() {
    @Override public Unit invoke(TwilioVerifyException error) {
      // Error
      return Unit.INSTANCE;
    }
  });
```

```kotlin
val metadata = mapOf("os" to "Android") // Custom metadata associated with the factor. Optional
val factorPayload = PushFactorPayload(factorName, verifyServiceSid, identity, pushToken, accessToken, metadata)
twilioVerify.createFactor(factorPayload, { factor ->
  // Success
}, { exception ->
  // Error
})
```

[Full Kotlin source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/kotlin/TwilioVerifyKotlinAdapter.kt#L38)

[Full Java source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/java/TwilioVerifyJavaAdapter.java#L47)

### Verify a factor

Verify a factor.

```java
VerifyFactorPayload verifyFactorPayload = new VerifyPushFactorPayload(factorSid);
twilioVerify.verifyFactor(verifyFactorPayload,
  new Function1<Factor, Unit>() {
    @Override public Unit invoke(Factor factor) {
      // Success
      return Unit.INSTANCE;
    }
  }, 
  new Function1<TwilioVerifyException, Unit>() {
    @Override public Unit invoke(TwilioVerifyException error) {
      // Error
      return Unit.INSTANCE;
    }
  });
```

```kotlin
val verifyFactorPayload = VerifyPushFactorPayload(factorSid)
twilioVerify.verifyFactor(verifyFactorPayload, { factor ->
  // Success
}, { exception ->
  // Error
})
```

[Full Kotlin source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/kotlin/TwilioVerifyKotlinAdapter.kt#L56)

[Full Java source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/java/TwilioVerifyJavaAdapter.java#L59)

> \[!WARNING]
>
> * The created factors and key pairs will not persist in the device after the app is uninstalled and reinstalled for security reasons, because the factors information is saved using the Android Keystore. You should provide an alternative way to enroll the factor again.
> * The Verify API has a limit of 20 Factors of `factor_type=push` per Entity. This limit could be reached if a user uninstalls and reinstalls your app frequently. Unverified Factors will be automatically deleted and unverifiable after 1-24 hours from when they were created, but you will need to explicitly [delete verified Factors](/docs/verify/api/factor#delete-a-factor-resource).

## Configure webhooks (optional)

Configure a webhook callback for your app backend to be notified of events such as when a `Factor` has been verified or when a `Challenge` has been approved, so that it knows to advance the user to the next step in your flow. This is more real-time and efficient than constantly polling the Verify Push API for the `status` of a `Factor` or `Challenge`.

**Follow the steps in this [Verify Webhooks](/docs/verify/api/webhooks) page.**

Configure webhook

```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 createWebhook() {
  const webhook = await client.verify.v2
    .services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    .webhooks.create({
      eventTypes: ["*"],
      friendlyName: "My Webhook",
      webhookUrl: "https://example.com/webhook",
    });

  console.log(webhook.sid);
}

createWebhook();
```

```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)

webhook = client.verify.v2.services(
    "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
).webhooks.create(
    event_types=["*"],
    friendly_name="My Webhook",
    webhook_url="https://example.com/webhook",
)

print(webhook.sid)
```

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

using System;
using Twilio;
using Twilio.Rest.Verify.V2.Service;
using System.Threading.Tasks;
using System.Collections.Generic;

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 webhook = await WebhookResource.CreateAsync(
            eventTypes: new List<string> { "*" },
            friendlyName: "My Webhook",
            webhookUrl: "https://example.com/webhook",
            pathServiceSid: "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa");

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

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

import java.util.Arrays;
import com.twilio.Twilio;
import com.twilio.rest.verify.v2.service.Webhook;

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);
        Webhook webhook = Webhook
                              .creator("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
                                  "My Webhook",
                                  Arrays.asList("*"),
                                  "https://example.com/webhook")
                              .create();

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

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

import (
	"fmt"
	"github.com/twilio/twilio-go"
	verify "github.com/twilio/twilio-go/rest/verify/v2"
	"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 := &verify.CreateWebhookParams{}
	params.SetEventTypes([]string{
		"*",
	})
	params.SetFriendlyName("My Webhook")
	params.SetWebhookUrl("https://example.com/webhook")

	resp, err := client.VerifyV2.CreateWebhook("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
		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);

$webhook = $twilio->verify->v2
    ->services("VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa")
    ->webhooks->create(
        "My Webhook", // FriendlyName
        ["*"], // EventTypes
        "https://example.com/webhook" // WebhookUrl
    );

print $webhook->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)

webhook = @client
          .verify
          .v2
          .services('VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa')
          .webhooks
          .create(
            event_types: [
              '*'
            ],
            friendly_name: 'My Webhook',
            webhook_url: 'https://example.com/webhook'
          )

puts webhook.sid
```

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

twilio api:verify:v2:services:webhooks:create \
   --service-sid VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa \
   --event-types * \
   --friendly-name "My Webhook" \
   --webhook-url https://example.com/webhook
```

```bash
curl -X POST "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Webhooks" \
--data-urlencode "EventTypes=*" \
--data-urlencode "FriendlyName=My Webhook" \
--data-urlencode "WebhookUrl=https://example.com/webhook" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Webhooks/YWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "sid": "YWaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "service_sid": "VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "friendly_name": "My Webhook",
  "event_types": [
    "factor.deleted",
    "factor.verified"
  ],
  "webhook_method": "POST",
  "webhook_url": "https://example.com/webhook",
  "status": "enabled",
  "version": "v2",
  "date_created": "2015-07-30T20:00:00Z",
  "date_updated": "2015-07-30T20:00:00Z"
}
```

## Verify a user

Congratulations! Verify Push consists of two user sequences, and you've just completed the first one: user and device registration. The second sequence is to challenge and verify (authenticate) a user with their registered device. Read on for the step-by-step instructions.

## Create a Challenge

Your web application backend needs to call the Verify Push API to create a [`Challenge`](/docs/verify/api/challenge) using the [`Factor`](/docs/verify/api/factor) that you've just created. When the challenge is created, Verify Push sends a push notification to the registered device using the configured Push Credential.

The code in the sidebar to the right/bottom demonstrates how to create those challenges using the Twilio server-side SDKs.

Create a Challenge to verify a user

```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 createChallenge() {
  const challenge = await client.verify.v2
    .services("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    .entities("User_UUID")
    .challenges.create({
      "details.fields": [
        {
          label: "msg",
          value: "Challenge details shown to user",
        },
      ],
      "details.message":
        "Message shown to the user when the push notification arrives",
      expirationDate: new Date("2020-07-30 21:00:00"),
      factorSid: "YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
      hiddenDetails: {
        msg: "Challenge details not shown to user",
      },
    });

  console.log(challenge.sid);
}

createChallenge();
```

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

# 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)

challenge = (
    client.verify.v2.services("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    .entities("User_UUID")
    .challenges.create(
        details_message="Message shown to the user when the push notification arrives",
        details_fields=[
            {"label": "msg", "value": "Challenge details shown to user"}
        ],
        hidden_details={"msg": "Challenge details not shown to user"},
        expiration_date=datetime(2020, 7, 30, 21, 0, 0),
        factor_sid="YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    )
)

print(challenge.sid)
```

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

using System;
using Twilio;
using Twilio.Rest.Verify.V2.Service.Entity;
using System.Threading.Tasks;
using System.Collections.Generic;

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 challenge = await ChallengeResource.CreateAsync(
            detailsMessage: "Message shown to the user when the push notification arrives",
            detailsFields: new List<Object> { new Dictionary<string, Object>() {
                { "label", "msg" }, { "value", "Challenge details shown to user" }
            } },
            hiddenDetails: new Dictionary<
                string,
                Object>() { { "msg", "Challenge details not shown to user" } },
            expirationDate: new DateTime(2020, 7, 30, 21, 0, 0),
            factorSid: "YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            pathServiceSid: "VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            pathIdentity: "User_UUID");

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

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

import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.util.Arrays;
import java.util.HashMap;
import com.twilio.Twilio;
import com.twilio.rest.verify.v2.service.entity.Challenge;

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);
        Challenge challenge =
            Challenge.creator("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", "User_UUID", "YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
                .setDetailsMessage("Message shown to the user when the push notification arrives")
                .setDetailsFields(Arrays.asList(new HashMap<String, Object>() {
                    {
                        put("label", "msg");
                        put("value", "Challenge details shown to user");
                    }
                }))
                .setHiddenDetails(new HashMap<String, Object>() {
                    {
                        put("msg", "Challenge details not shown to user");
                    }
                })
                .setExpirationDate(ZonedDateTime.of(2020, 7, 30, 21, 0, 0, 0, ZoneId.of("UTC")))
                .create();

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

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

import (
	"fmt"
	"github.com/twilio/twilio-go"
	verify "github.com/twilio/twilio-go/rest/verify/v2"
	"os"
	"time"
)

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 := &verify.CreateChallengeParams{}
	params.SetDetailsMessage("Message shown to the user when the push notification arrives")
	params.SetDetailsFields([]interface{}{
		map[string]interface{}{
			"label": "msg",
			"value": "Challenge details shown to user",
		},
	})
	params.SetHiddenDetails(map[string]interface{}{
		"msg": "Challenge details not shown to user",
	})
	params.SetExpirationDate(time.Date(2020, 7, 30, 21, 0, 0, 0, time.UTC))
	params.SetFactorSid("YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")

	resp, err := client.VerifyV2.CreateChallenge("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
		"User_UUID",
		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);

$challenge = $twilio->verify->v2
    ->services("VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX")
    ->entities("User_UUID")
    ->challenges->create(
        "YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX", // FactorSid
        [
            "detailsMessage" =>
                "Message shown to the user when the push notification arrives",
            "detailsFields" => [
                [
                    "label" => "msg",
                    "value" => "Challenge details shown to user",
                ],
            ],
            "hiddenDetails" => [
                "msg" => "Challenge details not shown to user",
            ],
            "expirationDate" => new \DateTime("2020-07-30T21:00:00Z"),
        ]
    );

print $challenge->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)

challenge = @client
            .verify
            .v2
            .services('VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX')
            .entities('User_UUID')
            .challenges
            .create(
              details_message: 'Message shown to the user when the push notification arrives',
              details_fields: [
                {
                  'label' => 'msg',
                  'value' => 'Challenge details shown to user'
                }
              ],
              hidden_details: {
                'msg' => 'Challenge details not shown to user'
              },
              expiration_date: Time.new(2020, 7, 30, 21, 0, 0),
              factor_sid: 'YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX'
            )

puts challenge.sid
```

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

twilio api:verify:v2:services:entities:challenges:create \
   --service-sid VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX \
   --identity User_UUID \
   --details.message "Message shown to the user when the push notification arrives" \
   --details.fields "{\"label\":\"msg\",\"value\":\"Challenge details shown to user\"}" \
   --hidden-details "{\"msg\":\"Challenge details not shown to user\"}" \
   --expiration-date 2016-07-31 \
   --factor-sid YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
```

```bash
HIDDEN_DETAILS_OBJ=$(cat << EOF
{
  "msg": "Challenge details not shown to user"
}
EOF
)
curl -X POST "https://verify.twilio.com/v2/Services/VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/Entities/User_UUID/Challenges" \
--data-urlencode "Details.Message=Message shown to the user when the push notification arrives" \
--data-urlencode "Details.Fields={\"label\":\"msg\",\"value\":\"Challenge details shown to user\"}" \
--data-urlencode "HiddenDetails=$HIDDEN_DETAILS_OBJ" \
--data-urlencode "ExpirationDate=2016-07-31" \
--data-urlencode "FactorSid=YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX" \
-u $TWILIO_ACCOUNT_SID:$TWILIO_AUTH_TOKEN
```

```json
{
  "sid": "YC03aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "account_sid": "ACaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "service_sid": "VAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "entity_sid": "YEaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "identity": "User_UUID",
  "factor_sid": "YFXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "date_created": "2015-07-30T20:00:00Z",
  "date_updated": "2015-07-30T20:00:00Z",
  "date_responded": "2015-07-30T20:00:00Z",
  "expiration_date": "2020-07-30T21:00:00Z",
  "status": "pending",
  "responded_reason": "none",
  "details": {
    "message": "Hi! Mr. John Doe, would you like to sign up?",
    "date": "2020-07-01T12:13:14Z",
    "fields": [
      {
        "label": "Action",
        "value": "Sign up in portal"
      }
    ]
  },
  "hidden_details": {
    "ip": "172.168.1.234"
  },
  "metadata": null,
  "factor_type": "push",
  "url": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Challenges/YC03aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa",
  "links": {
    "notifications": "https://verify.twilio.com/v2/Services/VAaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Entities/ff483d1ff591898a9942916050d2ca3f/Challenges/YC03aaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/Notifications"
  }
}
```

> \[!NOTE]
>
> * You may choose to put Personally Identifiable Information (PII) or other sensitive information in `details` and `hidden_details`. The data in each param will be stored per its retention policy listed in the [Challenge](/docs/verify/api/challenge)resource.
> * If you are sending push notifications, use the [Notifications](/docs/verify/api/notifications-resource) resource to resend a push notification if the first one fails for some [reason](/docs/verify/push/best-practices#1-what-are-methods-to-ensure-that-the-device-receives-the-challenge). This is better than creating another duplicate Challenge.

## Poll for the Challenge

Now that the pending Challenge has been created in the Verify API, your mobile app needs to become aware of it. This can be done by telling your user to open up your mobile app on the registered device, and then having your app check (poll) the Verify API for any pending Challenges whenever it's opened.

**Example implementation**

1. Display a message for your user to open your app on the registered device: "Approve this login/transaction by opening the `[App name]` app and tapping `[Approve button text]`
2. Know when the app is opened and in foreground, then automatically poll for pending challenges.

   1. Android: Use the [onResume()](https://developer.android.com/reference/android/app/Activity#onResume\(\)) method of your activity or subscribe to a [lifecycle observer.](https://developer.android.com/guide/components/activities/activity-lifecycle#onresume)
   2. iOS: Use the [applicationWillEnterForeground](https://developer.apple.com/documentation/uikit/uiapplicationdelegate/1623076-applicationwillenterforeground) method in your application delegate or [sceneWillEnterForeground](https://developer.apple.com/documentation/uikit/uiscenedelegate/3197918-scenewillenterforeground) if your app supports scenes, see more info [here.](https://developer.apple.com/documentation/uikit/app_and_environment/scenes/preparing_your_ui_to_run_in_the_foreground)
3. Alternatively, you can display to the user an "inbox" menu item to manually check for "pending verification requests" (challenges)
4. To get the pending challenges you can call the `getAllChallenges` method in the SDK, passing `Pending` as `ChallengeListPayload's status` and `Desc` as `ChallengeListPayload's order`
5. You can define the number of challenges to be returned using `ChallengeListPayload's pageSize.` To show only one challenge, pass `1` as `ChallengeListPayload's pageSize`
6. You can display the pending challenge(s) as a pop-up, just like if your app had received a push notification
7. Alternatively, you can show multiple pending challenges in an "inbox" menu item. You can display a badge number in the inbox to let the user know how many pending challenges are waiting for them.

> \[!WARNING]
>
> Make sure to specify `Desc` as the `ChallengeListPayload`'s order in step 4 above and whenever you want to get the most recent challenge first. If you don't specify `Desc`, the list will default to returning `Asc` order (oldest challenge first), which could create high latency and a timeout error if the list of challenges is long and you are looking for the most recent challenge.

Get pending challenges.

```java
ChallengeListPayload challengeListPayload = new ChallengeListPayload(factorSid, PAGE_SIZE, Pending, Desc);
twilioVerify.getAllChallenges(challengeListPayload,
  new Function1<List<Challenges>, Unit>() {
    @Override
    public Unit invoke(List<Challenges> challenges) {
      // Show pending challenge(s)
      return Unit.INSTANCE;
    }
  },
  new Function1<TwilioVerifyException, Unit>() {
    @Override public Unit invoke(TwilioVerifyException error) {
      // Error
      return Unit.INSTANCE;
    }
});
```

```kotlin
twilioVerify.getAllChallenges(ChallengeListPayload(factorSid, PAGE_SIZE, Pending, order = Desc),
      { challengeList ->
        // Show pending challenge(s)
      },
      {
        // Error
      }
    )
```

## Read Push Notification (optional)

If you setup FCM push notifications as instructed in a previous section, then a push notification will be automatically sent when the pending Challenge is created. Your Android app then needs to read the contents of the push notification payload to obtain the `challengeSid`, `factorSid`, and `message` parameters.

The following Kotlin and Java code snippets run when there is an incoming FCM push notification, and if the type is `verify_push_challenge`, read the parameters out of the notification.

Read Push Notification.

```java
@Override public void onMessageReceived(@NonNull RemoteMessage remoteMessage) {
  String type = remoteMessage.getData().get("type");
  if ("verify_push_challenge".equals(type)) {
    String factorSid = remoteMessage.getData().get("factor_sid");
    String challengeSid = remoteMessage.getData().get("challenge_sid");
    String message = remoteMessage.getData().get("message");
    if (factorSid != null && challengeSid != null) {
      // Show push notification or update challenge
    }
  }
}
```

```kotlin
override fun onMessageReceived(remoteMessage: RemoteMessage) {
  when (remoteMessage.data["type"]) {
    "verify_push_challenge" -> {
      val factorSid = remoteMessage.data["factor_sid"]
      val challengeSid = remoteMessage.data["challenge_sid"]
      val message = remoteMessage.data["message"]
      if (factorSid != null && challengeSid != null) {
        // Show push notification or update challenge
      }
    }
  }
}
```

Once your app receives the push notification containing the `challengeSid`, it needs to retrieve the `challenge` details that correspond to that sid. Type/paste the sample code below. This step is not necessary if you have already retrieved the `challenge` details via the `getAllChallenges` method as previously instructed in the "poll for the challenge" section.

Get and display Challenge details.

```java
twilioVerify.getChallenge(challengeSid, factorSid,
  new Function1<Challenge, Unit>() {
    @Override public Unit invoke(Challenge challenge) {
      // Success
      return Unit.INSTANCE;
    }
  }, 
  new Function1<TwilioVerifyException, Unit>() {
    @Override public Unit invoke(TwilioVerifyException error) {
      // Error
      return Unit.INSTANCE;
    }
  });
```

```kotlin
twilioVerify.getChallenge(challengeSid, factorSid, { challenge ->
  // Success
}, { exception ->
  // Error
})
```

[Full Kotlin source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/viewmodel/ChallengeViewModel.kt#L21)

[Full Java source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/java/TwilioVerifyJavaAdapter.java#L76)

> \[!NOTE]
>
> See additional tips for push notifications and ensuring that the device receives the challenge [here](/docs/verify/push/best-practices#1-what-are-methods-to-ensure-that-the-device-receives-the-challenge).

## Update the Challenge to verify the user

In an actual implementation, your Android app should either display the Challenge details to the user and request confirmation that the Challenge is expected, or silently approve the Challenge, because your app already knows that the user is trying to login on the same device as the registered device that is being challenged.

In either case, the next step is for your app to call the Verify Push API directly and update the Challenge `status` as `approved` or `denied.` Type/paste the sample code below into your Android app.

Update the Challenge to verify the user.

```java
UpdateChallengePayload updateChallengePayload = new UpdatePushChallengePayload(factorSid, challengeSid, newStatus);
    twilioVerify.updateChallenge(updateChallengePayload,
        new Function0<Unit>() {
          @Override
          public Unit invoke() {
            // Success
            return Unit.INSTANCE;
          }
        },
        new Function1<TwilioVerifyException, Unit>() {
          @Override public Unit invoke(TwilioVerifyException error) {
            // Error
            return Unit.INSTANCE;
          }
        });
```

```kotlin
val updateChallengePayload =  UpdatePushChallengePayload(factorSid, challengeSid, newStatus)
twilioVerify.updateChallenge(updateChallengePayload, {
  // Success
}, { exception ->
  // Error
})
```

[Full Kotlin source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/viewmodel/ChallengeViewModel.kt#L36)

[Full Java source](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/java/TwilioVerifyJavaAdapter.java#L65)

### How to Implement Silent Device Approval

By optionally implementing Silent Device Approval within the Verify Push Client Library, you can silently approve challenges without push notifications when your app already knows that the user is trying to complete an action (actively logging in, making a transaction, etc.) on the same device as the registered device that is being challenged. This results in an authentication that is completely invisible to the user. While implementation details will vary, here are some suggested steps:

* In order to be confident about the user's intent, the challenge approval should be done when the app is in foreground during the flow of the action that is being approved (e.g. immediately after the user taps "login").
* Identify the device starting the action and create a challenge for the factor linked to that device (a factor only represents one device).
* If you want to send challenges for multiple devices (factors) or if you want to be sure that you're approving the correct challenge, there are two options:

  * Include the associated challenge sid for the action in the response to the device and validate that it's the expected challenge sid before approving it.
  * Assign a transaction id to the started action and include it in the response to the device, and add the transaction id to the challenge's hidden details, so before approving the challenge you can get the challenge's hidden details to validate it is the expected challenge
* To receive the challenge on the client-side, you can:

  * Implement a strategy to listen for incoming push notifications when the app is in foreground and after some seconds, poll for pending challenges just in case the push notification did not arrive.
  * Poll for the latest pending challenge for an immediate approval, if your backend implementation can guarantee that the challenge was already created.

For additional suggestions, see:

* [Getting challenge's hidden details](/docs/verify/quickstarts/push-android#code-get-and-display-challenge-details)
* [Full source for listening to incoming push notifications when the app is in foreground](https://github.com/twilio/twilio-verify-android/blob/main/sample/src/main/java/com/twilio/verify/sample/view/MainActivity.kt#L68)
* [Poll for the challenge](/docs/verify/quickstarts/push-android#poll-for-the-challenge)

## Receive Challenge status

Once Verify Push API receives a Challenge update from your Android app, it will forward the update by sending a webhook callback (`challenge.approved` or `challenge.denied`) to your app backend, so that it knows to take your user to the next step in your flow. If you don't have a webhook configured, you can poll the Verify Push API for the `status` of the `Challenge`.

This completes the second user sequence of Verify Push: Challenge and verify a user.

### Congratulations

## Where to next?

Now that you've verified your first user, check out the following resources to continue your Verify Push journey with Twilio:

* Add Verify Push to your iOS app by following the [iOS SDK Quickstart](/docs/verify/quickstarts/push-ios)
* Prepare to go-live by reviewing [Verify Push Best Practices for Production use](/docs/verify/push/best-practices)
* Explore adding [Verify's other verification channels](/docs/verify) beyond Push

Let's build something amazing.
