Integrating Lead Validation into Zoho CRM

In this guide, we’ll illustrate how to create a custom button in a Zoho CRM module that will call our DOTS Lead Validation – International API. Lead Validation – International is a natural fit for a CRM-type solution, as it provides insight into a lead by cross-referencing data points such as name, address, email, phone number, and IP address. This service works by ensuring that all the different lead data points line up with each other and paint an accurate picture of a valid lead. A button like this in your Zoho CRM instance would help quickly and effectively assess the quality of a lead, and give your sales team an edge in figuring which leads to engage with first. This guide will highlight best practices and potential pain points to look out for when creating a custom button, and some of the logic behind it.

Here are a few things you will need in order to follow along with this integration guide.

  • Service Objects validation API key. We’re using DOTS Lead Validation International in this example, but any of our validation APIs should work well.
  • Administrator/Developer access in Zoho CRM – This is needed in order to add a custom button and the logic associated with it.
  • Working knowledge of Deluge (the scripting language used in Zoho CRM for writing custom functions).

What is Zoho CRM and why does it matter?

Zoho CRM is a powerful cloud-based CRM solution that allows its users to quickly and effectively reach their clients. Adding a Service Objects validation API to its functionality can make it even more powerful. An API like Lead Validation – International can give effective high-level information on the quality of a lead. Lead Validation – International cross-references all the given data points and helps highlight whether the given lead information lines up. For example, Lead Validation – International will score a lead better if the given phone, address, and IP address all look to come from the same physical location. This can help optimize your sales team’s efforts and allow them to target leads that will have the highest likelihood of engaging in selling activities. Previously, we’ve shown how to integrate a Service Objects API into a Zoho CRM Workflow rule, and this blog will cover some of the same ground. If you would rather call a Service Objects API with a workflow rule (i.e. on record add, edit, or save), that might be the guide for you!

How to integrate Service Objects validation APIs Into Zoho CRM

Step 1: Setting up custom fields to hold Service Objects response

One of the first steps would be to create custom fields to hold the responses from the Service Objects API you wish to call. In our case, we’ve created a separate “Lead Validation Ints” module that will hold all the results from the API. We’ll use the Lead ID to link this module to the Leads module when we run Lead Validation – International.

If you want to add custom fields to an existing module, our previous Zoho CRM Workflow Integration guide will highlight that process.

To add a custom module as we’ve done, select the settings wheel in the upper right-hand corner on the CRM home page

Then select the “Modules and Fields” option under the Customization heading.

From here you can select the “New Module” button and begin creating your module! We won’t go through all the steps of creating every single field in Lead Validation – International here, because there are quite a few of them. It may be helpful to review the documentation for the service to determine which fields it would be beneficial for you to leverage. This would be a great place to ping our support team; we can help you make the best decisions for leveraging the data and getting the most out of your Service Objects validation API.

Step 2: Creating the button

The easiest way to get set up on creating a button is to head to the “Modules and Fields” category under the Customization heading, then select the module that you want to add a button.

As mentioned above, we’re using the Leads module, so we’ll select that.

From here, we can select “Links and Buttons”

And then select the New Button option.

From here, we can begin to fill in some of our details about the button we want to create. We’ll fill in the details as follows:

Under the “What action would you like the button to perform?”, select “Writing Function” and then provide appropriate values for the Function Name, Display Name, and Description. Select Create and now we can begin writing some code in Deluge!

Step 3: Getting the inputs from the lead module

To start, we’ll need to edit the input arguments for our new function. To do this, select the “Edit Arguments” link at the top of the page.

On the resulting page, we’ll just add a single input for this function which will be the corresponding lead ID for the lead that we are sending to the Lead Validation – International web service.

Typing “#” in the rightmost box under argument mappings will allow you to pick the appropriate input that you want for the function. Select “Save” and then let’s get to setting up our input for the Lead Validation International service.

To do this, we’ll use Zoho’s API for pulling down lead information associated with a Lead ID. This can be done with the code below:

//This is the lead that we'll use to update the LeadInt object
lead = zoho.crm.getRecordById("Leads",leadID);

//Create some new strings and encode the values for URL transport
fullName = encodeURL(IfNull(lead.get("Full_Name"),""));
salutation = encodeURL(IfNull(lead.get("Salutation"),""));
firstName = encodeURL(IfNull(lead.get("First_Name"),""));
lastName = encodeURL(IfNull(lead.get("Last_Name"),""));
businessName = encodeURL(IfNull(lead.get("Company"),""));
businessDomain = encodeURL(IfNull(lead.get("Domain"),""));
businessEin = encodeURL(IfNull(lead.get("EIN"),""));
address1 = encodeURL(IfNull(lead.get("Address_1"),""));
address2 = encodeURL(IfNull(lead.get("Street_2"),""));
address3 = encodeURL(IfNull(lead.get("Street_3"),""));
address4 = encodeURL(IfNull(lead.get("Street_4"),""));
address5 = encodeURL(IfNull(lead.get("Street_5"),""));
locality = encodeURL(IfNull(lead.get("City"),""));
adminArea = encodeURL(IfNull(lead.get("State"),""));
postalCode = encodeURL(IfNull(lead.get("Zip_Code"),""));
country = encodeURL(IfNull(lead.get("Country"),""));
phone1 = encodeURL(IfNull(lead.get("Phone1"),""));
phone2 = encodeURL(IfNull(lead.get("Phone2"),""));
email = encodeURL(IfNull(lead.get("Email"),""));
ipAddress = encodeURL(IfNull(lead.get("Ip_Address"),""));
//Currently No DOB Field in Lead Module so this is blank
dateOfBirth = "";
//Currently No Gender field in Lead Module so this is blank
gender = "";
utcCaptureTime = encodeURL(IfNull(lead.get("Created_Date_Time"),""));
//Going to set these as Standard Values 
outputLanguage = "English";
testType = "business";
licenseKey = "YourKeyHere";

 

In the above code, we’ll pull down the lead object we want to access and create strings from the parameter values that we want to send to the service. We’ll also URL-encode so we can make a successful HTTP GET call to the Lead Validation International service. Within each encodeURL function, we’ll call Deluge’s handy ifNull function, which will check the value we’re pulling back from the lead for nulls. If it is null, we’ll simply use an empty string.

We’re also using the ‘business’ test type to send to the service. The test type used can dramatically affect the scoring that the Lead Validation service performs. This would be a good time to review some of the available test types in the service. If you don’t see one that seems like it would be a good fit, reach out to us! We’d be happy to make a recommendation or even create a custom test type for your needs.

Step 4: Calling the Lead Validation – International service with failover configuration

Now that we have all our inputs, we can construct the URL request and call out to the service. If you are using a trial key, your URLs should start with https://trial.serviceobjects.com… Otherwise, the primary endpoint should be pointed to https://sws.serviceobjects.com…, and the backup endpoint should begin with https://swsbackup.serviceobjects.com.

//Construct the URL
primaryURL = "https://sws.serviceobjects.com/lvi/api.svc/json/ValidateLeadInternational?FullName=" + fullName + "&Salutation=" + salutation + "&FirstName=" + firstName + "&LastName=" + lastName + "&BusinessName=" + businessName + "&BusinessDomain=" + businessDomain + "&BusinessEIN=" + businessEin + "&Address1=" + address1 + "&Address2=" + address2 + "&Address3=" + address3 + "&Address4=" + address4 + "&Address5=" + address5 + "&Locality=" + locality + "&AdminArea=" + adminArea + "&PostalCode=" + postalCode + "&Country=" + country + "&Phone1=" + phone1 + "&Phone2=" + phone2 + "&Email=" + email + "&IPAddress=" + ipAddress + "&Gender=" + gender + "&DateOfBirth=" + dateOfBirth + "&UTCCaptureTime=" + utcCaptureTime + "&OutputLanguage=" + outputLanguage + "&TestType=" + testType + "&LicenseKey=" + licenseKey;

//construct backup URL
backupURL = "https://swsbackup.serviceobjects.com/lvi/api.svc/json/ValidateLeadInternational?FullName=" + fullName + "&Salutation=" + salutation + "&FirstName=" + firstName + "&LastName=" + lastName + "&BusinessName=" + businessName + "&BusinessDomain=" + businessDomain + "&BusinessEIN=" + businessEin + "&Address1=" + address1 + "&Address2=" + address2 + "&Address3=" + address3 + "&Address4=" + address4 + "&Address5=" + address5 + "&Locality=" + locality + "&AdminArea=" + adminArea + "&PostalCode=" + postalCode + "&Country=" + country + "&Phone1=" + phone1 + "&Phone2=" + phone2 + "&Email=" + email + "&IPAddress=" + ipAddress + "&Gender=" + gender + "&DateOfBirth=" + dateOfBirth + "&UTCCaptureTime=" + utcCaptureTime + "&OutputLanguage=" + outputLanguage + "&TestType=" + testType + "&LicenseKey=" + licenseKey;


//Call LVI and perform failover check
lviResponse = getUrl(primaryURL);
if(lviResponse.isNull() || !lviResponse.getJSON("Error").isNull() && lviResponse.getJSON("Error").getJSON("TypeCode") == "3")
{
    lviResponse = getUrl(backupURL);
}

 

In the code above, we have implemented a failover call that utilizes our recommended best practices for achieving maximum uptime in the service. After calling the primaryURL with the getUrl function in Deluge, we check if the response was null or if there was a Fatal Error returned from the service. If either of these conditions are met, then the script will call the backupURL. This functionality helps maintain uptime in the event that the primary Service Objects endpoint experiences any issues. With this logic in your script, you can keep validating leads to your heart’s content without worrying about any downtime issues! Feel free to read more about our failover configuration here.

Step 5: Pushing the Service Objects response back to Zoho CRM

Now that we called the Lead Validation – International service and have a response, we can work on pushing that back to Zoho CRM. To start, we’ll create a few strings to hold the error object values, and then populate those values if an error is present in the response. The validation service should return an error only when certain fields are missing (i.e. license key, country, output language, or test type) but checking for the error can help reduce some headaches down the road if the Zoho CRM button doesn’t seem to be working properly.

type = "";
typecode = "";
desc = "";
desccode = "";
if(lviResponse.isNull())
{
    return "Error in LVI Call!";
}
//set error values if there are any
if(!lviResponse.getJSON("Error").isNull())
{
    type = lviResponse.getJSON("Error").getJSON("Type");
    typecode = lviResponse.getJSON("Error").getJSON("TypeCode");
    desc = lviResponse.getJSON("Error").getJSON("Desc");
    desccode = lviResponse.getJSON("Error").getJSON("DescCode");
}

 

Now that the error object values are put into strings, we can push the whole response back to our corresponding module fields. To do this, we’ll need to create a Zoho Map object that will allow us to use the Zoho CRM API and update our custom Lead_Validation_Int module. There are map functions in Deluge that will allow you to add key value pairs into a map object but, if you read the Map function documentation after you built a Map out manually as we did, you can create one like we did below.

That is quite a bit of code! At a high level, we’re performing a null check on every element that is returned from the Lead Validation – International service, and if it is present, that value will get pushed into the corresponding module value. At the very bottom of the Lead_Validation_Ints map, we’re updating the id field to be the input leadID that was sent to our function. This will help us link this newly created module with the original Lead module.

After this, we’ll use the Zoho CRM API to create a Lead_Validations_Int record. With this response, we can create an associated Phone Contact module if there was a Phone Contact present in the Lead Validation – International response.

Finally, we’ll return the “Success!” message as part of our response. If you would rather that no message is returned, you can simply have the function return an empty string and no message will be displayed to the user. Go ahead and click Save, and then deploy the button! Now it’s time to test it out. For reference, here’s the full bit of code used in the function we made.

//Build out our new lead object from all the values
newLead = { "Full_Name":zoho.encryption.urlDecode(fullName),
            "First_Name":zoho.encryption.urlDecode(firstName),
            "Last_Name":zoho.encryption.urlDecode(lastName),
            "Salutation":zoho.encryption.urlDecode(salutation),
            "Business_Name":zoho.encryption.urlDecode(businessName),
            "Business_Domain":zoho.encryption.urlDecode(businessDomain),
            "Business_EIN":zoho.encryption.urlDecode(businessEin),
            "Phone_1":zoho.encryption.urlDecode(phone1),
            "Phone_2":zoho.encryption.urlDecode(phone2),
            "Address_1":zoho.encryption.urlDecode(address1),
            "Address_2":zoho.encryption.urlDecode(address2),
            "Address_3":zoho.encryption.urlDecode(address3),
            "Address_4":zoho.encryption.urlDecode(address4),
            "Address_5":zoho.encryption.urlDecode(address5),
            "Locality":zoho.encryption.urlDecode(locality),
            "Admin_Area":zoho.encryption.urlDecode(adminArea),
            "Postal_Code":zoho.encryption.urlDecode(postalCode),
            "Country":zoho.encryption.urlDecode(country),
            "Email_1":zoho.encryption.urlDecode(email),
            "IP_Address":zoho.encryption.urlDecode(ipAddress),
            "Date_Of_Birth":zoho.encryption.urlDecode(dateOfBirth),
            "Gender":zoho.encryption.urlDecode(gender),
            "UTC_Capture_Time":zoho.encryption.urlDecode(utcCaptureTime),
            "Output_Language":outputLanguage,
            "Test_Type":testType,
            "Overall_Certainty":ifNull(lviResponse.getJSON("OverallCertainty"),""),
            "Overall_Quality":ifNull(lviResponse.getJSON("OverallQuality"),""),
            "Lead_Type":ifNull(lviResponse.getJSON("LeadType"),""),
            "Lead_Country":ifNull(lviResponse.getJSON("LeadCountry"),""),
            "Note_Codes":ifNull(lviResponse.getJSON("NoteCodes"),""),
            "Note_Description":ifNull(lviResponse.getJSON("NoteDesc"),""),
            "Name_Certainty":ifNull(lviResponse.getJSON("NameCertainty"),""),
            "Name_Quality":ifNull(lviResponse.getJSON("NameQuality"),""),
            "F_Name":ifNull(lviResponse.getJSON("FirstName"),""),
            "L_Name":ifNull(lviResponse.getJSON("LastName"),""),
            "F_Name_Clean":ifNull(lviResponse.getJSON("FirstNameClean"),""),
            "L_Name_Clean":ifNull(lviResponse.getJSON("LastNameClean"),""),
            "Name_Note_Codes":ifNull(lviResponse.getJSON("NameNoteCodes"),""),
            "Name_Notes_Description":ifNull(lviResponse.getJSON("NameNoteDesc"),""),
            "Address_Certainty":ifNull(lviResponse.getJSON("AddressCertainty"),""),
            "Address_Quality":ifNull(lviResponse.getJSON("AddressQuality"),""),
            "Address_Line_1":ifNull(lviResponse.getJSON("AddressLine1"),""),
            "Address_Line_2":ifNull(lviResponse.getJSON("AddressLine2"),""),
            "Address_Line_3":ifNull(lviResponse.getJSON("AddressLine3"),""),
            "Address_Line_4":ifNull(lviResponse.getJSON("AddressLine4"),""),
            "Address_Line_5":ifNull(lviResponse.getJSON("AddressLine5"),""),
            "Address_Locality":ifNull(lviResponse.getJSON("AddressLocality"),""),
            "Address_Admin_Area":ifNull(lviResponse.getJSON("AddressAdminArea"),""),
            "Address_Postal_Code":ifNull(lviResponse.getJSON("AddressPostalCode"),""),
            "Address_Resolution_Level":ifNull(lviResponse.getJSON("AddressResolutionLevel"),""),
            "Address_Note_Codes":ifNull(lviResponse.getJSON("AddressNoteCodes"),""),
            "Address_Notes_Description":ifNull(lviResponse.getJSON("AddressNoteDesc"),""),
            "Email_Certainty":ifNull(lviResponse.getJSON("EmailCertainty"),""),
            "Email_Quality":ifNull(lviResponse.getJSON("EmailQuality"),""),
            "Email_Corrected":ifNull(lviResponse.getJSON("EmailCorrected"),""),
            "Email_Note_Codes":ifNull(lviResponse.getJSON("EmailNoteCodes"),""),
            "Email_Notes_Description":ifNull(lviResponse.getJSON("EmailNoteDesc"),""),
            "IP_Address_Certainty":ifNull(lviResponse.getJSON("IPCertainty"),""),
            "IP_Address_Quality":ifNull(lviResponse.getJSON("IPQuality"),""),
            "IP_Country":ifNull(lviResponse.getJSON("IPCountry"),""),
            "IP_Locality":ifNull(lviResponse.getJSON("IPLocality"),""),
            "IP_Admin_Area":ifNull(lviResponse.getJSON("IPAdminArea"),""),
            "IP_Note_Codes":ifNull(lviResponse.getJSON("IPNoteCodes"),""),
            "IP_Notes_Description":ifNull(lviResponse.getJSON("IPNoteDesc"),""),
            "Phone_1_Certainty":ifNull(lviResponse.getJSON("Phone1Certainty"),""),
            "Phone_1_Quality":ifNull(lviResponse.getJSON("Phone1Quality"),""),
            "Phone_1_Locality":ifNull(lviResponse.getJSON("Phone1Locality"),""),
            "Phone_1_Admin_Area":ifNull(lviResponse.getJSON("Phone1AdminArea"),""),
            "Phone_1_Country":ifNull(lviResponse.getJSON("Phone1Country"),""),
            "Phone_1_Note_Codes":ifNull(lviResponse.getJSON("Phone1NoteCodes"),""),
            "Phone_1_Notes_Description":ifNull(lviResponse.getJSON("Phone1NoteDesc"),""),
            "Phone_2_Certainty":ifNull(lviResponse.getJSON("Phone2Certainty"),""),
            "Phone_2_Quality":ifNull(lviResponse.getJSON("Phone2Quality"),""),
            "Phone_2_Locality":ifNull(lviResponse.getJSON("Phone2Locality"),""),
            "Phone_2_Admin_Area":ifNull(lviResponse.getJSON("Phone2AdminArea"),""),
            "Phone_2_Country":ifNull(lviResponse.getJSON("Phone2Country"),""),
            "Phone_2_Note_Codes":ifNull(lviResponse.getJSON("Phone2NoteCodes"),""),
            "Phone_2_Note_Description":ifNull(lviResponse.getJSON("Phone2NoteDesc"),""),
            "Business_Certainty":ifNull(lviResponse.getJSON("BusinessCertainty"),""),
            "Business_Quality":ifNull(lviResponse.getJSON("BusinessQuality"),""),
            "Name1":ifNull(lviResponse.getJSON("BusinessName"),""),
            "Domain":ifNull(lviResponse.getJSON("BusinessDomain"),""),
            "Business_Email":ifNull(lviResponse.getJSON("BusinessEmail"),""),
            "Business_Note_Codes":ifNull(lviResponse.getJSON("BusinessNoteCodes"),""),
            "Business_Notes_Description":ifNull(lviResponse.getJSON("BusinessNoteDesc"),""),
            "Error_Type_Description":desc,
            "Error_Type":type,
            "Error_Type_Code":typecode,
            "Error_Type_Code_Description":desccode,
            "Owner":lead.get("Owner"),
            "Name":lead.get("Full_Name"),
            "Lead":{"name":lead.get("Full_Name"),
            "id":leadID}};

//call create record
resp = zoho.crm.createRecord("Lead_Validations_Int",newLead);

//If the PhoneContact object exists, we will create a linked phone object
if(!lviResponse.getJSON("PhoneContact").getJSON("Name").isNull())
{
    newPhone = {"Name1":ifNull(lviResponse.getJSON("PhoneContact").getJSON("Name"),""),
                "Name":ifNull(lviResponse.getJSON("PhoneContact").getJSON("Name"),""),
                "Address":ifNull(lviResponse.getJSON("PhoneContact").getJSON("Address"),""),
                "City":ifNull(lviResponse.getJSON("PhoneContact").getJSON("City"),""),
                "State":ifNull(lviResponse.getJSON("PhoneContact").getJSON("State"),""),
                "Zip":ifNull(lviResponse.getJSON("PhoneContact").getJSON("Zip"),""),
                "Type":ifNull(lviResponse.getJSON("PhoneContact").getJSON("Type"),""),
                "Owner":lead.get("Owner"),
                "LVI":{"name":lead.get("Full_Name"),
                "id":resp.get("id")}};
                
    phoneResp = zoho.crm.createRecord("LVI_Phone_Contacts",newPhone);
}
return "Success!";

 

Step 6: Test out that fancy new button

Now that our button is ready to go, let’s test it out on a test lead. Head to the Leads module (or wherever you added the button) and select the lead you to process through Lead Validation – International. If you don’t see the button, make sure you set the correct permissions on the button.

Find your button, and click it!

If you decided to return a message, you should see it pop up on the screen:

If all went well you should see a message come back to the screen and see that the updated information was populated into your module!

The validated address and filled in values of the different lead components let us know that the service was successfully called!

Tips and reminders for Zoho CRM Integration

  • If you are running into integration issues, try using the “info”. This will dump an object’s value to the screen and can be extremely helpful in debugging.
  • Having a leadID handy can also be really helpful when testing the functionality of the custom function you are writing for this button
  • If something doesn’t quite look right when calling the Lead Validation – International service, please reach out to us! It is possible that a required input may be missing, or the test type that is being used isn’t lining up with the input data.

Closing

Thanks for following along in our tutorial! Zoho CRM and Service Objects APIs are a great pairing to help enrich, validate, and enhance existing data. If you are looking to pair Lead Validation International with a Zoho CRM workflow rule, then you may want to look at our other Zoho CRM Integration guide for some assistance.

Be sure to check out Lead Validation – International service and sign up for a free trial key to get started on your Zoho CRM Integration. Your leads are waiting to be validated! If you have any questions about this integration guide or any of our products, be sure to reach out to support@serviceobjects.com and we’d be happy to help with your integration needs.