Detecting Robocalls in Java with Twilio Lookup and Nomorobo

August 28, 2019
Written by

Detecting Robocalls in Java with Twilio Lookup and Nomorobo

Twilio's CEO Jeff Lawson recently wrote about the history of robocalls and what we're doing to eliminate them. 

Until that happens, we can build a tool in Java that will help us identify an unwanted call using the Twilio Lookup API with the Nomorobo Spam Score Add-on.

Set Up

In order to create this project you’ll need

Add the Nomorobo Add-on to your Twilio Account

Head to the Twilio Console and install the Nomorobo add-on. Look for the yellow logo and click through to "Install".

Nomorobo Add-on logo

Leave the name as nomorobo_spamscore and "Save" the Add-On.

Setting Up your Java Project

Create a new Maven project with the java8-quickstart-archetype:

mvn archetype:generate \
 -DarchetypeGroupId=pl.org.miki \
 -DarchetypeArtifactId=java8-quickstart-archetype \
 -DarchetypeVersion=1.0.0 \
 -DtestLibrary=none

This command will prompt for a groupId and artifactId. If you’re not sure what those are then check the Maven naming guide - I used lol.gilliard and twilio-lookup-nomorobo. You can accept the defaults for version and package. The project will be created in a subdirectory with the same name as the artifactId. Open the project in your favourite IDE.

In the pom.xml file there will be an empty <dependencies> section - we’ll be using the Twilio Java Helper Library, so add it here:

<dependency>
  <groupId>com.twilio.sdk</groupId>
  <artifactId>twilio</artifactId>
  <version>7.37.4</version>
</dependency>

Next you’ll need to create a class to hold your code.  Inside the src/main/java directory add a new class - I called mine LookupNomorobo.  Then add the following code:

import com.twilio.Twilio;
import com.twilio.type.PhoneNumber;

public class LookupNomorobo {

   public static void main(String[] args) {
       Twilio.init(
           System.getenv("ACCOUNT_SID"),
           System.getenv("AUTH_TOKEN"));

       com.twilio.rest.lookups.v1.PhoneNumber fetcher =
           com.twilio.rest.lookups.v1.PhoneNumber
           .fetcher(new PhoneNumber("+19892008374"))
           .setAddOns("nomorobo_spamscore")
           .fetch();

       System.out.println(fetcher.getAddOns());
   } 
}

To avoid hard-coding your Twilio account credentials, this code looks them up in a couple of environment variables. You can find the values you need on https://www.twilio.com/console:

Screenshot showing location of ACCOUNT SID and AUTH TOKEN on the Twilio console

To make these available to your code you will need to set the ACCOUNT_SID and AUTH_TOKEN environment variables. I do this using the IntelliJ EnvFile plugin, you can also set them in Eclipse or system-wide.

If you run this code you should see output like this:

{
  status=successful, 
  message=null, 
  code=null, 
  results={
    nomorobo_spamscore={
      status=successful, 
      request_sid=XR47ed08bb9e823fcd7ee35466190c5838,
      message=null,
      code=null,
      result={
        status=success,
        message=success,
        score=1
      }
    }
  }
}

The output will all be on one line - I have reformatted it for clarity here. If you get a response that says AddOn not found double check you have installed the Nomorobo AddOn in the Console.

The key section is score=1.  This means that Nomorobo has detected that this number is most likely a robocaller.

Making your Code Reusable

The possible values for score are 1 (likely a robocall) and 0 (likely not).  You can write your code to be more reusable by creating a method which checks that and returns a boolean.

In order to do that we need to recognize that add-ons are able to put small amounts of data in Twilio’s API responses, and that the exact format of that JSON can be different for each add-on.  This makes it difficult to provide Java types in the Helper library which represent the data that the add-on has provided.  So, we will use the lower-level TwilioRestClient API to be able to access the JSON response directly, and then use JsonPath to read the value out of the JSON.

First, add the JsonPath dependency to pom.xml. The XML you need is this:

<dependency>
    <groupId>com.jayway.jsonpath</groupId>
    <artifactId>json-path</artifactId>
    <version>2.4.0</version>
</dependency>

Then, change your source code to look like this:

import com.jayway.jsonpath.JsonPath;
import com.twilio.Twilio;
import com.twilio.http.*;

import java.io.IOException;

public class LookupNomorobo {

   public static void main(String[] args) throws IOException {
       Twilio.init(
           System.getenv("ACCOUNT_SID"),
           System.getenv("AUTH_TOKEN"));


       System.out.println(isRobocall("+19892008374"));
   }

   public static boolean isRobocall(String number) throws IOException {

       TwilioRestClient restClient = Twilio.getRestClient();

       Request request = new Request(
           HttpMethod.GET,
           "lookups",
           "/v1/PhoneNumbers/" + number + "",
           restClient.getRegion()
       );
       request.addQueryParam("AddOns", "nomorobo_spamscore");

       Response response = restClient.request(request);

       int spamScore = JsonPath.read(response.getStream(),
                        "$.add_ons.results.nomorobo_spamscore.result.score");
       return spamScore == 1;
   }
}

The highlighted code uses JsonPath to retrieve the score which is deeply nested in the JSON response.

If you run this code you should see true as the output, and 🎉Ta da! Now we have a handy method we can use to identify robocalls.

What's next for using Lookup?

Maybe you want to filter calls in your call center or identify the line type (mobile vs. landline) of a phone number. With Lookup you can also prompt customers to add SMS (or voice!) based 2FA, clean up your database, or segment your users.

Have you built something that takes advantage of Twilio Lookup? Let me know in the comments or on Twitter @MaximumGilliard.