Introduction
With Remarkety, you can trigger automations based on various events which occur in your system.
What are events?
Events simply describe something that happened on your website or business. Events always have a type, a time and a subject.
Some examples of events are:
- A customer made an order on your website on July 4, 2017, 10:00am.
- A visitor visited a page on your website on February 26, 2016, 8:53pm.
- A product was restocked to a level of 100 units on June 5, 2016, 9:41am.
- An order was shipped to a customer on Oct 12, 2015, 9:34am
- A subscriber signed up for a newsletter on...
- A recipient clicked on a link in a campaign on...
You get the picture ;)
How are events used in Remarkety?
Events are used within Remarkety to:
- Trigger automations, either immediately or with a delay
- Update eCommerce data in Remarkety (Customers/Orders/Products/Carts).
Sending Events
Event Format
All events must have a type. Remarkety has some built-in event types for e-commerce which you should use if you are sending e-commerce related events. In addition, you can send us any other type of custom event, but we will not be able to perform advanced e-commerce related analytics on them.
The built-in event types are specified in the E-Commerce Event Types section. For sending your own custom events, please see the Custom Events section.
Server-Side API
<?php
$storeId = "AAABBB"; // Unique per remarkety account
$apiKey = "SuperSecretApiKey"; // Get this from Remarkety
$eventType = "customers/update"; // See "Event types"
$domain = "kingslanding.com"; // Your store's domain
$platform = "MAGENTO"; // Per-platform setting
$headers = [
"x-domain: $domain",
"x-platform: $platform",
"x-token: $apiKey",
"x-event-type: $eventType",
'Content-Type: application/json; charset=UTF-8'
];
$customerData = [
'created_at' => '2017-04-04T15:12:21-05:00',
'email' => 'john.snow@thewall.org',
'first_name' => 'John',
'last_name' => 'Snow',
'updated_at' => '2017-04-04T15:12:21-05:00',
'accepts_marketing' => true
];
$dataString = json_encode($customerData);
$ch = curl_init("https://webhooks.remarkety.com/webhooks/?storeId=$storeId");
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, "POST");
curl_setopt($ch, CURLOPT_POSTFIELDS, $dataString);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
$result = curl_exec($ch);
var storeId = "AAABBB"; // Unique per remarkety account - get yours from the API setting page
var eventType = "customers/update"; // See "Event types"
var data = JSON.stringify({
"email": "john.snow@thewall.org",
"first_name": "John",
"last_name": "Snow",
"accepts_marketing": true
});
// If run server-side, send the request directly to our webhook endpoint, and include your API token
var token ="<Your API token>"; // Never expose this client-side!
var xhr = new XMLHttpRequest();
xhr.withCredentials = true;
xhr.addEventListener("readystatechange", function () {
if (this.readyState === 4) {
console.log(this.responseText);
}
});
xhr.open("POST", "https://webhooks.remarkety.com/webhooks/store/"+storeId);
xhr.setRequestHeader("Content-Type", "application/json");
xhr.setRequestHeader("x-event-type", eventType);
xhr.setRequestHeader("x-token", token);
xhr.setRequestHeader("Cache-Control", "no-cache");
xhr.send(data);
The request must be a POST
request to our endpoint.
The request needs to include the following headers:
Header | Value | Example |
---|---|---|
Content-Type | application/json; charset=UTF-8 | |
x-event-type | The event type | customers/update |
x-api-key | Your Remarkety API Key (not necessary on client-side events) | abc123 |
x-domain | Your domain (optional) | my.store.com |
x-platform | Your e-commerce platform (optional). For custom events use "custom". | MAGENTO1 |
x-event-time | UNIX timestamp. When this event occurred. By default, Remarkety assumes events happen when a request is made. Add this header if you'd like to track an event that happened in past. |
1573649331 |
The body
of the request is simply the event JSON itself.
Client-Side API
Remarkety's client-side library allows you to send events to Remarkety based on the visitor's actions on the store.
You can also send eCommerce events using the client-side library based on the event payload described on the E-Commerce event types docs.
Adding the client-side snippet
For client-side library examples switch to "javascript" examples
<script>
var _rmData = _rmData || [];
_rmData.push(['setStoreKey', '<STORE_ID>']);
</script>
<script>(function(d, t) {
var g = d.createElement(t),
s = d.getElementsByTagName(t)[0];
g.src = 'https://d3ryumxhbd2uw7.cloudfront.net/webtracking/track.js';
s.parentNode.insertBefore(g, s);
}(document, 'script'));
</script>
All pages on the website should include this piece of code, just before the </body>
tag.
Make sure to include the correct <STORE_ID>
which you can find under Settings > API Keys in your account.
Identifying Visitors
For client-side library examples switch to "javascript" examples
var _rmData = _rmData || [];
//Identify using email address
_rmData.push(['setCustomer', '<CUSTOMER_EMAIL>']);
//Identify using customer id
_rmData.push(['setCustomerId', '<CUSTOMER_ID>']);
//Identify the customer and update the accepts_marketing and first_name properties
_rmData.push(['setCustomer', {
"email": "john.snow@thewall.org",
"first_name": "John",
"accepts_marketing": true
}]);
The setCustomer
and setCustomerId
method allows you identify the visitors based on their email address or your internal customer id.
You can also use the setCustomer
method with customer information, that will get updated in Remarkety contact's details.
For the full list of customer properties please check the "customers/create" properties.
Please Note:
- If the contact does not exists in Remarkety, the setCustomer method will create the contact.
- The
setCustomerId
method requires that the contact will already be synced to Remarkety. - Without identifying the visitor, Remarkety will not receive the events.
Sending events
For client-side library examples switch to "javascript" examples
var _rmData = _rmData || [];
//Sending an eCommerce event for updating the customer data
var eventType = 'customers/update';
var data = {
"email": "john.snow@thewall.org",
"first_name": "John",
"last_name": "Snow",
"accepts_marketing": true
};
_rmData.push(['track', eventType, data]);
//Sending a custom event based on visitor's action on the website
var eventType = 'site-search';
var data = {
"searchKeyword": "Red shorts",
"result_1_title": "Swim Short",
"result_1_image": "http://www.example.com/swim_shorts.png"
};
_rmData.push(['track', eventType, data]);
When sending events you can choose to send eCommerce-related events or you can choose to send any custom event with custom properties.
Product view events
For client-side library examples switch to "javascript" examples
//Example code for productView event
var _rmData = _rmData || [];
_rmData.push(['productView', {
productId: '1112222',
productCategories: ['Men / Shorts', 'Men / Swimwear']
}]);
To let Remarkety know that a visitor viewed a particular product, for using in the "Browse Abandonment" automation or product recommendations,
you should send the productView
event with the properties listed below.
These properties should match the product id as received from the products feed.
Property name | description | required |
---|---|---|
productId | The product id that the visitor viewed. | Yes |
productCategories | List of categories that this product attached to. | No |
E-Commerce Event Types
Following is a list of e-commerce Event Types and their JSON format. Each event type has several mandatory fields, which must by included in the JSON. The rest are optional, but the more data you send the more accurate Remarkety can be in analyzing the data and communicating with your customer.
The event type must be specified in the x-event-type
header.
customers/create
{
"accepts_marketing": true,
"birthdate": "1997-02-26",
"created_at": "2012-02-15T15:12:21-05:00",
"default_address": {
"country_code": "USA",
"region": "MO",
"zip": "45415-3423",
"city": "Kansas City",
"street": "4647 Sunset Drive",
"phone": "1-923-555-5555"
},
"email": "guy@remarkety.com",
"first_name": "Guy",
"last_name": "Harel",
"gender": "M",
"groups": [
{
"id": 1,
"name": "VIP Customers"
}
],
"id": 1234,
"rewards": {
"points": 10
},
"tags": [
"tag1",
"tag2"
],
"updated_at": "2012-02-15T15:12:21-05:00"
}
Used to inform Remarkety about customers being created or updated.
Mandatory Fields
Field | Data type | Description |
---|---|---|
email |
string | Email must be valid |
Optional Fields
Field | Data type | Description | Default Value |
---|---|---|---|
accepts_marketing |
Boolean | If the user did not explicitly opt in or out on the website, send null here. Check your account settings to determine whether unknown value allows sending emails to the customers by default or not |
null (Unknown) |
created_at |
Date | The registration date of the customer to your website. | Current time |
tags |
Array of Strings | [] | |
append_tags |
boolean | If the contact already exists in Remarkety, pass true to append new tags instead of replacing existing tags |
false |
gender |
M/F |
customers/update
Same format as customers/create. Used to inform Remarkety about a customer update.
If the customer has changed her email address, make sure to send a valid id
. Remarkety will then update the
customer record based on this id. Otherwise, a new customer might be created with the new email.
orders/create
{
"created_at": "2012-02-15T15:12:21-05:00",
"currency": "USD",
"customer": {
"accepts_marketing": true,
"birthdate": "1997-02-26",
"created_at": "2012-02-15T15:12:21-05:00",
"default_address": {
"country": "United States",
"country_code": "USA",
"province_code": "MO",
"zip": "45415-3423",
"phone": "1-923-555-5555"
},
"email": "guy@remarkety.com",
"first_name": "Guy",
"gender": "M",
"groups": [
{
"id": 1,
"name": "VIP Customers"
}
],
"id": 1234,
"info": {},
"last_name": "Harel",
"updated_at": "2012-02-15T15:12:21-05:00",
"tags": "tag1,tag2",
"title": "Mr.",
"verified_email": true
},
"discount_codes": [
{
"code": "10OFF",
"amount": 20,
"type": "fixed_amount"
}
],
"email": "guy@remarkety.com",
"fulfillment_status": "string",
"id": 1234,
"line_items": [
{
"product_id": 1234,
"quantity": 1,
"sku": "SKU1234",
"name": "Blue Shirt, Size S",
"url": "https://my.cool.store/catalog/cool-gadget.html",
"image": "https://my.cool.store/images/cool-gadget.jpg",
"title": "Shirt",
"variant_title": "Blue",
"vendor": "Castro",
"price": 100,
"taxable": true,
"tax_lines": [
{
"title": "VAT",
"price": 18,
"rate": 0.18
}
],
"added_at": "2012-02-15T15:12:21-05:00",
}
],
"note": "Please don't break this!",
"shipping_lines": [
{
"title": "Fedex 2-day",
"price": 20,
"code": "fedex-2-day"
}
],
"status": {
"code": "S",
"name": "Shipped"
},
"financial_status": {
"code": "S",
"name": "Shipped"
},
"subtotal_price": 100,
"tax_lines": [
{
"title": "VAT",
"price": 18,
"rate": 0.18
}
],
"taxes_included": true,
"test": true,
"total_discounts": 20,
"total_line_items_price": 100,
"total_price": 100,
"total_shipping": 20,
"total_tax": 18,
"total_weight": 150,
"updated_at": "2012-02-15T15:12:21-05:00",
"channel": "POS"
}
Used to inform Remarkety about a new order in the system. Send us much information as possible here.
Note that the order
information is a nested object which also includes information about the customer
and lineitems
.
Mandatory fields
Field | Data type | Description |
---|---|---|
id |
String | The order id in your backoffice |
created_at |
Datetime string (with timezone) | Order creation date. |
customer.accepts_marketing |
Boolean | Is the customer opted in to marketing emails |
customer.created_at |
Datetime string (with timezone) | The time this customer was created |
customer.updated_at |
Datetime string (with timezone) | The time this customer was last updated |
customer.email |
Valid email | The email associated with the customer. |
lineitems[].product_id |
String | Your backoffice's product id |
lineitems[].quantity |
Numeric | The amount of this item in the order |
lineitems[].sku |
String | The SKU of this item |
lineitems[].name |
String | The name of the product to be displayed to the user |
lineitems[].url |
URL | A link to this item's product page in your store |
lineitems[].image |
URL | URL of the image of this item or product |
lineitems[].price |
Numeric | The price of this item in this specific order |
status.name |
String | The name of the order status |
subtotal_price |
Numeric | Order subtotal |
total_discounts |
Numeric | The total of all discounts applied. This should be a positive number. |
total_shipping |
Numeric | Shipping costs for this order |
total_tax |
Numeric | Tax added to this order |
total_price |
Numeric | The total that the customer was charged for this order |
orders/update
Same format as orders/create. Inform Remarkety about an order being updated (status changed, products changed, etc)
products/create
{
"body_html": "This is an <strong>awesome</strong> product!",
"categories": [
{
"code": 12,
"name": "Men's clothing"
}
],
"created_at": "2012-02-15T15:12:21-05:00",
"id": 1234,
"image": {
"id": 1111,
"product_id": 1234,
"created_at": "2012-02-15T15:12:21-05:00",
"updated_at": "2012-02-15T15:12:21-05:00",
"src": "https://my.cool.store/image1.jpg",
"variant_ids": [
null
]
},
"images": [
{
"id": 1111,
"product_id": 1234,
"created_at": "2012-02-15T15:12:21-05:00",
"updated_at": "2012-02-15T15:12:21-05:00",
"src": "https://my.cool.store/image1.jpg",
"variant_ids": [
null
]
}
],
"options": [
{
"id": 4444,
"name": "Color",
"values": [
"red"
]
}
],
"published_at": "2012-02-15T15:12:21-05:00",
"product_exists": true,
"sku": "SKU1234",
"tags": "cool,new",
"title": "Cool Gadget",
"updated_at": "2012-02-15T15:12:21-05:00",
"url": "https://my.cool.store/catalog/cool-gadget.html",
"variants": [
{
"barcode": "string",
"currency": "USD",
"created_at": "2012-02-15T15:12:21-05:00",
"fulfillment_service": "string",
"id": 12345,
"image": "https://my.cool.store/images/image1.jpg",
"inventory_quantity": 12,
"price": 199.23,
"product_id": 1234,
"sku": "SKU1234",
"taxable": true,
"title": "Blue Shirt",
"option1": "Blue",
"updated_at": "2012-02-15T15:12:21-05:00",
"requires_shipping": true,
"weight": 150,
"weight_unit": "g"
}
],
"vendor": "Samsung"
}
Inform Remarkety about a new product.
What are product variants?
A variant is a "subtype" of a more generic product. For example, for the product "Nike Air Jordan", you would have different variants such as White / Size 12 or Black / Size 12.
For an iPhone 7, you might have the Silver / 32GB and the Gold / 256GB variants.
If you don't have such variants (for example: you sell A Chair), then the product would have exactly one variant, with most of the properties (SKU, id, etc) being duplicated into the variant.
Mandatory fields
Field | Data type | Description |
---|---|---|
id |
String | The product id in your backoffice |
sku |
String | The product SKU |
created_at |
Datetime string (with timezone) | The time this product was created |
image.src |
URL | URL of the main product image thumbnail |
product_exists |
Boolean | Is this product currently for sale in the store? |
title |
String | Short title describing the product |
url |
URL | Link to the product page on the store website |
vendor |
String | Name of the product vendor/manufacturer |
variants[].id |
String | The backoffice ID of this specific variant |
variants[].image |
URL | The image URL of this variant |
variants[].inventory_quantity |
Numeric | # of items youhave in stock |
variants[].product_id |
Numeric | The id of this variant's parent |
variants[].sku |
String | The SKU of this product variant |
variants[].title |
String | The title of this specific variant |
products/update
Similar to products/create, inform Remarkety about a product that's been updated.
products/delete
Products cannot be deleted, but they can be updated so that they are no longer available for recommendations.
To do this, update the product with product_exists=false
.
carts/create
{
"abandoned_checkout_url": "https://my.cool.store/carts/2341234sdfasdf",
"billing_address": {
"country": "United States",
"country_code": "USA",
"province_code": "MO",
"zip": "45415-3423",
"phone": "1-923-555-5555"
},
"accepts_marketing": true,
"cart_token": "cart_abc",
"created_at": "2012-02-15T15:12:21-05:00",
"currency": "USD",
"customer": {
"accepts_marketing": true,
"birthdate": "1997-02-26",
"created_at": "2012-02-15T15:12:21-05:00",
"default_address": {
"country": "United States",
"country_code": "USA",
"province_code": "MO",
"zip": "45415-3423",
"phone": "1-923-555-5555"
},
"email": "guy@remarkety.com",
"first_name": "Guy",
"gender": "M",
"groups": [
{
"id": 1,
"name": "VIP Customers"
}
],
"id": 1234,
"info": {},
"last_name": "Harel",
"updated_at": "2012-02-15T15:12:21-05:00",
"tags": "tag1,tag2",
"title": "Mr.",
"verified_email": true
},
"discount_codes": [
{
"code": "10OFF",
"amount": 20,
"type": "fixed_amount"
}
],
"email": "guy@remarkety.com",
"fulfillment_status": "string",
"id": 1234,
"line_items": [
{
"product_id": 1234,
"quantity": 1,
"sku": "SKU1234",
"name": "Blue Shirt, Size S",
"title": "Shirt",
"variant_title": "Blue",
"vendor": "Castro",
"price": 100,
"taxable": true,
"tax_lines": [
{
"title": "VAT",
"price": 18,
"rate": 0.18
}
],
"added_at": "2012-02-15T15:12:21-05:00"
}
],
"note": "Please don't break this!",
"shipping_address": {
"country": "United States",
"country_code": "USA",
"province_code": "MO",
"zip": "45415-3423",
"phone": "1-923-555-5555"
},
"shipping_lines": [
{
"title": "Fedex 2-day",
"price": 20,
"code": "fedex-2-day"
}
],
"subtotal_price": 100,
"tax_lines": [
{
"title": "VAT",
"price": 18,
"rate": 0.18
}
],
"taxes_included": true,
"total_discounts": 20,
"total_line_items_price": 100,
"total_price": 100,
"total_shipping": 20,
"total_tax": 18,
"total_weight": 150,
"updated_at": "2012-02-15T15:12:21-05:00"
}
When a user browses the site, they will start (hopefully) adding products to the cart. As long as the cart did not turn
into an actual order, you should use the carts
endpoints in order to let Remarkety know about them. If the cart is
anonymous (most are...), the customer
and emails
fields can be sent as null
.
Mandatory fields
Field | Data type | Description |
---|---|---|
abandoned_checkout_url |
URL | This URL should lead to the cart contents. Optimally, this URL should work on any browser. |
accepts_marketing |
Boolean | Does this customer accept email marketing? |
created_at |
Datetime string (with timezone) | Time that this cart was originally created |
currency |
String | 3-letter code of this cart's currency |
customer |
Boolean | If this cart is not a guest (anonymouns) cart, send the customer information here. Otherwise set to null |
customer.accepts_marketing |
Boolean | Does this customer accept marketing? |
customer.email |
The email address of this customer | |
customer.id |
String | The backoffice customer id |
email |
String | For guest checkouts, this can be set even if there is no registered customer. If unknown, set as null |
id |
String | The cart ID in the backoffice. Used when updating (and deleting) the cart. |
title |
String | Short title describing the product |
line_items |
Array | The products in the cart. Same as in the order |
total_discounts |
Numeric | Discounts given for this cart |
total_price |
Numeric | Total price of this cart, incl tax, discounts and shipping |
updated_at |
Datetime (with timezone) | Last time this cart was updated. Very important for timing the emails. |
carts/update
Same format as carts/create. Make sure to keep the same id
so that carts don't get duplicated.
newsletter/subscribe
{
"email": "shopper@gmail.com",
"first_name": "Edgar",
"last_name": "Poe",
"sms_phone_number_e164": "+12025550137",
"customerId": "111112",
"tags": ["politics", "sport"],
"double_optin_required": false
}
var storeId = "AAABBB"; // Unique per remarkety account - get yours from the API setting page
var eventType = "newsletter/subscribe"; // See "Event types"
var data = JSON.stringify({
"email": "shopper@gmail.com",
"first_name": "Edgar",
"last_name": "Poe",
"sms_phone_number_e164": "+12025550137",
"customerId": "111112",
"tags": ["politics", "sport"]
});
// If run client-side, use our tracking script:
var _rmData = _rmData || [];
_rmData.push(['setStoreKey', storeId]); // Only needs to be run once on the page
_rmData.push(['track', eventType, data]);
// End client-side code
Send this event to inform Remarkety of a customer's explicit wish to receive email newsletters or SMS blasts.
When Remarkety received this event, we will send an opt-in confirmation based on the account settings and the double_optin_required
field.
Make sure you send the sms_phone_number_e164
field as an E.164 formatted phone number.
newsletter/unsubscribe
{
"email": "shopper@gmail.com"
}
var storeId = "AAABBB"; // Unique per remarkety account - get yours from the API setting page
var eventType = "newsletter/unsubscribe"; // See "Event types"
var data = JSON.stringify({
"email": "shopper@gmail.com"
});
// If run client-side, use our tracking script:
var _rmData = _rmData || [];
_rmData.push(['setStoreKey', storeId]); // Only needs to be run once on the page
_rmData.push(['track', eventType, data]);
// End client-side code
Inform Remarkety that a shopper wishes to unsubscribe. We will add this email to our suppression list, so that if the
customer record is updated from different sources, we will not send marketing materials to this user, even if the
customer record contains accepts_marketing: true
.
If you would like to resubscribe the customer after an unsusbcribe event, send an explicit newsletter/subscribe
event.
Custom Events
For client-side library examples switch to "javascript" examples
// Send a site-search event
var _rmData = _rmData || [];
//Identify using email address
var customerEmail = "<Your customer email here>";
_rmData.push(['setCustomerEmail', customerEmail]);
var eventType = 'site-search';
var data = {
"searchKeyword": "Red shorts",
"result_1_title": "Swim Short",
"result_1_image": "http://www.example.com/swim_shorts.png"
};
_rmData.push(['track', eventType, data]);
// On a different page - send a room booking event
var _rmData = _rmData || [];
var customerEmail = "<Your customer email here>";
_rmData.push(['setCustomerEmail', customerEmail]);
var eventType = 'room-booked';
var data = {
"lodging": {
"name": "Kempinski Seychelles Resort",
"stars": 5,
"type": "resort",
"image": "https://r-ec.bstatic.com/images/hotel/max1024x768/169/16951276.jpg"
},
"guest": {
"reservation_name": "John and Jane Doe"
}
};
_rmData.push(['track', eventType, data]);
In addition to the built-in eCommerce events, you can use our client-side tracking script to send custom events as well. These events, with their associated properties, can be used to trigger automations inside Remarkety.
Top-level properties can be used to filter the events triggering the automation. Any and all properties sent in the event can be used inside the email template triggered by this event.
See some usage examples on the right.
Please note: When sending any client-side event (including custom events), the user must first be identified. We currently don't track events that were sent without a user being identified first. Please read here on how to identify users.
Receiving Events
In many cases, in addition to sending events to Remarkety, you'd also like to be informed on actions that Remarkety performs or knows about, such as email sends, opens, clicks and unsubscribes.
Remarkety supports publishing these events via JSON webhooks. You supply an SSL (https) endpoint, and we will POST events to that endpoint as detailed below.
Setup
Setup your receiving endpoint in your Remarkety Settings page.
Webhook Structure
POST /endpoint.yoursite.com HTTP/1.1
X-Event-Hmac-SHA256: 4293d6f6232a9d346fbd5da0ba0c9a86851675507b750509373f227414f3cb98
X-Event-Topic: newsletter/subscribed
Content-Type: application/json
User-Agent: Remarkety
Cache-Control: no-cache
{
"email": "john@doe.com",
"ip_signup": "10.0.0.1",
"ip_opt": "10.0.0.1",
"properties": {
"first_name": "John",
"last_name": "Doe",
"campaign": "Lead gen #3"
}
}
Our POST to your endpoint will have the structure shown on the right:
Headers
Header | Purpose |
---|---|
X-Event-Hmac-SHA256 |
Message digest for authentication - see below |
X-Event-Topic |
The event topic, or type |
Body
The request body will contain JSON-formatted text as detailed in the topics below.
Authentication
<?php
define('SHARED_SECRET', '<shared secret>');
function verify_webhook($data, $hmac_header)
{
$calculated_hmac = base64_encode(hash_hmac('sha256', $data, SHARED_SECRET, true));
return hash_equals($hmac_header, $calculated_hmac);
}
$hmac_header = $_SERVER['HTTP_X_EVENT_HMAC_SHA256'];
$data = file_get_contents('php://input');
$verified = verify_webhook($data, $hmac_header);
if ($verified) {
$payload = json_decode($data);
$eventTopic = $_SERVER['HTTP_X_EVENT_TOPIC'];
} else {
error_log("Invalid signature");
}
In order to verify that the request came from Remarkety, you can use the X-Event-Hmac-SHA256 header, which includes a digital signature of the message contents (body only - not including the headers). We create the signature using the Shared Secret provided in the app. On the right is a PHP example on how to verify the signature.
Retries and Errors
We expect your endpoint to respond within 5 seconds with a 2xx return code. In case the request exceeds the timeout or returns with a 5xx error code, we will continue retrying in increasing intervals, for 2 hours. If we fail after 2 hours, we will stop retrying and will send an email to the account administrator.
Event Topics and Payloads
Common fields:
Field | Purpose |
---|---|
timestamp | The timestamp of the event itself |
The recipient's email address (cc or bcc will not trigger events) | |
campaign_name | The plain-text name of the campaign that triggered this email |
campaign_group | The plain-text name of the campaign group |
campaign_id | The internal Remarkety id of the campaign |
umk | A unique identifier per email message |
useragent | The useragent header as sent by the recipient's email client |
ip | The ip address of the recipient |
email/sent
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 13118,
"umk": "5acf31d0b22410.937575625acf31d0b"
}
Sent when an email is sent to the recipient.
email/clicked
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 13118,
"umk": "5acf31d0b22410.937575625acf31d0b",
"link_url": "https://my.website.com/some-page",
"useragent": "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)",
"ip": "1.2.3.4"
}
Sent when a recipient clicks on a link inside an email
email/opened
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 13118,
"umk": "5acf31d0b22410.937575625acf31d0b",
"useragent": "Mozilla/5.0 (Windows NT 5.1; rv:11.0) Gecko Firefox/11.0 (via ggpht.com GoogleImageProxy)",
"ip": "1.2.3.4"
}
Sent when an email is opened. This is not 100% correct because open tracking is done via images, which are sometimes blocked and sometimes opened by the receiving mail server and not the actual, human recipient.
email/delivered
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 13118,
"umk": "5acf31d0b22410.937575625acf31d0b"
}
Sent when the recipient's email server acknowledges receipt of the message. This does not necessarily mean that the email reached the inbox.
email/bounced
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 13118,
"umk": "5acf31d0b22410.937575625acf31d0b",
"reason": "554 5.4.14 Hop count exceeded - possible mail loop ATTR34 [SN1NAM04FT063.eop-NAM04.prod.protection.outlook.com]",
"soft_bounce": true
}
Sent when the receiving email server does not accept the message. May signal a soft bounce (for example: mailbox full) or a hard bounce (address doesn't exist).
email/spam
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 13118,
"umk": "5acf31d0b22410.937575625acf31d0b"
}
Sent when an email is marked as spam. Not all email servers send back a spam notification, gmail in particular does not.
email/unsubscribed
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 13118,
"umk": "5acf31d0b22410.937575625acf31d0b"
}
newsletter/subscribed
{
"timestamp": "2018-04-12T12:50:00+00:00",
"optin_timestamp": "2018-04-12T12:55:00+00:00",
"email": "john@doe.com",
"signup_ip" : "1.2.3.4",
"optin_ip": "1.2.3.4"
}
Sent when a customer's marketing preferences changes to "yes", either by signing up to a popup, by an API call, or by an
admin in the app. signup_ip
(optional) is the IP address used to initially sign up the user (might a server IP if this was an API call).
optin_ip
(optional) is the IP used to click the "confirm email" link in the double opt-in email, if sent.
sms/sent
{
"timestamp": "2020-07-19T10:12:15.296Z",
"email": "john@doe.com",
"campaign_name": "Welcome Campaign",
"campaign_id": "111112",
"umk": "5acf31d0b22410.937575625acf31d0b",
"characters_count": 92,
"body": "Sample message content.",
"to": "+15417540000",
"from": "+15417541111",
"is_test": false,
"recipient_country_code": "US"
}
Sent when an SMS is sent to the recipient. campaign_id, campaign_name and umk are all optional fields, if the massage was sent by a system message (double opt-in confirmation, unsubscribe confirmation, etc.) these fields will not get included in the JSON.
sms/clicked
{
"timestamp": "2020-07-19T10:12:15.296Z",
"to": "+15417540000",
"from": "+15417541111",
"email": "john@doe.com",
"campaign_name": "Welcome Campaign",
"campaign_id": "111112",
"umk": "5acf31d0b22410.937575625acf31d0b",
"is_test": false,
"ip": "1.1.1.1",
"user_agent": "Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/83.0.4103.61 Safari/537.36",
"url": "https://www.remarkey.com"
}
Sent when an SMS link with Remarkety's short URL was clicked. campaign_id, campaign_name and umk are all optional fields, if the massage was sent by a system message (double opt-in confirmation, unsubscribe confirmation, etc.) these fields will not get included in the JSON.
sms/replied
{
"to": "+15417540000",
"from": "+15417541111",
"body": "Message content body"
}
Triggered when someone sends a message to one of your phone numbers that purchased via Remarkety.
sms/unsubscribed
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"campaign_name": "Abandoned cart #1",
"campaign_id": 11111,
"umk": "5acf31d0b22410.937575625acf31d0b",
"phone_number": "+15417543010",
"reason": "Unsubscribed via link"
}
Sent whenever an SMS contact is unsubscribed, by replying to the account's incoming number or by clicking an unsubscribe link. campaign_id, campaign_name and umk are all optional fields, if the contact unsubscribed by replying to your incoming number, these fields will not get included in the JSON.
email-suppression/added
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"client_ip": "1.1.1.1",
"type": "unsubscribed",
"reason": "Recipient unsubscribed"
}
Sent when an email is added to the suppression list and will not receive any marketing emails from now on.
The email address can be added multiple times to the suppression list with different suppression types.
Suppression types
- unsubscribed
- manually_suppressed
- hard_bounce
- soft_bounce
- spam_complaint
- pending_opt_in
- domain_suppressed
- deleted
- suspected_as_spam
email-suppression/removed
{
"timestamp": "2018-04-12T12:50:00+00:00",
"email": "john@doe.com",
"client_ip": "1.1.1.1",
"type": "unsubscribed",
"reason": "Customer re-subscribed"
}
Sent when an email is removed from the suppression list.
The email address can be added multiple times to the suppression list with different suppression types, when a specific type is removed the email might still be in the list with a different suppression type.
Errors
The API may return the following error codes:
Error Code | Meaning |
---|---|
400 | Bad Request -- The request is malformed or is missing mandatory fields |
401 | Unauthorized -- Wrong API key |
403 | Forbidden |
404 | Not Found |
406 | Not Acceptable -- You requested a format that isn't json |
418 | I'm a teapot |
429 | Too Many Requests -- You are making too many requests in a limited time |
500 | Internal Server Error -- We had a problem with our server. Try again later. |
503 | Service Unavailable -- We're temporarily offline for maintenance. Please try again later. |