Orange is my favorite color

This is going to be mostly code because I don’t have time to really annotate much. However, if you’re an Adobe ColdFusion developer and you also use (or are considering) the very good Batchbook Social CRM then you may also want to use their REST API in order to programmatically create or read your contact data.

While Batchbook does have the pretty cool web forms which can capture contact data from any ole web form, it doesn’t give you total flexibility with filling in customized data fields. In our case, we wanted to create companies rather than individuals as part of a sales pipeline so we needed to have more control than the web forms currently allow.

Start with a contact form

Here’s the HTML form that we’re using – it still uses the original web form field names so all I’ve done here is changed the form ACTION to point at my CFM instead of Batchbook:

<form method="post" action="https://ourserver.com/form.cfm">
<input type="hidden" name="location[address][country]" value="US" />
<h2>Sign-up Now!</h2>
<table class="form">
<tr><td><label>Company *</label></td></tr>
<tr><td><input type="text" name="company[name]" size="30" /></td></tr>
<tr><td><label>Account Type *</label></td></tr>
<tr><td><select name="supertags[sales first contact][plan]"><option value="">Select a plan - you can change later</option><option value="Plan 1">Plan Uno</option><option value="Plan 2">Plan Dos</option><option value="Plan 3">Plan Tres</option></select></td></tr>
<tr><td><label>First Name *</label></td></tr>
<tr><td><input type="text" name="contact_details[first_name]" size="30" /></td></tr>
<tr><td><label>Last Name *</label></td></tr>
<tr><td><input type="text" name="contact_details[last_name]" size="30" /></td></tr>
<tr><td><label>Email *</label></td></tr>
<tr><td><input type="text" name="location[email]" size="30" /></td></tr>
<tr><td><label>Phone *</label></td></tr>
<tr><td><input type="text" name="location[phone]" size="30" /></td></tr>
<tr><td><label>Organization Address</label></td></tr>
<tr><td><input type="text" name="location[address][address_1]" size="30" /></td></tr>
<tr><td><label>Address 2</label></td></tr>
<tr><td><input type="text" name="location[address][address_2]" size="30" /></td></tr>
<tr><td><label>City, State Zip</label></td></tr>
<tr><td><input type="text" name="location[address][city]" size="15" />, <input type="text" name="location[address][state]" size="4" /> <input type="text" name="location[address][zip_code]" size="10" /></td></tr>
<tr><td><label>Company URL</label></td></tr>
<tr><td><input type="text" name="location[website]" size="40" /></td></tr>
<tr><td><label>Do you have an existing service?  If so, which:</label></td></tr>
<tr><td><input type="text" name="supertags[sales first contact][existing_service]" size="40" /></td></tr>
<tr><td><label>Date of next event:</label></td></tr>
<tr><td><input type="text" name="supertags[sales first contact][date_of_first_event]" size="15" /><br /><small>Format date like mm/dd/yyyy</small></td></tr>
<tr><td><label>Questions/Comments</label></td></tr>
<tr><td><textarea name="supertags[sales first contact][customer_comments]" rows="10" cols="50"></textarea></td></tr>
<tr class="submit"><td><input class="button" type="submit" value="Request Account" /></td></tr>
</table>
</form>

It’s the same contact form you’ve whipped up 100 times before. If you’re using the built in web forms, the field names must match what is above. If I was writing my form handler from scratch I would have selected more normalized names.

Note that we a hidden field at the beginning – not all of the data must be user editable. Of course, I could also just set it in my form handler. The country value is a holdover from the original web form.

Process those fields

Our next step is to process that form submission with ColdFusion and use the Batchbook API to create my contacts and populate my custom data fields:

< !--- credentials --->
<cfset variables.api_key = 'YOUR-SECURITY-KEY' />< !--- get this from "Your Account", right column --->
<cfset variables.root_uri = 'https://[YOUR HOST].batchbook.com/service' />

<cfhttp url="#variables.root_uri#/companies.xml" method="post" username="#variables.api_key#" password="x" charset="UTF-8" timeout="30" throwonerror="no">
	<cfhttpparam name="company[name]" value="#form['company[name]']#" type="formfield" />
	<cfhttpparam name="company[notes]" value="" type="formfield" />
</cfhttp>
< !--- cfdump var="#cfhttp#" --->

<cfif structKeyExists(cfhttp, "responseheader") AND isStruct(cfhttp.responseheader) AND structKeyExists(cfhttp.responseheader, "location")>

	<cfhttp url="#cfhttp.responseheader.location#" method="get" username="#variables.api_key#" password="x" charset="UTF-8" timeout="30" throwonerror="no">
	</cfhttp>
	< !--- cfdump var="#cfhttp#" --->

	<cfset xmlCompany = xmlParse(cfhttp.fileContent) />
	<cfset id = xmlCompany.company.id.xmlText />

	< !--- now add location to company --->
	<cfhttp url="#variables.root_uri#/companies/#id#/locations.xml" method="post" username="#variables.api_key#" password="x" charset="UTF-8" timeout="30" throwonerror="no">
		<cfhttpparam name="location[label]" value="work" type="formfield" />
		<cfhttpparam name="location[email]" value="#form['location[email]']#" type="formfield" />
		<cfhttpparam name="location[website]" value="#form['location[website]']#" type="formfield" />
		<cfhttpparam name="location[phone]" value="#form['location[phone]']#" type="formfield" />
		<cfhttpparam name="location[street_1]" value="#form['location[address][address_1]']#" type="formfield" />
		<cfhttpparam name="location[street_2]" value="#form['location[address][address_2]']#" type="formfield" />
		<cfhttpparam name="location[city]" value="#form['location[address][city]']#" type="formfield" />
		<cfhttpparam name="location[state]" value="#form['location[address][state]']#" type="formfield" />
		<cfhttpparam name="location[postal_code]" value="#form['location[address][zip_code]']#" type="formfield" />
		<cfhttpparam name="location[country]" value="#form['location[address][country]']#" type="formfield" />
	</cfhttp>
	< !--- cfdump var="#cfhttp#" --->

	< !--- set default values for sales super tag and capture user-provided information --->
	<cfset arrSuperTag = arrayNew(1) />
	<cfset arrayAppend(arrSuperTag, "super_tag[existing_service]=#URLEncodedFormat(form['supertags[sales first contact][existing_service]'])#") />
	<cfset arrayAppend(arrSuperTag, "super_tag[date_of_first_event]=#URLEncodedFormat(form['supertags[sales first contact][date_of_first_event]'])#") />
	<cfset arrayAppend(arrSuperTag, "super_tag[customer_comments]=#URLEncodedFormat(form['supertags[sales first contact][customer_comments]'])#") />
	<cfset arrayAppend(arrSuperTag, "super_tag[plan]=#URLEncodedFormat(form['supertags[sales first contact][plan]'])#") />
	<cfset arrayAppend(arrSuperTag, "super_tag[requested_demo]=#URLEncodedFormat(form['supertags[sales first contact][requested_demo]'])#") />
	<cfset arrayAppend(arrSuperTag, "super_tag[active]=true") />
	<cfset arrayAppend(arrSuperTag, "super_tag[paperwork_sent]=false") />
	<cfset arrayAppend(arrSuperTag, "super_tag[agreement_back]=false") />
	<cfset arrayAppend(arrSuperTag, "super_tag[announced_on_facebook]=false") />
	<cfset arrayAppend(arrSuperTag, "super_tag[buddy_check_complete]=false") />	

	<cfhttp url="#variables.root_uri#/companies/#id#/super_tags/sales.xml" method="put" username="#variables.api_key#" password="x" charset="UTF-8" timeout="30" throwonerror="no">
		<cfhttpparam type="header" name="Content-Type" value="application/x-www-form-urlencoded" />
		<cfhttpparam type="body" value="#arrayToList(arrSuperTag, "&")#" />
	</cfhttp>
	< !--- cfdump var="#cfhttp#" --->

	< !--- create person--->
	<cfhttp url="#variables.root_uri#/people.xml" method="post" username="#variables.api_key#" password="x" charset="UTF-8" timeout="30" throwonerror="no">
		<cfhttpparam name="person[first_name]" value="#form['contact_details[first_name]']#" type="formfield" />
		<cfhttpparam name="person[last_name]" value="#form['contact_details[last_name]']#" type="formfield" />
		<cfhttpparam name="person[company]" value="#form['company[name]']#" type="formfield" />
	</cfhttp>
	< !--- cfdump var="#cfhttp#" --->
</cfif>

Some notes about the above:

  • What’s my password? Your password is X. Or Y. Or Z. It doesn’t matter – Batchbook only authenticates you on your unique key which is sent as the username. The password can be anything.
  • If you’re new to REST APIs, I suggest enabling the CFDUMPs as they will show you how data comes and goes. Plus, you’ll see what the response headers look like (hint, they aren’t all 200 OKs).
  • Associating people with companies – there is no official way to do this. Just make sure the “company” value for the person is a string match for the company record and Batchbook will make the magic happen on their end.
  • There is basically no error checking or exception handling here – I’ve got my code wrapped up in some try/catch and I fall back to sending an email to us if all else fails. Plan for failure. At some point the API will be down or the Internet will break and you need to have a contingency plan when dealing with remote third parties.

The above code took me a day or two of toying around to get working properly. While the docs are pretty good, my experience is that API implementations never quite match their documentation. Getting super tags to work (key to our sales process) took a lot of fooling around plus some assistance from the very helpful Eric Krause at Batchbook.

Next post will be how we’re integrating the results of this sales pipeline with Email Center Pro to dynamically generate and send out contracts in preparation for our sales cycle this winter.

Comments are closed.