Yext has recently become the sole provider of Yahoo free basic listings. This transition involves verifying Yahoo listings for certain customers. One verification option is that customers choose to receive a phone call from Yext which contains a verification code. In order to accomplish this time-sensitive project, we built an outbound phone call system within one week using the Twilio API and the Play framework.

Play is an open source web application framework that is widely used at Yext, and Twilio REST API makes life easier to build a phone application. This blog illustrates how we combined them to build up the system.

The Call Flow

A database table has been created in order to track the calls history. The responsibilities of the Play server are to process the requests from Twilio API, send back the TwiML responses, and update the database. Twilio API acts like a middle layer between users and the server to create the phone calls and gather user inputs (e.g. a user presses a key). The overall call flow is shown below.

Phone Call Flow

Call initialization

After a user selects the option to receive a phone call from Yext to get the verification code, it triggers Twilio API to initialize a call.

/**
  * Makes an outbound call to the provided customer phone number.
  *
  * @param toPhoneNumber The customer's phone number to call
  * @param phoneCallUrl the URL to which Twilio makes an HTTP request to get
  *                     the TwiML response when the call connects
  *
  * @return The call's Twilio Sid
  */
public static String makeOutboundCall(String toPhoneNumber, String phoneCallUrl)
throws TwilioRestException {
    // Initializes Twilio client
    TwilioRestClient client = new TwilioRestClient(ACCOUNT_SID, AUTH_TOKEN);
    CallFactory callFactory = client.getAccount().getCallFactory();

    // Sets the request parameters
    Map<String, String> callParams = new HashMap<String, String>();
    callParams.put("To", toPhoneNumber);
    callParams.put("Url", phoneCallUrl);
    // ...

    // Makes the call
    Call call = callFactory.create(callParams);
    return call.getSid();
}

Once the call connects, Twilio sends an HTTP request to the provided phoneCallUrl which hits the following Play endpoint.

public static void initialRequestHandler() throws TwiMLException {
    TwiMLResponse twiml = YahooHelper.generateTwiMLResponse();
    renderXml(twiml.toXML());
}

A sample TwiML response the above endpoint sends back:

<?xml version="1.0" encoding="UTF-8"?>
<Response>
    <Gather>
        <Play>instruction...</Play>
        ...
        <Play>instruction...</Play>
    </Gather>
    <Play>GoodBye instruction</Play>
    <Hangup></Hangup>
</Response>

User Input

The following Play endpoint generates the TwiML response for the request that Twilio API would fire when the user presses a key on the phone.

public static void userInputHandler() throws TwiMLException {
    String digit = params.get("Digits");
	
    // Generates the TwiML response based on the user input
    TwiMLResponse twiml = new TwiMLResponse();
    // ...
	
    renderXml(twiml.toXML());
}

After the call

The following Play endpoint handles the request that twilio API would send after the call ends and updates the call history table in the database.

public static void endCallHandler() throws SQLException {
    String statusParam = params.get("CallStatus");
    // Updates DB based on the call status, e.g. completed, no answer...
    // ...
}

Future Work

Currently this phone system only supports the outbound call feature. However, given this infrastructure, it would be flexible and easy to add and implement other features like receiving inbound calls from customers.