Skip to content

Commit

Permalink
Merge pull request #509 from aricday/verify-prefill
Browse files Browse the repository at this point in the history
feat(templates): add verify-prefill template
  • Loading branch information
cmsunu28 authored Jun 5, 2024
2 parents a6c1880 + a4fbde8 commit 724bd44
Show file tree
Hide file tree
Showing 14 changed files with 364 additions and 2 deletions.
5 changes: 3 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,8 @@
"voice-javascript-sdk",
"voicemail",
"verify-sna",
"reminder-message",
"flex-dialpad"
"flex-dialpad",
"verify-prefill",
"reminder-message"
]
}
5 changes: 5 additions & 0 deletions templates.json
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,11 @@
"name": "Transfers",
"description": "Transfers a call to another number"
},
{
"id": "verify-prefill",
"name": "Twilio Verify Pre-Fill Sample App",
"description": "Showcases the new Twilio Lookup Pre-Fill API"
},
{
"id": "reminder-message",
"name": "Send scheduled reminder messages",
Expand Down
15 changes: 15 additions & 0 deletions verify-prefill/.env.example
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
# description: SID of your Twilio Verify Service
# format: sid
# link: https://www.twilio.com/console/verify/services
# required: true
VERIFY_SERVICE_SID=

# description: Your Lookup API Key. Can be created in the Console.
# required: true
# format: sid
LOOKUP_API_KEY=

# description: Your Lookup API Secret. Can be created in the Console.
# required: true
# format: secret
LOOKUP_API_SECRET=
4 changes: 4 additions & 0 deletions verify-prefill/.owners
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
dkundel
alisontanu
pthirumurthi
aricday
8 changes: 8 additions & 0 deletions verify-prefill/CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Changelog

## [Unreleased]

## [1.0.0]
### Added
- Initial release.

113 changes: 113 additions & 0 deletions verify-prefill/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
# Twilio Verify: Identity-Prefill-API Demo

Demo application showing Twilio Verify and Lookup Identity-Prefill APIs

In today's digital age, user experience is paramount. Every additional step or friction point can deter potential customers, reduce conversion rates, and degrade the overall experience. To combat this, Twilio introduces an innovative feature within its Lookup API: **Identity Pre-Fill** in Private Beta. This powerful tool can revolutionize how businesses handle customer interactions, from onboarding to checkout, by pre-populating user data with verified information. Below, we discuss how this feature works, its potential benefits, and ways you can leverage it through a sample demo app.

This project demonstrates a phone number verification and prefilling user information using Twilio's Verify and Lookups APIs. Users can enter their phone number, receive an OTP, and verify their phone number. Upon successful verification, additional user details such as name and address will be fetched and displayed after a 90 seconds delay.

## Features

- Send OTP to entered phone number using Twilio Verify API.
- Verify OTP entered by the user.
- Fetch and display user information using Twilio Lookups API after successful OTP verification with a 90 seconds delay.

### What is Identity Pre-Fill?

**Identity Pre-Fill** is a new pilot preview capability in the Twilio Lookup API that provides the first name, last name, and address of end-users after verifying their phone number possession using Twilio Verify. This data helps pre-populate forms, making the user experience smoother and faster by reducing manual input efforts.

![verify-prefill](./image.png)

## Pre-requisites

### Technical Considerations

A few technical aspects to keep in mind:

- Queries to the Identity Pre-Fill API are only accepted within 10 minutes of successful verification through Twilio Verify.

- This product is only available in the United States during the pilot phase.

- Use of this product requires the use of the Twilio Verify product. Customers using custom code implementations for verification are not eligible for the pilot.

### Environment variables

This project requires some environment variables to be set. A file named `.env` is used to store the values for those environment variables. To keep your tokens and secrets secure, make sure to not commit the `.env` file in git. When setting up the project with `twilio serverless:init ...` the Twilio CLI will create a `.gitignore` file that excludes `.env` from the version history.

In your `.env` file, set the following values:

| Variable | Description | Required |
| :------------------- | :---------- | :------- |
| `VERIFY_SERVICE_SID` | Verify SID | True |
| `LOOKUP_API_KEY` | ApiKey | True |
| `LOOKUP_API_SECRET` | ApiSecret | True |

### Function Parameters

`/send-otp` expects the following parameters:

| Parameter | Description | Required |
| :---------- | :----------------- | :------- |
| phoneNumber | E.160 Phone Number | True |

`/verify-otp` expects the following parameters:

| Parameter | Description | Required |
| :-------- | :---------- | :------- |
| Code | Verify Code | True |

`/fetch-user-data` expects the following parameters:

| Parameter | Description | Required |
| :--------------- | :------------------ | :------- |
| verificationSid | Approved Verify SID | True |

## Create a new project with the template

1. Install the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart#install-twilio-cli)
2. Install the [serverless toolkit](https://www.twilio.com/docs/labs/serverless-toolkit/getting-started)

```shell
twilio plugins:install @twilio-labs/plugin-serverless
```

3. Initiate a new project

```
twilio serverless:init example --template=verify-prefill && cd example
```

4. Start the server with the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart):

```
twilio serverless:start
```

5. Open the web page at <https://localhost:3000/index.html> and enter your phone number to test

ℹ️ Check the developer console and terminal for any errors, make sure you've set your environment variables.

## Deploying

Deploy your functions and assets with either of the following commands. Note: you must run these commands from inside your project folder. [More details in the docs.](https://www.twilio.com/docs/labs/serverless-toolkit)

With the [Twilio CLI](https://www.twilio.com/docs/twilio-cli/quickstart):

```
twilio serverless:deploy
```

## Test the Application

1. Access your Twilio Function URL that serves the `index.html` file.
2. Enter a phone number and click on "Send OTP."
3. Enter the received OTP and click on "Verify OTP."
4. Upon successful verification, wait for 90 seconds, and then user data should be displayed on the webpage.

### Conclusion

Identity Pre-Fill is a game-changer for businesses looking to enhance user experiences and streamline processes. By reducing the effort required to fill out forms and ensuring data accuracy while speeding up interactions, you can significantly improve customer satisfaction and conversion rates.

#### Learn More

For detailed documentation and more information on Twilio Lookup APIs, visit the [Twilio Lookup API documentation](https://www.twilio.com/docs/lookup/api).
92 changes: 92 additions & 0 deletions verify-prefill/assets/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Verify Prefill Demo</title>
</head>
<body>
<h1>Phone Number Verification</h1>
<form id="verification-form">
<label for="phone-number">Phone Number - E.164:</label>
<input type="tel" id="phone-number" name="phone-number" required>
<button type="button" onclick="sendOTP()">Send OTP</button>
<br><br>
<label for="otp-code">OTP Code:</label>
<input type="text" id="otp-code" name="otp-code" required>
<button type="button" onclick="verifyOTP()">Verify OTP</button>
</form>
<br>
<h2>Identity Lookup Results Below</h2>
<br>
<div id="user-data" style="display:none;">
<h2>User Data: Results</h2>
<p>First Name: <span id="first-name"></span></p>
<p>Last Name: <span id="last-name"></span></p>
<p>Address Line: <span id="address-line"></span></p>
<p>Country Code: <span id="country-code"></span></p>
<p>State: <span id="state"></span></p>
<p>Postal Code: <span id="postal-code"></span></p>
</div>

<script>
async function sendOTP() {
const phoneNumber = document.getElementById('phone-number').value;
const response = await fetch('/send-otp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ phoneNumber })
});
const result = await response.json();
alert(result.message);
}

async function verifyOTP() {
const phoneNumber = document.getElementById('phone-number').value;
const code = document.getElementById('otp-code').value;
const response = await fetch('/verify-otp', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ phoneNumber, code })
});
const result = await response.json();
if (result.success) {
alert('Verification successful. Fetching user data in 90 seconds...');
setTimeout(() => fetchUserData(phoneNumber, result.verificationSid), 90000); // 90 seconds delay
} else {
alert('Verification failed: ' + result.message);
}
}

async function fetchUserData(phoneNumber, verificationSid) {
const response = await fetch('/fetch-user-data', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ phoneNumber, verificationSid })
});
const result = await response.json();
if (result.success) {
displayUserData(result.prefillData);
} else {
alert('Fetching user data failed: ' + result.message);
}
}

function displayUserData(data) {
document.getElementById('first-name').innerText = data.first_name;
document.getElementById('last-name').innerText = data.last_name;
document.getElementById('address-line').innerText = data.address_line;
document.getElementById('country-code').innerText = data.country_code;
document.getElementById('state').innerText = data.state;
document.getElementById('postal-code').innerText = data.postal_code;
document.getElementById('user-data').style.display = 'block';
}
</script>
</body>
</html>
3 changes: 3 additions & 0 deletions verify-prefill/functions/blank.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
exports.handler = function (context, event, callback) {
callback(null, {});
};
27 changes: 27 additions & 0 deletions verify-prefill/functions/fetch-user-data.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
exports.handler = async function (context, event, callback) {
const { phoneNumber } = event;
const { verificationSid } = event;
const lookupApiKey = context.LOOKUP_API_KEY;
const lookupApiSecret = context.LOOKUP_API_SECRET;

try {
// Use dynamic import to load the node-fetch module
const fetch = (await import('node-fetch')).default;

const lookupUrl = `https://lookups.twilio.com/v2/PhoneNumbers/${phoneNumber}?Fields=pre_fill&VerificationSid=${verificationSid}`;
const lookupResponse = await fetch(lookupUrl, {
headers: {
Authorization: `Basic ${Buffer.from(
`${lookupApiKey}:${lookupApiSecret}`
).toString('base64')}`,
},
});

const lookupData = await lookupResponse.json();

return callback(null, { success: true, prefillData: lookupData.pre_fill });
} catch (error) {
console.error('Error fetching user data:', error);
return callback(null, { success: false, message: error.message });
}
};
41 changes: 41 additions & 0 deletions verify-prefill/functions/send-otp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
exports.handler = async function (context, event, callback) {
const { phoneNumber } = event;
const { VERIFY_SERVICE_SID: serviceSid } = context;

// Ensure the Twilio client is initialized
const client = context.getTwilioClient();

if (!serviceSid) {
console.error('Missing VERIFY_SERVICE_SID');
return callback('Missing VERIFY_SERVICE_SID');
}

try {
// Validate phone number using Twilio Lookup API with Node.js library
const lookupResponse = await client.lookups.v2
.phoneNumbers(phoneNumber)
.fetch();

if (!lookupResponse.valid) {
const message =
'Invalid phone number. Please enter a valid number in E.164 format.';
console.error(message, lookupResponse);
return callback(null, { success: false, message });
}

// Start verification if the phone number is valid
const verification = await client.verify.v2
.services(serviceSid)
.verifications.create({ to: phoneNumber, channel: 'sms' });

console.log('Verification response:', verification);

return callback(null, {
success: true,
message: `Verification sent to ${phoneNumber}`,
});
} catch (error) {
console.error('Error sending OTP:', error);
return callback(null, { success: false, message: error.message });
}
};
35 changes: 35 additions & 0 deletions verify-prefill/functions/verify-otp.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
exports.handler = async function (context, event, callback) {
const { phoneNumber, code } = event;
const { VERIFY_SERVICE_SID: serviceSid } = context;

const client = context.getTwilioClient();

if (!serviceSid) {
console.error('Missing VERIFY_SERVICE_SID');
return callback('Missing VERIFY_SERVICE_SID');
}

try {
// Verify the OTP using Twilio Verify API V2
const verificationCheck = await client.verify.v2
.services(serviceSid)
.verificationChecks.create({ to: phoneNumber, code });

console.log('Verification check response:', verificationCheck);

if (verificationCheck.status === 'approved') {
return callback(null, {
success: true,
verificationSid: verificationCheck.sid,
});
}

return callback(null, {
success: false,
message: `Verification failed. Status: ${verificationCheck.status}`,
});
} catch (error) {
console.error('Error verifying OTP:', error);
return callback(null, { success: false, message: error.message });
}
};
Binary file added verify-prefill/image.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
9 changes: 9 additions & 0 deletions verify-prefill/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"name": "verify-prefill",
"version": "1.0.0",
"private": true,
"dependencies": {
"twilio": "^5.0.4",
"node-fetch": "^3.3.2"
}
}
9 changes: 9 additions & 0 deletions verify-prefill/tests/blank.test.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
const { handler } = require('../functions/blank');

describe('verify-prefill function template', () => {
it('Calls callback with empty JSON', () => {
const callback = jest.fn();
handler({}, {}, callback);
expect(callback).toHaveBeenCalledWith(null, {});
});
});

0 comments on commit 724bd44

Please sign in to comment.