Address Validation Integration in CPQ

This is a short article that illustrates how integrations can be done in CPQ Cloud. To keep it simple I chose to demonstrate how to integrate with an address verification service.

Register for Service

In the past I created this integration with a provider that requires you to purchase a license. For this blog, I selected a provider that offers free service, SmartyStreets, so everyone can give it a try.

To gain access to their service you need to register for a free account that allows up to 250 requests per month. That should be enough to try it out. After registration you obtain an auth-id and a auth-token which is used in the request.

To test whether the auth id and token are correct, you can use curl in the command line:

$ curl "https://us-street.api.smartystreets.com/street-address?auth-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&auth-token=xxxxxxxxxxxxxxxxxxxx&street=86+Frontage+Road&city=Belmont&state=MA&candidates=10"

If you have valid auth id and token you should get a response like this:

[
  {
    "input_index": 0,
    "candidate_index": 0,
    "delivery_line_1": "100 Hinckley Way",
    "last_line": "Belmont MA 02478-1158",
    "delivery_point_barcode": "024781158004",
    "components": {
      "primary_number": "100",
      "street_name": "Hinckley",
      "street_suffix": "Way",
      "city_name": "Belmont",
      "state_abbreviation": "MA",
      "zipcode": "02478",
      "plus4_code": "1158",
      "delivery_point": "00",
      "delivery_point_check_digit": "4"
    },
    "metadata": {
      "record_type": "S",
      "zip_type": "Standard",
      "county_fips": "25017",
      "county_name": "Middlesex",
      "carrier_route": "C002",
      "congressional_district": "05",
      "rdi": "Commercial",
      "elot_sequence": "0052",
      "elot_sort": "A",
      "latitude": 42.41062,
      "longitude": -71.18248,
      "precision": "Zip9",
      "time_zone": "Eastern",
      "utc_offset": -5,
      "dst": true
    },
    "analysis": {
      "dpv_match_code": "Y",
      "dpv_footnotes": "AABB",
      "dpv_cmra": "N",
      "dpv_vacant": "N",
      "active": "Y",
      "footnotes": "LI#N#",
      "lacslink_code": "A",
      "lacslink_indicator": "Y"
    }
  }
]

Creating Data Table

It is best practice, not just in CPQ but also in any development environment, to decouple and avoid hard coding authentication and endpoints. In some systems, connection data can be stored in property files. In CPQ it’s pretty common to have a data table as storage for integration metadata. I created “Endpoints” data table, where all integration endpoints and authentication ids and tokens are stored. This table is not only used for this sample integration but I will safe it to store data for all future integrations as well.

The method/verb column is used because some APIs offer slightly different functionality whether using Get or Post. For example, Smartystreets offers two types of address verification: single address and multiple address. Single Address requests uses the HTTP “Get” method. The single address is passed as a query string parameter. But if you need to verify a list of addresses (up to 100) in a single call, you should use the HTTP “Post” method. The list of addresses is placed in the request body, where each address in an element in a JSON array.

For simplicity, we will be using the single address request in this demonstration.

Here is a brief description of the API (HTTP/get method):

https://<hostname>/<endpoint>?<query string>
where, hostname is “http://us-street.api.smartystreets.com”,
endpoint is “street-address” and
the query string contains the authentication id, token and the address.

You have already seen this above when I called the API using curl, but I will show again for clarity. Here is what it looks like when values are populated:

"https://us-street.api.smartystreets.com/street-address?auth-id=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx&auth-token=xxxxxxxxxxxxxxxxxxxx&street=86+Frontage+Road&city=Belmont&state=MA&candidates=10"

“Candidates=10” is to put an upper limit on the number of addresses returned, in case it finds several matches.

Now that we have the details of how to call the API, let’s create a function to prepare the URL, call the REST API and return the result.

Create BML Util Library

To make the address validation reusable, I chose to implement as a Util Library function. Custom code in CPQ is written in BML, BigMachines Extensible Language, is a scripting tool is is used to capture business logic. I created a function that does these tasks:

  • parse the input (address fields)
  • fetch the authentication attributes, URL, service name and method type
  • build the query parameter
  • call the REST API
  • parse the response
  • return the validated address

The first step in the BML function is to parse the JSON string into address, city, state, etc.

Next I query the “Endpoints” table to obtain the URL, auth id, token and method type for the API call.

authenticationQuery = bmql("SELECT hostname, endpoint, auth_id, auth_token, method FROM Endpoints WHERE service = 'validateSingleAddress' AND env = 'dev'");

for row in authenticationQuery{
	hostname = get(row, "hostname");
	endpoint = get(row, "endpoint");
	method = get(row, "method");
	//add parameters to dictionary
	put(queryDict, "auth-id", get(row, "auth_id"));
	put(queryDict, "auth-token", get(row, "auth_token"));
}

Note that I used a dictionary, queryDict, to build the query parameter list and added the auth-id and auth-token to the dictionary.

Next, the remainder of the query parameters is built and finally the entire URL is assembled.

if (method == "get") {
	//add parameters to dictionary
	put(queryDict, "street", replace(street, " ", "+"));
	put(queryDict, "city", city);
	put(queryDict, "state", state);
	put(queryDict, "postalCode", postalCode);
	put(queryDict, "candidates", "10");
	
	//loop through queryDict and build remainder of URL for REST call
	urlParameters = "";
	urlParameterList = String[];
	queryKeys = keys(queryDict);
	for key in queryKeys{
		append(urlParameterList, key + "=" + get(queryDict, key));
	} 
        urlParameters = "?" + join(urlParameterList, "&");
        url = hostname + endpoint + urlParameters;

The urldata is the function that makes the REST call. If the response has a “Message-Body” it was successful. The print statements below is just for debugging purpose.

restResponse = urldata(url,method);
	
if(get(restResponse, "Message-Body") <> "" AND NOT isnull(get(restResponse, "Message-Body"))){
	ret = get(restResponse, "Message-Body");
	print ret;
}else{
	print "didn't get a response";
}

The only thing left to do now is to construct the response JSON object with the desired fields. If the requirements are simple, all you need is to assemble a JSON object with the verified address which came back in the response object.

With the REST call being abstracted in a util function, you can create a validation rule that calls the util function. This separation of concerns provides a more modular and reusable solution. I hope this has been useful to not only demonstrate how CPQ can integrate with an external system, but also show how some best practices should be used in CPQ.

Add Your Comment