API Days Mediterranea Hackathon

The day before APIdays Mediterranea a Hackatón took place, with the intention of encouraging the use and distribution of web APIs. There were various categories and here we will show two: development and use of Twilio APIs.

20 minutes to create an API

During the afternoon of the Hackathon we had to get our act together in order to come up with something useful and of value that we could build using the Twilio API and that could be offered, once complete, as an API. We didn’t know Twilio and had to spend part of the afternoon reading the documentation and carrying out tests with their API. So we decided to make a simple API that enabled customers to check the authenticity of a phone number, just as there are usually verification systems for email addresses. We called it Veriphone before realising that the name was already registered.

The value of Veriphone

The API that we wanted to develop had two complimentary value proposals. On one hand, you have to be able to eliminate spammers in the user registration for a website like you do with captcha, that is to say, interacting with a user over the phone in order to eliminate dealing with a bot. On the other hand, you have to be able to guarantee certain actions in an application or a web site asking the user for information that only they could know, and across a device that only they would have.

A good security system is based on three foundations: who you are, what you know and what you possess; Veriphone should use two of these. What the user knows, a temporary key that can communicate by telephone. What the user possesses, the telephone that acts like a key. Next, we’ll show you how we do it.

How does it work?

1. The API consumer requests the verification of an operation that a user is carrying out.

a. The API is sent the telephone number of the user.

b. As a response it sends the user a random PIN code so that it is show to the user.

2. Next it carries out a phone call to the user in question and it asks them to enter the PIN that they were shown before.

3. The user enters the PIN on the keypad on their phone.

4. Once the user enters the PIN on their phone it invokes a callback URL on the consumer of the API in order to inform them of the result of the verification.

Architecture

arquitectura

Design

Entity Model

Diseño

  • Account

Each Account corresponds with an API client (consumer). It is composed of:

    • A name
    • A domain from which they will make calls to the API
    • It will assign an API Key to each user which will serve to identify them
    • Each consumer will have a list of phone numbers of which they can request verifications
publicclassAccount{
privateStringname;
privateStringdomain;
privateStringapiKey;
privateList<Phone>phones;
}
  • Phone

Phone number associated with an API client of which you can request verifications. It is made up of:

    • A phone number
    • A list of verifications that have been carried out upon the phone.
publicclassPhone{
privateStringnumber;
privateAccountaccount;
privateList<Verification>verifications;
}
  • Verification

Verification associated with a phone number. It is made up of:

    • A status, which can take the values: PENDING, FAILED or VERIFIED
    • A verification request date, which enables you to check if the verification has been done within a certain time period
    • A random PIN code
    • A phone number of which verification can be done
    • A callback URL for the API client which they invoke to communicate the result of the verification
    • The identifier of the Twilio call that has been carried out for the verification
publicclassVerification{
privateLongid;
privateVerificationStatusstatus;
privateStringcode;
privateDaterequestDate;
privateStringcallSid;
privateStringcallbackUrl;
privatePhonephone;
}
  • Comments on the entity design 

The callback URL is established at the Verification stage and not at the Account stage in order to allow the same web application to have various verification points with different callback URLs.

Endpoints

  • Register the API client

post account

It enables an API client to register and to obtain an API Key so as to be able to carry out the calls themselves.

@RequestMapping(value="/accounts",method=RequestMethod.POST,
consumes=MediaType.APPLICATION_JSON_VALUE,produces=MediaType.APPLICATION_JSON_VALUE)
publicResponseEntity<String>createCustomer(@RequestBodyAccountaccount)throws
JsonGenerationException,JsonMappingException,IOException{
AccountcreatedAccount=customerService.createAccount(account);
SimpleFilterProviderfilters=newSimpleFilterProvider();
filters.addFilter("accountFilter",SimpleBeanPropertyFilter.serializeAllExcept("id","phones"));
Stringjson=objectMapper.writer(filters).writeValueAsString(createdAccount);
returnnewResponseEntity<String>(json,HttpStatus.CREATED);}
  • Link a phone number to a client

post phonesIt enables an API client to be linked with a phone number that they want to verify. The relationship between Phoney Account is done through the API Key received at the head of the HTTP Authorization.

@RequestMapping(value="/phones",method=RequestMethod.POST,consumes=MediaType.APPLICATION_JSON_VALUE,
produces=MediaType.APPLICATION_JSON_VALUE)
publicResponseEntity<String>createPhone(@RequestBodyPhonephone,@RequestHeader("Authorization")
Stringauthorization)throwsJsonGenerationException,JsonMappingException,IOException,
AccountNotFoundException{
PhonecreatedPhone=phoneService.createPhone(AuthorizationHeaderParser.getApiKey(authorization),
phone);
SimpleFilterProviderfilters=newSimpleFilterProvider();
filters.addFilter("phoneFilter",SimpleBeanPropertyFilter.serializeAllExcept("account",
"verifications"));Stringjson=objectMapper.writer(filters).writeValueAsString(createdPhone);
returnnewResponseEntity<String>(json,HttpStatus.CREATED);
}
  • Create a phone verification

verificationIt allows the creation of a verification for a phone number. It returns the verification in the status of PENDING with a random PIN code that it will show the user. It will also carry out the call to the user in order to request the PIN.

@RequestMapping(method=RequestMethod.POST,value="/phones/{phoneNumber}/verifications",
consumes=MediaType.APPLICATION_JSON_VALUE,produces=MediaType.APPLICATION_JSON_VALUE)
publicResponseEntity<String>createVerification(@PathVariable("phoneNumber")StringphoneNumber,
@RequestBodyVerificationverification,@RequestHeader("Authorization")Stringauthorization)throws
TwilioRestException,JsonGenerationException,JsonMappingException,IOException,
AccountNotFoundException{
VerificationcreatedVerification=
verificationService.createVerification(AuthorizationHeaderParser.getApiKey(authorization),phoneNumber,
verification);
SimpleFilterProviderfilters=newSimpleFilterProvider();
filters.addFilter("verificationFilter",SimpleBeanPropertyFilter.serializeAllExcept("id","phone"));
Stringjson=objectMapper.writer(filters).writeValueAsString(createdVerification);
returnnewResponseEntity<String>(json,HttpStatus.CREATED);
}
  • Test the status of a verification

callsid

It enables the consultation of the status of a verification

@RequestMapping(method=RequestMethod.GET,value="/verifications/{callSid}",
produces=MediaType.APPLICATION_XML_VALUE)
publicResponseEntity<String>getVerification(@PathVariable("callSid")StringcallSid,
@RequestHeader("Authorization")Stringauthorization)throwsJsonGenerationException,
JsonMappingException,IOException,AccountNotFoundException,VerificationNotFoundException{
Verificationverification=
verificationService.getVerification(AuthorizationHeaderParser.getApiKey(authorization),callSid);SimpleFilterProviderfilters=newSimpleFilterProvider();
filters.addFilter("verificationFilter",SimpleBeanPropertyFilter.serializeAllExcept("id","phone"));
Stringjson=objectMapper.writer(filters).writeValueAsString(verification);
returnnewResponseEntity<String>(json,HttpStatus.OK);
}
  • Collect the code entered on the phone

digits

This is a special endpoint that invokes Twilio to collect that code that the user has typed on the phone’s keypad, to buy it with the registered code, to update the status of the verification and to invoke the callback URL in order to communicate the result of the verification.

@RequestMapping(method=RequestMethod.GET,params={"CallSid","Digits"},
produces=MediaType.APPLICATION_XML_VALUE)
publicResponseEntity<String>checkVerification(@RequestParam("CallSid")StringcallSid,
@RequestParam("Digits")Stringdigits)throwsVerificationNotFoundException{
verificationService.checkVerification(callSid,digits);
returnnewResponseEntity<String>(twilioService.getTwilioAfterGatherMessage(),HttpStatus.OK);
}

The response of this endpoint is an xml with instructions for Twilio. An example response would be the following:

<Response>
<Sayvoice="woman">Wehavereceivedsuccessfullyyourpinnumber.</Say>
</Response>

In this case we give Twilio the phone locution message to show the user that we have received the PIN that they have entered.

  • Obtain instructions for the phone call

twiml call

This is also a special endpoint that Twilio invokes when the call is made from the phone to collect the instructions that should be followed.

@RequestMapping(method={RequestMethod.GET,RequestMethod.POST},value="/twiml-call",produces=MediaType.APPLICATION_XML_VALUE)
publicResponseEntity<String>getTwilioCallMessage(){
returnnewResponseEntity<String>(twilioService.getTwilioCallMessage(),HttpStatus.OK);
}

This is an example response:

<Response>
<Gathertimeout="20"finishOnKey="*"method="GET"
action="http://veriphone.byteflair.cloudbees.net/api/v1/verifications">
<Sayvoice="woman">Pleaseenteryourpinnumberandthenpressstar.</Say>
</Gather>
</Response>

What it tells Twilio in this response is that it has to ask the user to enter a series of numbers on their phone’s keypad, and that the ‘*’ will indicate the end. The user will have 20 seconds to enter them. They will also indicate a URL to Twilio, which will be invoked when the user enters the last character or when the 20 seconds expire:

<Gathertimeout="20"finishOnKey="*"method="GET"
 action="http://veriphone.byteflair.cloudbees.net/api/v1/verifications">

Twilio will also show the phone locution message where it will explain to the user what they have to say:

<Sayvoice="woman">Pleaseenteryourpinnumberandthenpressstar.</Say>

Seguridad

As a security mechanism, use an API Key. Every API client will have to register and specify a domain from which they will make their calls and they will be assigned a key (API Key). This key will have to be sent as an HTTP heading in all of the calls made to the API.

In each request the API will test that it is receiving the heading with the key and that the domain from which the request is coming corresponds with the key.

The API has a frontend to register as an API client and to obtain the usage key itself. This frontend will be the only one that will have access to the API client registration endpoint (POST/accounts).

Authors: Daniel Cerecedo and Diego Castro (Winners of the APIdays Mediterranea Hackathon in the Creation of an API category)
Web: http://byteflair.com/
Share →