This document will show you some examples on how to use our REST API. The code snippets will be in PHP. If you are using a different language, these examples should still give you a pretty good hint on how to use our REST API and the Oauth interface.

REST in General

Our latest API is a RESTful one, since REST calls are pretty straight forward. Initiliaze your REST Library, append the access token (or do a login and use that token instead) and you are ready to query the API. Check Our full REST API documentaion because it contains everything you need to know and also you can test your queries there.

We also wrote a PHP REST library which most of the the examples here will be based on. You can download our REST library including some examples here.

You need to know this!

The REST API basicly works like every HTTP browser. You want to access a resource f.e. "/groups" and you want to GET all the available groups. Except that REST utilizes the other methods like POST, PUT and DELETE aswell. GET will obviously read from resources, POST will create new resources, PUT updates resources and DELETE will of course delete resources. For a detailed list of available resources and methods, have a look at our REST API documentaion.

Authenticating

Before we can start sending queries, we need to authenticate with the REST API. We will be using the OAuth Baerer method for authenticating.

$rest = new CR\tools\rest("https://rest.cleverreach.com/v2");

//skip this part if you have an OAuth access token
$token = $rest->post('/login', 
	array(
		"client_id"=>'<YOUR_CUSTOMER_ID>',
		"login"=>'<YOUR_LOGIN>',
		"password"=>'<YOUR_PASSWORD>'
	)
);

$rest->setAuthMode("bearer", $token);

GET (retrieve)

To retrieve a resource, like all your available groups, simply run this:

$data = $rest->get("/groups");

Some resources have additional filters/options. /mailings for example has filters to specify what kind of mailings you want (all/finished/draft/waiting)

$data = $rest->get("/mailings", array("type"=>"draft") );

POST (create new and special functions)

Creating a new resource like f.e. a group, follows the same principle. All you need to do is adding the required parameters.

$data = $rest->post("/groups", array("name"=>"my new REST group") );

PUT (update)

Updating a resource requires you to know the resource ID, but follows the same style as a POST.

$data = $rest->put("/groups/1234", array("name"=>"my updated REST group") );

DELETE

Deleting just requires the resource ID

$data = $rest->delete("/groups/1234");

Error handling

In case of errors, you will receive a http error code and the apropiate error description. In this example we tried to access a report which does not exist.

$data = $rest->get("/report/4321");

{
  "error": {
    "code": 404,
    "message": "Not Found"
  }
}

Structure

The Cleverreach data structure might be a bit confusing at first, so we are going to explain some basics here.

During the usage of the REST API you will encounter these main resources.

Nesting

While every resource is accessable on its own, some of these resources may be nested within each other because they can have multiple points of origin.

/receivers f.e. can be a standalone resource, returning you information about an email address.
/groups/receivers on the other hand returns only the receiver inside this group and way more data like subscription dates, group bound attributes events and more.

/attributes Returns a list of all global attributes (not bound to any group)
/groups/{group_id}/attributes returns all attributes bound to this group and
groups/{group_id}/receivers/{pool_id}/attributes returns all attributes assigned to this user INCLUDING their current values.
However, if you just use groups/{group_id}/receivers/{pool_id}, you will get the attributes of the user anyway embeded inside the returned structure.

Example REST Calls

Initialization - Create what you need!

Once you plugin is beeing initialized, its best to create the necessary group (or let the user select it) and attributes in advance. Usualy its best to just create global attributes which can be accessed no matter what group you are currently using. Also only create attributes the user realy needs since the number of attributes are limited.

Imagine a User withe the Email "batman@gotham.com" with the firstname "Bruce". It should not matter what group (list) he is in, his name will always be "Bruce". Therefor creating a global attribute "Firstname" makes sense.

$rest->post("/attributes", array("name"=>"salutation", "type"=>"gender"));
$rest->post("/attributes", array("name"=>"firstname", "type"=>"text"));
$rest->post("/attributes", array("name"=>"lastname", "type"=>"text"));
$rest->post("/attributes", array("name"=>"address", "type"=>"text"));
$rest->post("/attributes", array("name"=>"city", "type"=>"text"));
$rest->post("/attributes", array("name"=>"zip", "type"=>"text"));
$rest->post("/attributes", array("name"=>"country", "type"=>"text"));
$rest->post("/attributes", array("name"=>"birthday", "type"=>"date"));

If you are writing software for f.e. Multishop solutions, you might want to switch to group bound attributes because the multiple firstnames might interfere with each other.

$rest->post("/groups/{$groupid}/attributes", array("name"=>"firstname", "type"=>"text"));
$rest->post("/groups/{$groupid}/attributes", array("name"=>"lastname", "type"=>"text"));

Syncronize/import receivers

After your setup process, its best to do an initial import. This should be done in stacks and not one by one. While you can import each user one by one, you shouldnt, because this way you will be dealing with way more overhead then necessary.

Here for example, we are passing to the REST API once a stack reaches 1000.

$receivers = array();
$rows = mysql_query("select id, email, firstname, lastname, gender, registration_date from user");

foreach ($rows as $row) {
	$orders = array();
	$order_rows = mysql_query("select * from orders where user_id={$row->id}");
	foreach ($order_rows as $order_row) {
		$orders[] = array(
			"order_id" => $order_row->order_id,	//required
			"product_id" => $order_row->product_id,	//optional
			"product" => $order_row->product_name, //required
			"price" => $order_row->single_price, //optional
			"currency" => "EUR", //optional
			"amount" => $order_row->order_ammount, //optional
			"mailing_id" => $order_row->mailing_id, //optional
			"source" => "batman-shop.org", //optional
		);
	}

	$receivers[] = array(
		"email"			=> $row->email,
		"registered"		=> strtotime($row->registration_date),
		"activated"		=> strtotime($row->registration_date),
		"source"		=> "Batcave Computer",
		"global_attributes"	=> array(
			"firstname" => $row->firstname,
			"lastname" => $row->lastname,
			"gender" => $row->gender
			//...
			),
		"orders" => $orders

	);


	if( count($receivers)>1000) {
		$rest->post("/groups/{$target_group_id}/receivers", $receivers);
		$receivers = array();
	}
}
$rest->post("/groups/{$target_group_id}/receivers", $receivers);

Order injection vs. import (post setup)

Since data still needs to be synchronized after the initial import, there are 2 methods you can use. You can either run the original import as a cronjob, or you can do a live order injection. We actualy prefer the live order injection which is basicly nothing more like reduced version of the Import.
Please make sure that you are using some sort of try and catch methods, otherwhise you might break your shops order process if the API cant be reached and any other error occurs.

try {
	$receiver = array(
		"email"		=> "bruce@wayne.com",
		"registered"=> time(),	//current date
		"activated"	=> time(),
		"source"	=> "Batcave Computer",
		"global_attributes"	=> array(
			"firstname" => "Bruce",
			"lastname" => "Wayne",
			"gender" => "male"
		),
		"orders" => array(
			array(
				"order_id" => "xyz12345",	//required
				"product_id" => "SN12345678",	//optional
				"product" => "Batman - The Movie (DVD)", //required
				"price" => 9.99, //optional
				"currency" => "EUR", //optional
					"amount" => 1, //optional
				"mailing_id" => "8765432", //optional
				"source" => "Batshop", //optional
			),
			array(
				"order_id" => "xyz12345",	//required
				"product" => "Batman - The Musical (CD)", //required
			)

		)


	);
	$batman = $rest->post("/groups/{$gotham_group->id}/receivers", $receiver);
} catch (\Exception $e){
	system_log("error syncing order");
}

Double-Opt-In

To send a DOI Email, you have to first create the customer. Please note the that the field "activated" is set to ZERO which means he will not be active and can't receive any newsletters until he is activated. After creation we will tell the REST API to sent him a specific form to activate his account.

$new_user = array(
	"email"			=> "batman@gotham.com",
	"registered"	=> time(),	//current date
	"avtivated"		=> 0,	//NOT active, will be set by DOI
	"source"		=> "Batcave Computer",
	"attributes"	=> array(
		"firstname" => "Bruce",
		"lastname" => "Wayne",
		"gender" => "male"
	)
);

if( $success = $rest->post("/groups/{$target_group_id}/receivers/insert", $new_user) ) {
	$rest->post("forms/{$form_id}/send/activate", array(
		"email" => $new_user["email"],
		"doidata" => array(
			"user_ip" => $_SERVER["REMOTE_ADDR"],
			"referer" => $_SERVER["SERVER_NAME"].$_SERVER["REQUEST_URI"],
			"user_agent" => $_SERVER["HTTP_USER_AGENT"]
			)
	));
}

Our Oauth implementation follows the 2.0 Specification. For a detailed Oauth explanation please have a look at https://blog.varonis.com/introduction-to-oauth/.

Download an example here!

In order to start, you need to create yourself an OAuth App inside of cleverreach. Go to Account > Extras > REST API and create one there. You will find all neccessary information there afterwards.

Oauth itself can be handled in 3 easy steps.

  1. Redirect the user to our OAuth service and make him login in order to give you access to his data
  2. if successfull, the OAuth interface will return the user to your website and give you an authorization code.
  3. Trade in the authorization code for a access token.

Example OAuth process

<?php
$clientid = "#Place OAuth clientID here#";
$clientsecret = "#Place OAuth client secret here#";
$auth_url = "https://rest.cleverreach.com/oauth/authorize.php";
$token_url = "https://rest.cleverreach.com/oauth/token.php";

$rdu = urlencode("#The URL of this file#");	//mandatory!

if(!$_GET["code"]) {	//if not returned from from OAuth interface
	echo "<h1>I am and example page and I may sit somwhere in your backend.</h1>";;
	echo "<a href=\"{$auth_url}?client_id={$clientid}&grant=basic&response_type=code&redirect_uri={$rdu}\">Klick me to get a User Token</a>";
}else {	//we got a authorization code which means we can trade it for an access token

	//prepare post
	$fields["client_id"]=$clientid;
	$fields["client_secret"]=$clientsecret;
	
	//must be the same as previous redirect uri
	$fields["redirect_uri"]=urldecode($rdu);	
	
	//tell oauth what we want! we want to trade in our auth code for an access token
	$fields["grant_type"]="authorization_code";	
	$fields["code"]=$_GET["code"];	


	//Trade the Authorize token for an access token
	$curl = curl_init();
	curl_setopt($curl,CURLOPT_URL, $token_url);
	curl_setopt($curl,CURLOPT_POST, sizeof($fields));
	curl_setopt($curl,CURLOPT_POSTFIELDS, $fields);
	curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
	$result = curl_exec($curl);	//
	curl_close ($curl);

	echo "<h1>Your backend again</h1>";
	echo "<pre>";
	var_dump($result);
	//save the access token for further usage!
}