Use Salsa Labs' supporter API with PHP and cURL

September 12, 2011
Development

Bowl of tasty chip salsa

Image by QualityFrog on Flickr

We recently designed and developed a web application for a United Auto Workers (UAW) internal campaign. The project required supporter registrations to be stored locally and with Salsa Labs’ online campaign platform that helps organize and energize UAW’s members. Conveniently, Salsa Labs provides an easy-to-use, robust API allowing developers like us to interface with Salsa Labs’ platform programmatically. Just like we at New Media Campaigns integrated with NGP’s fundraising API, we used PHP and cURL to send new UAW supporter registrations to Salsa Labs’ database.

Salsa Labs' online platform is one of several tools in our toolbox that allow us to build powerful, robust web solutions for our political clients.

Requirements

You’ll need your own Salsa Labs account. You’ll also need PHP 5.0.0 (or newer) with the libcurl package. Before going further, make sure you have this information about your Salsa Labs account handy:

  • Salsa Node URL
  • Salsa Organization Key

If you have any questions about the required Salsa Labs information, contact your Salsa Labs representative.

Brief Overview

Our application and Salsa Labs’ platform both run atop a MySQL database and store similar supporter data, albeit with different column names. We’ll need to map our database columns to their Salsa Labs equivalent.

To programmatically submit a new supporter into Salsa Labs’ platform, we’ll send an HTTP POST request to a Salsa Labs API URL. We do not need to authenticate against the Salsa Labs API because we are only submitting new data and not editing existing data.

HTTP Request URL

To save new supporter data to the Salsa API, we’ll send an HTTP request to this URL:

http://your.node.url.tld/save?json

Replace “your.node.url.tld” with your own Salsa Labs Node URL. The “json” query parameter, after the question mark, indicates we expect an HTTP response from the API in JSON format; we can also use “xml”. We find JSON easier to work with, and the easier the better, right?

We must tell Salsa who we are by appending the organization_KEY parameter (case-sensitive) to the HTTP request’s URL query string. For the sake of demonstration, let’s assume the organization key is ABC123, but of course, use your own organization key.

http://your.node.url.tld/save?json&organization_KEY=ABC123

Each object in Salsa Labs’ platform is identified by a unique key. We tell Salsa Labs we are sending a new supporter by appending the key parameter to the HTTP request’s URL query string with a value of 0.

http://your.node.url.tld/save?json&organization_KEY=ABC123&key=0

Now, Salsa Labs will create a new supporter rather than update an existing one.

HTTP Request Data

Next, we include the new supporter data with the HTTP request; in PHP, the user data is an associative array (shown below). We append each key/value pair to the HTTP request’s URL query string making sure each value is url encoded.

As I said above, our local database schema does not match Salsa Labs’ database schema. We need to map our database columns to Salsa Labs’ database columns with a PHP associative array. Array keys represent our local database column names; array values represent Salsa Labs’ database column names.

<?php
$map = array(
    'created_at' => 'Date_Created',
    'name_first' => 'First_Name',
    'name_last' => 'Last_Name',
    'email' => 'Email',
    'phone' => 'Cell_Phone',
    'phone_home' => 'Phone',
    'city' => 'City',
    'state' => 'State',
    'zip' => 'Zip',
    'unit_company' => 'Organization'
);
?>

The supporter information is stored in an associative array like this:

<?php
$supporter = array(
    'name_first' => 'John',
    'name_last' => 'Doe',
    'email' => 'john.doe@fakegmail.com',
    'phone' => '1234567890',
    'phone_home' => '2345678901',
    'city' => 'Carrboro',
    'state' => 'NC',
    'zip' => '27510',
    'unit_company' => 'New Media Campaigns',
    'created_at' => '2011-09-08 00:00:00'
);
?>

Now we can build the rest of the HTTP request URL query string with a foreach loop, making sure we use Salsa Labs’ database column names instead of our own.

<?php
//The Request URL so far...
$url = 'http://your.node.url.tld/save?json&organization_KEY=ABC123&key=0';

//Complete the Request URL with supporter data
foreach ( $supporter as $key => $value ) {
    if ( isset($map[$key]) ) {
        $url .= sprintf('&%s=%s', $map[$key], urlencode($value));
    }
}
?>

The HTTP request URL is complete.

Submitting the HTTP request

Finally, we need to send an HTTP POST request to Salsa Labs’ API with the supporter data. We do this with cURL.

<?php
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Length: 0'));
curl_setopt($ch, CURLOPT_POSTFIELDS, '');
$lastResponse = curl_exec($ch);
$lastResponseHeaders = curl_getinfo($ch);
curl_close($ch);
?>

Salsa Labs’ API did not want to work with URL encoded data in the HTTP request’s body; so we set the cURL CURLOPT_POSTFIELDS option to an empty string and ensure the HTTP request has a Content-length header with a value of 0. The supporter data will still be sent to the API; it will be in the URL query string rather than in the request body.

Salsa Labs will receive the supporter data and return an HTTP response in JSON format. Here is an example response:

[{"object":"supporter","key":"12345678","result":"success","messages":[]}]

If the HTTP request failed, the result key will be “error” and an array of error messages will be in the messages array. For debugging purposes, the raw HTTP response will be in the $lastResponse variable and all HTTP response headers (and more) will be in the $lastResponseHeaders variable.

Complete Code

Here’s the complete PHP code.

<?php
//Map of our database columns (keys) to Salsa Labs' database columns (values)
$map = array(
    'created_at' => 'Date_Created',
    'name_first' => 'First_Name',
    'name_last' => 'Last_Name',
    'email' => 'Email',
    'phone' => 'Cell_Phone',
    'phone_home' => 'Phone',
    'city' => 'City',
    'state' => 'State',
    'zip' => 'Zip',
    'unit_company' => 'Organization'
);

//Supporter data
$supporter = array(
    'name_first' => 'John',
    'name_last' => 'Doe',
    'email' => 'john.doe@fakegmail.com',
    'phone' => '1234567890',
    'phone_home' => '2345678901',
    'city' => 'Carrboro',
    'state' => 'NC',
    'zip' => '27510',
    'unit_company' => 'New Media Campaigns',
    'created_at' => '2011-09-08 00:00:00'
);

//The Request URL so far...
$url = 'http://your.node.url.tld/save?json&organization_KEY=ABC123&key=0';

//Complete the Request URL with supporter data
foreach ( $supporter as $key => $value ) {
    if ( isset($map[$key]) ) {
        $url .= sprintf('&%s=%s', $map[$key], urlencode($value));
    }
}

//Send the request
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_POST, 1);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 5);
curl_setopt($ch, CURLOPT_HTTPHEADER, array('Content-Length: 0'));
curl_setopt($ch, CURLOPT_POSTFIELDS, '');
$lastResponse = curl_exec($ch);
$lastResponseHeaders = curl_getinfo($ch);
curl_close($ch);
?>

For our application, and for your convenience, we’ve encapsulated this code into a PHP singleton class. You’ll need to update the class variables with your own Salsa Labs account information and update the class database column map to reflect your own local database schema. After you update the class variables, you can save an associative array of supporter data to Salsa Labs’ API like this:

<?php
require 'Salsa.php';
Salsa::getInstance()->save(array(...));
?>

Download Our Salsa API Class

Comments

vikas kumar's avatar
vikas kumar
Thanks for valuable information. very nicely explained and easy to understand..
Jessica's avatar
Jessica
Thanks so much for this tutorial. I have one edit -- I struggled for a short while getting this to work. I was getting:

"There was a problem with your submission. No object was specified"

as an error response. I found that you also need to send "&object=supporter" in the query string. After adding that, everything worked perfectly.
Joel Sutherland's avatar
Joel Sutherland NMC team member
Great overview Josh. It looks like a very clean API and pretty nice to use!

Leave a comment