REST Client API (Bulk)

Introduction

Exponea has direct SDK support for the following platforms: JavaScript, Android, iOS, Unity, Flash, Python, Xamarin (Android). Almost every SDK offers a range of convenient features like automatic session tracking, offline event collection, bulk uploading and so on. Therefore these SDKs should be your starting point whenever you need to integrate your business with Exponea.

However we also provide you with the option to use low-level HTTP requests through our REST API. Using these requests you can track customer actions, identify customers and update their attributes. This guide should help you get started with REST in no time.

When should I use REST Client API?

Integration through the REST API is recommended when you need to send data from an unsupported platform or if you need low-level details for some reason.

How REST Client API works?

You can find information about the REST architecture on the internet, we will limit the explanation to our use case, that is sending data from your business to Exponea.

To send data to Exponea you basically need to create a HTTP request, send it to our server and then wait for the success reply. There are few options in what data you can send, to which end point on our server and which replies from our server you can get.

Before you start

Before you start integrating your business you should have a clear understanding of how Exponea works. To learn more see How does Exponea work?

When using our REST API there is no need to initialize anything in the code like you would need to if you were using our other SDKs. However there are some important concepts that you should understand before you start the integration. You can skip the next section if you are a seasoned developer.

What is REST?

REST is a simple way to organize interaction between independent systems (for example between your business and Exponea). REST architecture is closely tied to the HTTP protocol. If you have no idea how HTTP works, you can have a look at this excellent tutorial for REST and HTTP as we will cover only the basics.

HTTP and client-server communication

HTTP is the protocol that allows for sending documents back and forth on the web. These documents can be web pages but also structured customer data from your business.

There are two roles in HTTP: client and server. The client (your business) usually starts the conversation while the server (Exponea) replies. HTTP is text based so the documents exchanged are readable. These documents are called messages and they consist of a header and a body. The body contains data you want to send (e.g. purchase) and the header contains important metadata (e.g. HTTP method used).

HTTP Requests

Every message that you will send from your business to Exponea server will have a form of a HTTP request. These requests will look something like this:

POST /bulk HTTP/1.1 
Host: api.exponea.com
Content-Type: application/json

data-in-json-you-want-to-send

As we mentioned earlier this message consists of two parts, the header and the body.

Request header:

To make sure that the message is correctly recognized on the server you need to include an HTTP verb. Verbs tell the server what to do with the data. In our requests we will be using only one verb: POST.

You also need to specify URL which is the connecting point on the server where you want the message to be delivered.  In this example it is /bulk.

Then there is the HTTP version that should be used: HTTP/1.1.

Of course the message can’t be delivered without identifying our server in the internet, this is the hostname api.exponea.com.

And last line in the request header is reserved for specifying content type. As you will be sending data to Exponea in the JSON format, you must use application/json.

Request body:

The body of the request is for now denoted data-in-json-you-want-to-send. We will talk more about the structure of JSON in the following parts of this guide.

HTTP Response

After you send an HTTP request to our server, you should receive a response immediately. This response is in JSON format and should look like this:

{
  "end_time": "timestamp",
  "results": [
    {
      "status": "ok",
      "other_data": "..."
    }
  ],
  "start_time": "timestamp",
  "success": true
}

Start and end time are only for information purposes, the important things are “success” field (indicates if request was received correctly) and “status” field (indicates if request completed successfully).

You should check if every request that you send is handled correctly at our side. This way you can be sure that the data will be added to your project in Exponea.

We will talk more about responses in following parts of this guide.

Testing requests with cURL

It is possible to test your HTTP requests before you actually implement them by using cURL. cURL is a command line tool that lets you create and send HTTP requests and receive a response from the server. If you are using Linux or Mac you already have this tool, if you are using Windows you can download it from here.

Example of a cURL command:

curl -H 'Content-type: application/json' -d 'data-in-json-that-you-want-to-send' https://api.exponea.com/bulk

This command creates an HTTP request matching  the example request from before and sends it. We will use curl commands to show you examples of how to quickly test if your integration is working.

Implementing REST API in your business

If you understand how REST works, you can now move on to the actual implementation. There are few common terms that we will be using throughout the implementation guide.

Common terms

These are few common terms we will be using in the next section:

data payload – the data you are sending as a JSON in the HTTP request.
command – command is one instruction in JSON format (e.g. tracking a single event) that is contained in the data payload. There can be up to 50 commands in a single data payload. However there is always only one data payload in one HTTP request.
endpoint name – this is an address on our server which will be used to handle the command. It can be either “crm/events” (for event tracking) or “crm/customers” (for updating and identifying customers).

Sending data to Exponea

To send data to Exponea you will always be using this template HTTP request.

Template HTTP request:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "endpoint-name",
      "data": command-payload
    }
  ]
}

/bulk is address on Exponea server that will handle HTTP request.
“commands” is an array of commands (in one HTTP request you can update customer attribute and track an event at the same time in two separate commands). You need to edit “endpoint-name” and command-payload according to the guide. The rest of the HTTP request is explained in the HTTP Requests earlier on this page.

Tracking customer events

We talk about what customer events (actions) you should track and why you should track them in a separate guide in Tracking customer actions. Here we will focus only on the implementation.

The most basic way how to track a customer action is to send an HTTP request with a single command in the data payload to Exponea server.

Generic example of a request for event tracking:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "crm\/events",
      "data": {
        "customer_ids": {
          "customer id": "identifier"
        },
        "project_id": "PROJECT TOKEN",
        "type": "name of the event",
        "properties": {event attributes},
        "timestamp": unix_timestamp
      }
    }
  ]
}

You can find descriptions of “data” fields in the Key descriptions.

CURL command for this request will look like this:

curl -H 'Content-type: application/json' -d '{"commands":[]}' https://api.exponea.com/bulk

Specific example for tracking an event with attributes:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "crm\/events",
      "data": {
        "customer_ids": {
          "registered": "john.doe@example.com"
        },
        "project_id": "e5e1cc64-cedc-12e4-875e-b083fedeed2e",
        "type": "purchase",
        "properties": {
          "price": 15,
          "number of items": 3
        },
        "timestamp": 1432658128
      }
    }
  ]
}

Explanation:
This request will track event with name “purchase” to the project identified by project token “e5e1cc64-cedc-12e4-875e-b083fedeed2e”. This event will have two attributes (properties): “price” set to “15” and “number of items” set to “3”. It will track this event to a customer with a “registered” unique identifier set to “john.doe@example.com”. If such customer does not exist at the time of tracking, the customer will be created and event will be then added to his customer profile on our server. This event will have UNIX timestamp of 1432658128 which translates to 05/26/2015 @ 4:35pm (UTC).

It is important to always wait for response from our server to see if the request was handled successfully. Read more at Handling HTTP responses.

It is also possible to track multiple events in a single HTTP request. You can learn more at Sending multiple commands in a single request.

Identifying customers

We talk about how customers can be identified and why is identifying important in a separate guide at Identifying customers. Here we will focus only on the implementation.

The most basic way how to identify a customer is to send an HTTP request with a single command in the data payload to Exponea server.

Generic example of a request for identifying a customer:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "crm\/customers",
      "data": {
        "ids": {
          "registered": "known customer identifier",
          "cookie": "anonymous customer identifier"
        },
        "project_id": "PROJECT TOKEN"
      }
    }
  ]
}

You can find descriptions of “data” fields in the Key descriptions.

Specific example for identifying a customer:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "crm\/events",
      "data": {
        "customer_ids": {
          "registered": "john.doe@example.com",
          "cookie": "1d8dfaf3-6d4f"
        },
        "project_id": "e5e1cc64-cedc-12e4-875e-b083fedeed2e",
        "type": "purchase",
        "properties": {
          "price": 15,
          "number of items": 3
        },
        "timestamp": 1432658128
      }
    }
  ]
}

This request will identify anonymous customer (with attribute “cookie” set to “1d8dfaf3-6d4f”) as a known customer (with attribute “registered” set to “john.doe@example.com”) in the project with project token “e5e1cc64-cedc-12e4-875e-b083fedeed2e”.

There are few possible cases that can happen before sending identification command:

  • there existed a customer profile with “cookie” set to “1d8dfaf3-6d4f” and there was no customer profile with “registered” set to “john.doe@example.com”. This request will then update the attribute  “registered” of this customer.
  • there existed a customer profile with “registered” set to “john.doe@example.com” and there was no customer profile with “cookie” set to “1d8dfaf3-6d4f”. This request will then update the “cookie” attribute of this customer.
  • there existed a customer profile with “registered” set to “john.doe@example.com” and there was a different customer profile with “cookie” set to “1d8dfaf3-6d4f”. This request will then try to merge events of these two customers into one single customer profile which will have both of the attributes “registered” and “cookie” set. Merging will fail if the customer with “cookie” set to “1d8dfaf3-6d4f” also has attribute “registered” set to some value.
  • there was no customer profile with either attribute “registered” set to “john.doe@example.com” or attribute “cookie” set to “1d8dfaf3-6d4f”. This request will then create a customer profile with both of these attributes set to mentioned values.

Best practices:

  • when using REST API you probably want to create your own “cookie” (for example from the device ID) and use it as an identifier of anonymous customers (those customers that you don’t know yet – you have no email or Facebook ID for them)
  • you should also store “cookie” ID in a local storage so you can use it in the future business sessions (so data for one customer are always added to the same customer profile in Exponea)

Updating/setting customer attributes

We talk about what are customer attributes and why should you use them in a separate guide in Updating customer attributes. Here we will focus only on the implementation.

The most basic way how to update an attribute for a customer is to send an HTTP request with a single command in the data payload to Exponea server.

Generic example of a request for updating a customer attribute:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "crm\/customers",
      "data": {
        "ids": {
          "customer id": "customer identifier"
        },
        "project_id": "project token",
        "properties": {
          
        }
      }
    }
  ]
}

You can find descriptions of “data” fields in the Key descriptions.

Specific example of updating a customer attribute:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "crm\/customers",
      "data": {
        "ids": {
          "registered": "john.doe@example.com"
        },
        "project_id": "e5e1cc64-cedc-12e4-875e-b083fedeed2e",
        "properties": {
          "email": "john.doe@example.com",
          "sex": "M",
          "country": "United States"
        }
      }
    }
  ]
}

This request will update attributes “email”, “sex” and “country” to specified values of a customer identified by the attribute “registered” “john.doe@example.com”, in a project with a project token “e5e1cc64-cedc-12e4-875e-b083fedeed2e”.

If the customer attribute does not exist at the time the request is sent, it is created and then set to the specified value. If the customer attribute exists at the time when the request is sent it will be updated.

Sending multiple commands in a single request

It is possible to send up to 50 commands in a single HTTP request to Exponea. This way you can send more data with fewer requests which lowers the network load and will also save you a bit of processing time. Commands in one bulk request can contain different endpoint names.

Bulk API takes a list of command payloads and handles them in a sequence, returning a result for each of the commands. If an error occurs during the processing of a single command, other commands in the list are still executed.

Generic example of three commands in single bulk request:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "endpoint-name",
      "data": command-payload
    },
    {
      "name": "endpoint-name",
      "data": command-payload
    },
    {
      "name": "endpoint-name",
      "data": command-payload
    }
  ]
}

We already talked about commands earlier in this guide. Commands will have different endpoint names and command payloads whether you track events, identify customers or update customer attributes.

Specific example of updating a customer attribute and tracking of two events in a single bulk request:

POST /bulk HTTP/1.1
Host: api.exponea.com
Content-Type: application/json

{
  "commands": [
    {
      "name": "crm\/customers",
      "data": {
        "ids": {
          "registered": "john.doe@example.com"
        },
        "project_id": "e5e1cc64-cedc-12e4-875e-b083fedeed2e",
        "properties": {
          "email": "john.doe@example.com",
          "sex": "M",
          "country": "United States"
        }
      }
    },
    {
      "name": "crm\/events",
      "data": {
        "customer_ids": {
          "registered": "john.doe@example.com"
        },
        "project_id": "e5e1cc64-cedc-12e4-875e-b083fedeed2e",
        "type": "view item",
        "properties": {
          "price": 15,
          "category": 3
        },
        "timestamp": 1432658128
      }
    },
    {
      "name": "crm\/events",
      "data": {
        "customer_ids": {
          "registered": "john.doe@example.com"
        },
        "project_id": "e5e1cc64-cedc-12e4-875e-b083fedeed2e",
        "type": "purchase",
        "properties": {
          "price": 15,
          "number of items": 3
        },
        "timestamp": 1432658148
      }
    }
  ]
}

This bulk request will update three customer attributes for a customer identified by the attribute “registered” and it will track two events “view item” and “purchase” with two different sets of attributes to this same customer, in the same project.

Handling HTTP responses

Whenever you send an HTTP request to Exponea API you should wait for a response.

The response is in a JSON format and contains “results” array. This array contains a list of responses for every command you sent in the request. The sequence of responses in this array is the same as the sequence of commands sent in the request.

Example response:

{
  "results": [
    {
      "status": "ok",
      ... other data ...
    }
  ]
}

There are three possible “status” values:

  • “ok” – the command was executed successfully
  •  “error” – the command failed and a list of error messages is returned in the errors key
  • “retry” – the command was not processed, retry submitting it later. A list of error messages is returned in the errors key.

Only response “ok” means that the command was executed and handled correctly so it will be available in your project. If you keep getting “error” messages please write to our support at support@exponea.com.

Key descriptions

In the following table you can find the description of all keys (fields) used for sending data through our REST Client API.

Key (field) Description
customer_ids
  • customer identifiers ( “cookie” for identifying anonymous customers or “registered” for identifying known customers)
  • required (when tracking an event)
 ids
  • customer identifiers ( “cookie” for identifying anonymous customers or “registered” for identifying known customers)
  • required (when identyfing a customer or when setting/updating a customer attribute)
project_id
  • project token (you can find it in the Overview section of your project)
  • required
type
  • event name (type), should be human readable (e.g. “purchase”, “view itm”)
  • required (when tracking an event)
 properties
  • attributes that specify either event (when you are using attributes in the event tracking) or customer (when you are setting/updating customer attributes)
  • not required
 timestamp
  • a UNIX timestamp from the time the event was generated (can be a float)
  • each event per customer should have a unique timestamp so the order of events is not random when analysing event flow (if there are two events with the same timestamp it is sufficient to increment one by one thousandth)
  • not required (if omitted from the command, our server will add the timestamp to the event automatically with the time of when is the request received)