Detecting High-Risk Phone Numbers with Vonage and Directus Automate
Published September 19th, 2023
When creating new users for your service, it's important to take steps to prevent fraudulent or malicious activity. In this post, you'll use Vonage's Number Insight V2 API and Directus Automate to determine the likelihood of a number being risky at the time of user registration, and let you act on it.
The Vonage Number Insight V2 API assigns a fraud score to numbers, along with a risk recommendation - allow, flag, or block. You can use this recommendation to allow user creation, allow it with a note to your team to validate or block creation.
Before You Start
You will need a Directus project - check out our quickstart guide if you don't already have one. You will also need a Vonage Developer API account, taking note of your API Key and Secret. You should also have a high-risk number to test with (I used the last spam caller I had).
Finally, in Your Directus project, add an input field called phone_number
to the directus_users
collection. This is a system collection, so you will need to expand them in the Data Model settings in order to see the directus_users
collection.
Set Up Trigger
Create a new Flow from your Directus project settings - call it "Check Phone Fraud Risk". Create an Event Hook trigger that is Blocking - this means the flow will run before the data is entered in the database. Set the Scope to items.create
on the directus_users
collection - this means the flow will start whenever a new user is created.
Set Up Number Insight Check
When authenticating your Vonage API call, you must provide your API Key and Secret Base64-encoded. Find an online encoder, and encode the following your_key:your_secret
(the colon is important). Take note of the encoded string.
Create a Webhook / Request URL operation and set the Key to check_number
. Setting the key inserts the data into the Flow's data chain using this property name. Set the Method to POST and the URL to [https://api.nexmo.com/v2/ni](https://api.nexmo.com/v2/ni)
.
Set one header:
Authorization: Basic BASE_64_ENCODED_AUTH_STRING
Authorization: Basic BASE_64_ENCODED_AUTH_STRING
In the body, send the following JSON:
{
"type": "phone",
"phone": "{{$trigger.payload.phone_number}}",
"insights": ["fraud_score"]
}
{
"type": "phone",
"phone": "{{$trigger.payload.phone_number}}",
"insights": ["fraud_score"]
}
Navigate to the Users Module in the module bar and create a new user. You can leave all information blank apart from the phone number - make sure it's in E.164 format. If you need to format numbers, check out a section in our post on building a wedding invite system - it also uses a Vonage API so you can reuse your credentials.
Come back to your flow and open the logs in the sidebar. You can see the operation outputs an object containing a fraud_score
and related information. The risk_score
is a scale of 0 to 100. This project will use the risk_recommendation
value of allow
, flag
, or block
in future steps.
Set Up Conditionals For Fraud Recommendation Result
From the resolved path of the API request, create a Condition operation with the following rule:
{
"check_number": {
"data": {
"fraud_score": {
"risk_recommendation": {
"_eq": "allow"
}
}
}
}
}
{
"check_number": {
"data": {
"fraud_score": {
"risk_recommendation": {
"_eq": "allow"
}
}
}
}
}
The resolved path will be followed if the risk_recommendation
is allow
. If a flow ends on a resolved path, the Blocking Flow will end and the item will be added to the collection.
The reject path will be followed if the value is anything else. From the reject path, create another Condition operation to determine whether the recommendation is flag
or block
:
{
"check_number": {
"data": {
"fraud_score": {
"risk_recommendation": {
"_eq": "flag"
}
}
}
}
}
{
"check_number": {
"data": {
"fraud_score": {
"risk_recommendation": {
"_eq": "flag"
}
}
}
}
}
The resolved path will be flag
, and the reject path will be block
.
The flow now looks like this:
Send Emails If Flagged or Blocked
In this tutorial, a flagged user will still be created, but an email will be sent to an internal team member to perform manual validation. From the resolved path of Is Flagged create a Send Email operation. Add an email address, and inject dynamic values in the Subject and Body:
— Subject —
Flagged Phone Number from {{$trigger.payload.first_name}} {{$trigger.payload.last_name}}
— Body —
The phone number {{$trigger.payload.phone_number}} was flagged by the Vonage Number Insight system with a score of {{check_number.data.fraud_score.risk_score}}.
Please manually validate this user's profile before approving their jobs.
— Subject —
Flagged Phone Number from {{$trigger.payload.first_name}} {{$trigger.payload.last_name}}
— Body —
The phone number {{$trigger.payload.phone_number}} was flagged by the Vonage Number Insight system with a score of {{check_number.data.fraud_score.risk_score}}.
Please manually validate this user's profile before approving their jobs.
Reject New User Item If Blocked
From the reject path of Is Flagged create a Send Email operation. Form a rejection message and send it to the user who tried to register using {{$trigger.payload.email}}
as the recipient.
When a Blocking Flow concludes, data is entered into the database. Currently, there is no elegant way to stop this, but there is a reliable way to make this happen. After the email operation that sends the rejection, create a Run Script operation from the resolved path:
throw new Error('Phone number failed fraud checks');
throw new Error('Phone number failed fraud checks');
This will cause the Flow to fail and not enter the item into the directus_users
collection.
Your final flow should look like this:
Summary
In this post, you have learned how to use the Vonage Number Insight V2 API to check a phone number for the likelihood of fraud at the time of new user registration. Based on the outcome, users are created, flagged, or blocked from being created.
Based on the allow
, flag
, or block
recommendation, you can add any operations from those provided by Directus, or through building your own.
If you have any questions, please feel free to join our Discord server and ask them.