0% found this document useful (0 votes)
214 views

Briteverify Developers Guide

The document provides technical documentation and examples for using the BriteVerify platform for real-time verification of consumer information such as name, email, address, and phone number. It describes the different verification services, authorization methods, and ways to integrate BriteVerify including using jQuery plugins or the RESTful web services API.

Uploaded by

svetlata
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
214 views

Briteverify Developers Guide

The document provides technical documentation and examples for using the BriteVerify platform for real-time verification of consumer information such as name, email, address, and phone number. It describes the different verification services, authorization methods, and ways to integrate BriteVerify including using jQuery plugins or the RESTful web services API.

Uploaded by

svetlata
Copyright
© © All Rights Reserved
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 19

BRITEVERIFY

Developer Guide

Subject: BriteVerify Developer Guide


Author: James McLachlan
Creation Date: November 13, 2009
Revision Number: 0.6 beta
Sensitivity: Draft

This document provides technical documentation and examples of


the BriteVerify Platform. It is intended for developers and the
technically minded. A basic grasp on JavaScript, jQuery, HMTL
and modern Web programming languages is strongly suggested.

Draft
Table of Contents
Developing with BriteVerify ...................................................................................................................... 1  
Overview ................................................................................................................................................. 1  
Types Verification................................................................................................................................ 2  
BriteVerify Authorization & Authentication ....................................................................................... 3  
How to BriteVerify.................................................................................................................................. 4  
BriteForm Plugin.................................................................................................................................. 4  
BriteVerify jQuery Functions............................................................................................................... 7  
BriteVerify Web Services API ............................................................................................................. 9  
BriverVerify API ................................................................................................................................... 10  
Name .................................................................................................................................................. 10  
Email .................................................................................................................................................. 11  
Address............................................................................................................................................... 12  
Phone.................................................................................................................................................. 13  
IP Address (Coming Soon) ................................................................................................................ 14  
More Web Service Examples ................................................................................................................ 15  

Modified: 6/10/10 1:34 PM i Draft


© 2009 Origin Ads Group
Developing with BriteVerify Overview

DEVELOPING WITH BRITEVERIFY

Overview

BriteVerify is a suite of RESTful Web Services and jQuery plug-ins for the real-time verification

of consumer information. The data elements available for verification are:

 Name
 Email
 Postal Address
 Phone
 IP Address

Modified: 6/10/10 1:34 PM 1 Draft


© 2009 Origin Ads Group
Developing with BriteVerify Overview

The jQuery plug-ins are designed to be used inside the browser and require no backend server

integration. Simply cut and past a code snippet into the body of any HTML page with a form and

you are ready to BriteVerify. For developers who wish to integrate on the backend, BriteVerify

RESTful Web Services can be consumed with nothing more than an HTTP client and an XML or

JSON parser in almost any language or platform (.NET, Perl, PHP, Ruby, Java...).

Types Verification
Name
The name verification service applies profanity filters to the name then attempts to identify

gender.

Email
The email service provides 3 escalating steps to ensure that a consumer’s email is correct and

deliverable.

1. Basic syntax and format validation


2. Domain and MX Record checks (to ensure the domain is real, active, and capable of receiving email)
3. Account Verification (ensures that the given account is active on the domain)

In the third step, account verification, BriteVerify opens an SMTP conversation with the email

server and attempts to validate that the account is active and capable or receiving email. The service

can verify email account on nearly every major provider.

Postal Address
The default behavior of the Postal Address verification is to ensure not only that the address is

fully coded but also that it is USPS Delivery Point Verified, or DPV. This means that the address is

not simple correct but that it is capable of receiving mail from the US Postal Service.

Modified: 6/10/10 1:34 PM 2 Draft


© 2009 Origin Ads Group
Developing with BriteVerify Overview

Phone
By default, the standard phone service applies a simple area code + prefix check against a

database of known area code and prefix matches. Premium phone verification ensures that the

phone number is a dialable number and is capable of filtering based on phone type (mobile, landline,

digital, directory assistance, toll free, etc.).

NOTE: We can only ensure that a number is dialable, not that is necessarily connected and

working. Dialable means that the North American Numbering Plan (NNAP) has assigned

the number to a service provider. This does not mean that the number is not out of

service. There is no way to ensure that a number has not been disconnected other than

physically calling that number.

BriteVerify Authorization & Authentication


There are two methods of authorization for BriteVerify that depend on the type of client

employed. The jQuery plug-ins use domain-based authorization, while the standard Web Service

clients use traditional basic HTTP authentication. Both of these methods are available over HTTPS.

Domain-Based Authorization
Since the jQuery-based calls execute directly in the browser traditional basic HTTP

authentication is not an option as the username and password are easily exposed. To get around this

issue BriteVerify references each request against a user supplied list of authorized domains. If the

request comes from a domain not on the list, BriteVerify responds with an error and does nothing.

During testing a certain number of test transactions can come from unauthorized domains before

BriteVerify starts rejecting requests.

Modified: 6/10/10 1:34 PM 3 Draft


© 2009 Origin Ads Group
Developing with BriteVerify How to BriteVerify

Basic HTTP Authentication


Basic HTTP Authentication is the standard authentication mechanism for RESTful Web

Services. Once your account is active, each request from your servers must include your username

and password as exemplified below:

https://myusername:[email protected]/emails.xml

How to BriteVerify

There are three different ways to get up and running with BriteVerify :

1. BriteForm jQuery Plugin


2. BriteVerify JQuery Functions
3. Web Service integration

BriteForm Plugin
The BriteForm Plugin automatically binds visual verification functions to any field on the page

that it recognizes as being verifiable. This is the simplest method since all that is required to verify

any form on a given web page in the inclusion of the required scripts and stylesheets. Then once a

user completes a BriteVerified field such as email a "verifying message" will display. If the email is

invalid an error message replace the "verifying message". Otherwise, the message will disappear.

Integrating using the BriteForm Plugin is as simple as cut and past. Just log in to your

BriteVerify account, click "Get Code" and cut and past HTML code snippet just about the close

body tag (</body>) of the page with a form or forms you wish to validate.

Example HTML Page with BriteForm Plugin

<!-- Begin BriteVerify Code -->


<script type="text/javascript"
src="https://api.briteverify.com/users/james/api.js?version=01"></script>
<script type="text/javascript">

Modified: 6/10/10 1:34 PM 4 Draft


© 2009 Origin Ads Group
Developing with BriteVerify How to BriteVerify

function bvInit(){
// This code binds to every form on the page.
// In production it is advised that you explicitly bind
// to only those forms that you wish to verify.
//
// ala: jQuery("#myFormId").briteForm();
//

jQuery("form").each(function(i){

// The briteForm plugin accepts an options JSON object.


// Two events are currently supported, "submit" and "change".
// If no event option is passed "change" is the detault.
// You can also pass the name of a function to execute
// before the briteVerify runs. This function must return
// true for briteVerify to run. If it returns false, execution halts
// var bf = jQuery("#new_address").briteForm({ event : "submit", onBeforeSubmit :
myFunc,
// errorMessage : errMsg });
//
// One can pass in custom error messages to override the default
// simply add the errorMessages option to the form, {errorMessages : errMsgs}.
// var errMsgs = {address : "My Address Error", email : "My Email Error",
// phone : "My Phone Error"};
//

var bf = jQuery(this).briteForm();

// The findFields() function attempts to find which feilds to verify


// by the id or name of the input. If the field has "email",
// for example, anywhere in the body of the id or name (id='myEmailAddress'),
// it will bind to it. This is simple a utility to get started and
// it is better to explicitly specify which fields should
// have which verifications as shown below.

bf.findFields();

// explicit binding

// For address, a css selector for street and zip are required.

Modified: 6/10/10 1:34 PM 5 Draft


© 2009 Origin Ads Group
Developing with BriteVerify How to BriteVerify

// However, to get the full benefits, one should also pass at


// suite, state, and city.

// bf.addAddressFields("#streetId", "#suiteId", "#cityId", "#stateId", "#zipId" );

// bf.addEmailField("#email_address1", { event: "submit"})

// bf.addPhoneField("#phone_number1", { required : false });

// muti-field phone numbers:

// bf.addPhoneFields("#phone_number2_areacode", "#phone_number2_prefix",
// "#phone_number2_suffix");

// The null value we are passing with the name is a the gender input/select. If a
// css selector is passed for gender, the service will attempt to populate it with
// either "M" or "F". So in the case of a select it will
// auto select the gender based on the name.

// bf.addNameFields("#name_first_name", "#name_last_name", null, {event :


"change"});

// For an example of all this in action go to http://www.briteverify.com/demo4.html

});

}
</script>
<!-- End BriteVerify Code -->

And that's it! BriteVerify will now start verifying your form.

A Note about Names

In order for BriteVerify to magically verify your forms, you do need to make sure that either the

name or id attribute of fields include BriteVerify keywords, such as email, phone, street, city, state,

zip, etc. So in the example above, BriteVerify is able to validate the email field because it has the

Modified: 6/10/10 1:34 PM 6 Draft


© 2009 Origin Ads Group
Developing with BriteVerify How to BriteVerify

word "email" somewhere in the id and or name attributes. As a best practice, use the id attribute to

identify which fields should be verified.

<input id="YourEmailAddress" name="emailAddress" type="text"/>

BriteVerify jQuery Functions


The BriteVerify jQuery functions are the core foundation on which the BriteForm Plugin rests.

Using it, JavaScript developers access programmatically any of the BriteVerifiy services. The

functions follow a similar pattern to traditional jQuery AJAX calls in that an optional callback

function may be passed to that will execute when the call completes. All BriteVerify functions are

contained within the briteVerify namespace to avoid potential naming conflicts.

All the BriteVerify functions follow a similar pattern for their method signature: value, callback.

The first parameter is the value to be verified, either a simple string for functions such as email, or

an object, as with address. The second parameter it the callback function to be executed when the

verification is completed. This function will always have the resulting object passed into it. This is

illustrated in the following code example:

jQuery.briteVerify.email(“[email protected]”, function(email){
alert(email.address); // [email protected]
}

Handling Errors

Errors Array
If the value cannot be verified, the response object will contain an array of errors. The errors

array is an array of arrays. Each individual error is an array where the first value is the name of the

attribute on which the error occurred and the second is the error message itself. Almost always there

is only one error per field. So checking for additional errors is usually pointless. However, it can be

valuable to know to which part of the value the error applies. For example, with the email response

object contains the address, domain, and account attributes and the error will apply to one of those.

Modified: 6/10/10 1:34 PM 7 Draft


© 2009 Origin Ads Group
Developing with BriteVerify How to BriteVerify

jQuery.briteVerify.email(“[email protected]”, function(email){
// first check to see if there are any errors
if(email.errors){
// get the first error in the array
var error = email.errors[0];
var attr = error[0];
var msg = error[1];
// so a different error message base on the attr
if(attr == “address”){
alert(“incorrect email syntax”);
}else if(attr == “account”){
alert(“the account was not found on the domain”);
}else if(attr == “domain”){
alert(“the is not valid”);
}

}
}

Errors JSON Object


In addition to the basic errors array, there is also an errors_json object that is essential a utility

object for the errors array. It makes coding a little easier and cleaner.

jQuery.briteVerify.email(“[email protected]”, function(email){
// first check to see if there are any errors
if(email.errors_json){
// so a different error message base on the attr
if(email.errors_json.address){
alert(“incorrect email syntax”);
}else if(email.errors_json.account){
alert(“the account was not found on the domain”);
}else if(email.errors_json.domain){
alert(“the is not valid”);
}
}
}

User Account Errors


Should your account surpass its daily test transaction limit for unauthorized domains, or if your

account balance reaches 0, an error will be returned on the “user” attribute. It is a best practice to

ignore these messages, but they can be helpful for testing purposes. A notification will be sent out

prior to any user account hitting a zero balance, or if auto-billing is enabled a billing notification will

be sent.

jQuery.briteVerify.email(“[email protected]”, function(email){
// first check to see if there are any errors
if(email.errors_json){
// so a different error message base on the attr
if(email.errors_json.user){
alert(“user account: ” + email.errors_json.user); //”overbalance”

Modified: 6/10/10 1:34 PM 8 Draft


© 2009 Origin Ads Group
Developing with BriteVerify How to BriteVerify

}
}
}

BriteVerify Web Services API


The BriteVerify Web Services API is implemented as plain XML over the HTTP POST method.

Every resource, like Name, Email, Address, Phone, and IPAddress, has its own URL in accordance

with the principles of a RESTful Web Service.

Although the best practice is to use POST to verify a given resource, a GET method is available.

However, you must pass your secret API key in the parameter list as this very method does not

require HTTP authentication. Your secret API key can be found by logging into your BriteVerify

Acount. Using the verify GET URL you can explore the resulting xml of various calls. It does

follow the Rails field naming convention, which is “object[attribute],” as illustrated in the examples

below.

Verify GET Example


https://api.briteverify.com/emails/verify.xml?email[address][email protected]&a
pikey=8971398-3e72-2343-ghsjdfg-8879987fds

Standard Post Example using curl


curl -u jdoe:password -H 'Content-Type: application/xml' -d
'<email><address>[email protected]</address></email>'
https://api.briteverify.com/emails.xml

Result
Both calls should respond with an HTTP status code of “201 Created” and the following xml

response document.

<?xml version="1.0" encoding="UTF-8"?>


<email>
<address>[email protected]</address>
<domain>briteverify.com</domain>
<account>jdoe</account>
</email>

Modified: 6/10/10 1:34 PM 9 Draft


© 2009 Origin Ads Group
Developing with BriteVerify BriverVerify API

BriverVerify API

Name
jQuery.briteVerify.name(name, callbackFunction)

Accepts the full name of a consumer and a callback function. A name object is passed into the

callback function with the results of the call.

name.first_name;
name.middle;
name.last_name;
name.prefix;
name.suffix;
name.gender;
name.errors; // an errors array with all errors returned by the service
name.errors_json; // an errors JSON object with all errors returned by the service

Example

jQuery("#myNameFieldId").change(function(){
// in this example there is just one name field into which the user types there
full name
// the callback function should have the name object passed back into it.
jQuery.briteVerify.name(this.value, function(name){
if(name.errors){
alert("Your name is not valid. Please correct");
}else{
var fullname = name.first_name + " " + name.middle + " " + name.last_name;
alert(fullname + " is a valid name");
}
});
});

Name Web Service

POST https://api.briteverify.com/names.xml
curl -u jdoe:password -H 'Content-Type: application/xml' -d '<name><fullname>James
McLachlan</fullname></name>' http://api.briteverify.com/names.xml

Response
Status: 201 Created
<?xml version="1.0" encoding="UTF-8"?>
<name>
<first-name>James</first-name>
<fullname>James McLachlan</fullname>
<gender>male</gender>
<last-name>McLachlan</last-name>
<middle-name> </middle-name>
</name>

Modified: 6/10/10 1:34 PM 10 Draft


© 2009 Origin Ads Group
Developing with BriteVerify BriverVerify API

GET Example
http://api.briteverify.com/names/verify.xml?name[fullname]=james+mclachlan&apikey=8
971398-3e72-2343-ghsjdfg-8879987fds

Parameters
 name[fullname]
 name[first_name]
 name[last_name]
 name[middle_name]

Email
jQuery.briteVerify.email(email, callbackFunction)

Accepts an email string and a callback function. An email object is passed into the callback

function, which is returned when processing is complete:

email.address; // [email protected]
email.domain; // nodo.com
email.account; // jdoe
email.errors; // [[“domain”, “does not exist”]]
email.errors_json; // {account : “not found on nodo.com”}

Example

jQuery("#myEmailFieldId").change(function(){
jQuery.briteVerify.email(this.value, function(email){
if(email.errors){
if(email.errors_json.domain){
alert("Your email domain " + email.errors_json.domain);
}else if(email.errors_json.address){
alert("Your email " + email.errors_json.address);
}else if(email.errors_json.account){
alert("Your account " + email.errors_json.account);
}
}
});
});

Email Web Service

POST https://api.briteverify.com/emails.xml
curl -u jdoe:password -H 'Content-Type: application/xml' -d
'<email><address>[email protected]</address></email>'
http://api.briteverify.com/emails.xml

Response
Status: 201 Created

Modified: 6/10/10 1:34 PM 11 Draft


© 2009 Origin Ads Group
Developing with BriteVerify BriverVerify API

<?xml version="1.0" encoding="UTF-8"?>


<email>
<address>[email protected]</address>
<domain>briteverify.com</domain>
<account>jdoe</account>
</email>

GET Example
http://api.briteverify.com/emails/verify.xml?email[address][email protected]&ap
ikey=8971398-3e72-2343-ghsjdfg-8879987fds

Parameters
 email[address]

Address
jQuery.briteVerify.address(address, callbackFunction)

Accepts an address JSON object and a callback function. An address object is passed into the

callback function, which is returned when processing is complete:

address.street;
address.unit;
address.city;
address.state;
address.zip;
address.plus4;
address.address_type;
address.errors;
address.errors_json

Example

jQuery("#myZipFieldId").change(function(){
// check first to see if the street field has something in it
var streetVal = jQuery("#myStreetFieldId").val();
if(streetVal){
var myAddress = { street : streetVal, unit : jQuery("#myUnitFieldId").val(),
city : jQuery("#myCityFieldId").val(), state : jQuery("#myStateFieldId").val(), zip
: jQuery("#myZipFieldId").val() }
};
jQuery.briteVerify.address(myAddress, function(address){
if(address.errors){
alert("Address not found.");
}
});
});

Modified: 6/10/10 1:34 PM 12 Draft


© 2009 Origin Ads Group
Developing with BriteVerify BriverVerify API

Address Web Service

POST https://api.briteverify.com/addresses.xml
curl -u jdoe:password -H 'Content-Type: application/xml' -d '<address><street>120 N
cedar</street><zip>28210</zip></address>' https://api.briteverify.com/addresses.xml

Response
Status: 201 Created
<?xml version="1.0" encoding="UTF-8"?>
<address>
<address-type>Highrise</address-type>
<city>Charlotte</city>
<county>Mecklenburg</county>
<plus4>1292</plus4>
<state>NC</state>
<street>120 N Cedar St </street>
<unit nil="true"></unit>
<zip>28202</zip>
</address>

GET Example
http://api.briteverify.com/addresses/verify.xml?address[street]=120+nowhere&address
[zip]=28202&apikey=8971398-3e72-2343-ghsjdfg-8879987fds

Parameters
 address[street]
 address[unit]
 address[city]
 address[state]
 address[zip]

Phone
jQuery.briteVerify.phone(phone, callbackFunction, options)

Accepts a phone string and a callback function. A phone object should be passed into the

callback function to hold the result returned when processing is complete. Options are optional and

there is currently only a premium flag is supported. If the premium option is passed as true, then the

service will execute using the premium phone verification service.

phone.number; // 7041231234
phone.areacode; // 704
phone.prefix; // 123
phone.suffix; // 1234
phone.city; // Charlotte
phone.county; // Mecklenburg

Modified: 6/10/10 1:34 PM 13 Draft


© 2009 Origin Ads Group
Developing with BriteVerify BriverVerify API

phone.country; // US
phone.errors; // { number : "is not valid" }

Example Default Verification

jQuery("#myPhoneFieldId").change(function(){
jQuery.briteVerify.phone(this.value, function(phone){
if(phone.errors){
alert("phone is not valid");
}
});
});

Phone Web Service

POST https://api.briteverify.com/phones.xml
curl -u jdoe:password -H 'Content-Type: application/xml' -d '<phone><number>704 525
5526</number></phone>' https://api.briteverify.com/phones.xml

Response
Status: 201 Created
<?xml version="1.0" encoding="UTF-8"?>
<phone>
<areacode>704</areacode>
<city>Charlotte</city>
<ext nil="true"></ext>
<number>704 525 5526</number>
<prefix>525</prefix>
<service-type>unknown</service-type>
<suffix>5526</suffix>
</phone>

GET Examples
http://api.briteverify.com/phones/verify.xml?phone[number]=7041231234&apikey=897139
8-3e72-2343-ghsjdfg-8879987fds

Parameters
 phone[number]
 phone[premium] (true or false)

IP Address (Coming Soon)


jQuery.briteVerify.locateIP(callbackFunction)

Returns an IP object with all the location information based.

ip.address; // 96.10.172.152
ip.longitude;
ip.latitude;
ip.zip;

Modified: 6/10/10 1:34 PM 14 Draft


© 2009 Origin Ads Group
Developing with BriteVerify More Web Service Examples

ip.region;
ip.city;
ip.country;
ip.isp;

Example

// This example just does an ip look up when the page loads.


// It simply grabs the ip from the browser request.

jQuery(document).load(function(){
jQuery.briteVerify.locateIP(function(ip){
alert(ip.city);
});
});

IP Address Web Service (Coming Soon)

More Web Service Examples

BriteVerify provides a RESTful Web Service API for backend server integration. Any language

that supports XML or JSON and HTTP can consume these services. The examples below illustrate a

very basic integration of the email service using the Ruby programming language.

The lifecycle of the web service is as follows:

4. Make a simple HTTP POST passing the email


5. Parse the XML response and respond appropriately.

We will be using the NET/HTTP libraries that are part of the core Ruby language. It is

documented at http://ruby-doc.org/stdlib/libdoc/net/http/rdoc/index.html.The xml parser we are

using is REXML and is documented at http://www.germane-software.com/software/rexml/.

Example

require 'net/http' # HTTP Library


require 'uri' # URL parser
require 'rexml/document' # XML parser

# First parse the url


url = URI.parse('https://api.briteverify.com/emails.xml')

# Create the HTTP request object


req = Net::HTTP::Post.new(url.path)

Modified: 6/10/10 1:34 PM 15 Draft


© 2009 Origin Ads Group
Developing with BriteVerify More Web Service Examples

# set the request to use SSL


req.use_ssl = true

# Set the user and password (obviously use your own)


req.basic_auth 'jdoe', 'password'

# Add the email address to the form


req.set_form_data({'email[address]'=>'[email protected]' }, ';')

# POST it to BriteVerify
res = Net::HTTP.new(url.host, url.port).start {|http| http.request(req) }

# Check the type of response


case res

# When success (401) then the email is valid


when Net::HTTPSuccess
# This means that the email is valid. The xml will simply an xml record
representing the email
# <?xml version="1.0" encoding="UTF-8"?>
# <email>
# <address>[email protected]</address>
# <domain>briteverify.com</domain>
# <account>jdoe</account>
% </email>

# Here we are using the REXML parser to parse the document


doc = REXML::Document.new res.body

# A simple XPATH statement to grab the email address


address = REXML::XPath.first(doc,"//email/address").text
# Output the email
p address # [email protected]

# When there is a client error and the code is 422 then the email is invalid
when Net::HTTPClientError
if res.code == "422"
# This means that the email is invalid. The xml response will be a list of
errors
# <errors>
# <error>Account jdoe not found at briteverify.com</error>
# </errors>

# Here we are using the REXML parser to parse the document


doc = REXML::Document.new res.body

# A simple XPATH statement to grab the first error text


error = REXML::XPath.first(doc,"//errors/error").text
# Output the error message
p error # Account jdoe not found at briteverify.com
else
res.error!
end
else
res.error!
end

Modified: 6/10/10 1:34 PM 16 Draft


© 2009 Origin Ads Group
Developing with BriteVerify More Web Service Examples

BriteVerify on Rails

Our Web Services work perfectly with ActiveResource, the Web Service client for Ruby on

Rails. The integration in this case is extremely simple, but it should prove equally simple for any

REST Web Service client in Java, PHP, or .NET.

Example

# A simple ActiveResource client


class Email < ActiveResource::Base
self.site = "http://jdoe:[email protected]/"
end

# Now some quick commands to test it out


# Here we pass a known invalid account
email = Email.new(:address => "[email protected]")
email.valid? # should return false
p email.errors.on(:account) # Account jdoe not found at briteverify.com

# Here we try a bad domain


email = Email.new(:address => "[email protected]")
email.valid? # false
p email.errors.on(:domain) # briteverify2323.com is invalid

Modified: 6/10/10 1:34 PM 17 Draft


© 2009 Origin Ads Group

You might also like