NAV Navbar
Logo
shell

Authentication

# With shell, you can just pass the correct header with each request
$ curl "api_endpoint_here" \
  -H "X-ApiKey: YOUR_API_KEY"

CM Commerce provides three types of Authentication, each with its own use case. These are:

  1. API Key: For store owners or someone affiliated with a store owner (typically a developer). This is the fastest way to get access to a store’s data and actions;
  2. OAuth: For Partner Apps that wish to authenticate with their users' accounts in CM Commerce. This gives access to CM Commerce on behalf of one or more users.
  3. HMAC: For Partner Apps only. Used for accessing the Partner App API.

API Key Authentication

All paths should prefixed with https://commerce.campaignmonitor.com/api/v1 and will need the following HTTP header:

X-ApiKey: YOUR_API_KEY

OAuth

CM Commerce implements the Authorization Code Grant of the OAuth v2.0 standard, with PoP Tokens (Proof of Possession).

The standard is followed to spec, except for these cases:

In general terms, the OAuth process involves a Partner App getting authorization from the User to access their account. When authorized, an Access Token must be requested from CM Commerce. This token can then be included in requests to CM Commerce to Authenticate & Authorize the App to access a User’s account.

This section has the following structure:

Terminology

Issuing Access Token

CM Commerce uses the Authorization Code Grant flow from OAuth 2.0 to issue Access Tokens. This involves three requests:

  1. Redirecting the User to CM Commerce, where they can authorize the Partner App
  2. CM Commerce redirects the User back to the Partner App, including a code
  3. The Partner App exchanges the code for an access_token

These three steps are described in detail below.

Step 1: Get User Authorization

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/oauth/authorize" \
  -G \
  -X GET \
  -d client_id=57b5aa3b046abfb053d80b52 \
  -d redirect_uri=https%3A%2F%2Fwww.partner-app.com%2Fcallback \
  -d scope=read_webhook%20write_newsletter_email \
  -d state=2034590283

To begin the OAuth flow, the User is redirected to CM Commerce’s authorize endpoint:

https://commerce.campaignmonitor.com/oauth/authorize

Including the following parameters in the URL query string:

Parameter Details
client_id: string
The Partner App’s ID. Should be provided by CM Commerce.
redirect_uri: string
Where the User will be redirected. Must match the value saved for the Partner App.
scope: string, optional
The scopes that the App wishes to access on behalf of the User. Space separated values.
state: string
A random string, at least 10 characters long, that is unique. This will be passed on to redirect_uri when the User accepts or rejects the authorization, and should be validated to be the same.

The User will be required to log-in to CM Commerce as needed.

If all required parameters are present and valid, the User can then review what permissions (scopes) are requested by which App. Conversely, any missing or invalid parameters will instead show an error page with a description of each problem.

At this point the User can Authorize or Reject the Authorization Request. When rejecting, the User will be redirected to redirect_uri with the following parameters in the URL query string:

Parameter Details
error: string
As per spec, will have the value “access_denied”.
error_description: string
Will be “The user refused to authorize your App.”.
state: string
Will be the same state value sent on the first request.

This ends the OAuth flow prematurely.

Conversely, when the User authorizes the App, an authorization code is generated that is bound to that User, the requested scopes and redirect_uri. The User is then redirected to redirect_uri with the code in the query params, and the same state that was received in the request, starting step 2.

Step 2: Receive Authorization Code

# EXAMPLE REQUEST
$ curl "https://www.partner-app.com/callback" \
  -G \
  -X GET \
  -d code=f85b6db85f79310aee955bf104caa2dfcb50e6a565f8f8837f44c6ded306 \
  -d state=2034590283

At this point the User has authorized the Partner App to access their account on their behalf. They will be redirected to redirect_uri and the URL query will include the following parameters:

Parameter Details
code: string
A 60 character hex string. This code represents the user’s authorization and must be used to get an Access Token in step 3. It is single-use and short-lived, expiring in 3 minutes.
state: string
Must be the same value sent in the first request.

The state param’s value should be validated. It is exactly the same value as was sent in the first step. This ensures that the User is coming from the original request, and that the code isn’t from an earlier request intercepted by an attacker.

The code can now be used to request an Access Token from CM Commerce.

Step 3: Exchange Code for Access Token

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/oauth/access-token" \
  -H "Authorization: Basic NTdiNWFhM2IwNDZhYmZiMDUzZDgwYjUyOndhdGNodS1sb29raW4tYXQ=" \
  -H "Content-Type: application/x-www-form-urlencoded" \
  -X POST \
  -d code=f85b6db85f79310aee955bf104caa2dfcb50e6a565f8f8837f44c6ded306 \
  -d redirect_uri=https%3A%2F%2Fwww.partner-app.com%2Fcallback

EXAMPLE RESPONSE

{
  "access_token": "0aee955bf104caa2dfcb50e6a565f8",
  "token_type": "pop"
}

To issue an access_token, the received code must be POSTed to CM Commerce.

This request must use HTTPS and be Authenticated using Basic Access Authentication using the App’s ID as the username and the App’s Client Secret as password. Both are provided by CM Commerce.

The POST body must have the application/x-www-form-urlencoded MIME type and the following parameters:

Parameter Details
code: string
The 60 character code received in Step 2 of the flow.
redirect_uri: string
The Partner App’s redirect URI. It must be the exact same value as used to generate the code.

If the App is successfully authenticated, the redirect_uri matches the App and the code is valid, CM Commerce will return a new access_token in JSON:

Parameter Details
access_token: string
A 30 character token bound to the User and requested Scopes. Must be kept secret.
token_type: string
Indicate’s the token’s type. Is “pop”.

This access_token can then be used to authorize any client when accessing the User’s data.

Authorizing Requests

As mentioned above, CM Commerce issues PoP Access Tokens. These add a layer of security on top of Bearer tokens, requiring Partner Apps to sign every request using their Client Secret.

Reading the Tokens draft & JWS RFC will provide deeper understanding of what’s going on, but to get started quickly we’d recommend using a lib for the language being used. Some examples:

  1. JavaScript -> npm install jws
  2. Ruby -> gem install jwt

If the language used isn’t listed, get in touch with us and we’ll help out finding an appropriate alternative.

Generating the PoP Token

# Ruby
require 'jwt'

client_secret = 'partner-app-client-secret'
payload = { at: 'pop-access-token', ts: Time.now.to_i }

pop_token = JWT.encode payload, client_secret, 'HS256'
# > "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdCI6IjEyMzQ1NiIsInRzIjoxMjM0NTY3OH0.J6DUAy9TopLOfIJHFbY2BNDankWID9ZvJ-ylHoV_a6k"
// JavaScript
const jws = require('jws');

const clientSecret = 'partner-app-client-secret';
const header = { typ: 'JWT', alg: 'HS256' };
const payload = { at: 'pop-access-token', ts: Math.floor(Date.now() / 1000) };

const popToken = jws.sign({ header, payload, secret: clientSecret });
// > 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdCI6IjEyMzQ1NiIsInRzIjoxMjM0NTY3OH0.Pocf1CzRha25nwCfoZynProYLcV1UE5SlcRGa3qzZXo'

As a first step, the Access Token received from CM Commerce must be included in an Object (Hash for Ruby) at the key at. In that object, the current Unix time must be defined at the key ts. This timestamp is validated by CM Commerce to be within 3 minutes of current time, in an effort to prevent header reuse by attackers.

This object is then signed with HMAC, generating 3 Base64 encoded strings, separated by a period. This is the PoP Token.

We support three HMAC algorithms, HS256, HS384 and HS512.

# Example authorized request
$ curl https://commerce.campaignmonitor.com/api/v1 \
  -H "Authorization: PoP eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJhdCI6IjEyMzQ1NiIsInRzIjoxMjM0NTY3OH0.Pocf1CzRha25nwCfoZynProYLcV1UE5SlcRGa3qzZXo

The PoP Token can then be included in a request’s Authorization header, prefixed with the string “PoP”.

The server then decodes the PoP Token and validates the signature to both Authenticate the Partner App and Authorize its access to a User’s account through the included Access Token.

Scopes

Below is a table of the recognized scopes. Scopes that are prefixed with write_ provide read & write access, while those with the read_ prefix provide access to read-only endpoints.

HMAC

# Ruby
require 'jwt'

client_secret = 'partner-app-client-secret'
payload = { iss: '57b5aa3b046abfb053d80b52' }

pop_token = JWT.encode payload, client_secret, 'HS256'
# > "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1N2I1YWEzYjA0NmFiZmIwNTNkODBiNTIifQ.sxd8uG4EkeIXHsIIVELrfGTIZcaTFE9a9YY-8HGHuOQ"
// Javascript
const jws = require('jws');

const clientSecret = 'partner-app-client-secret';
const header = { typ: 'JWT', alg: 'HS256' };
const payload = { iss: '57b5aa3b046abfb053d80b52' };

const popToken = jws.sign({ header, payload, secret: clientSecret });
// > 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1N2I1YWEzYjA0NmFiZmIwNTNkODBiNTIifQ.sxd8uG4EkeIXHsIIVELrfGTIZcaTFE9a9YY-8HGHuOQ'
# Example authorized request
$ curl https://commerce.campaignmonitor.com/api/v1/partners/ \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1N2I1YWEzYjA0NmFiZmIwNTNkODBiNTIifQ.sxd8uG4EkeIXHsIIVELrfGTIZcaTFE9a9YY-8HGHuOQ

This authentication type is used exclusively when accessing the Partner Apps API because it authenticates a Partner only, not a User. It is used on signed JSON Web Tokens with a JSON Web Signature.

The token must have an iss entry set to the Partner App’s ID. Then, it must be signed with the Client Secret and added to the Authorization header of each request, using the Bearer schema.

All requests to the Partner Apps API must be authorized this way.

Coupons

Services related to retreiving coupons using the Coupons API

All Coupons

# DEFINITION
GET https://commerce.campaignmonitor.com/api/v1/coupons

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/coupons" \
  -H "X-ApiKey: YOUR_API_KEY"

EXAMPLE RESPONSE

{
   "meta":{
      "_links":{
         "next":"...",
         "prev":"...",
         "last":"...",
         "first":"..."
      }
   },
   "data":[
      {
         "upsellType":"coupon",
         "active":true,
         "title":"Lorem ipsum",
         "freeShipping":true,
         "amount":"10",
         "couponCode":"55G2-DHM0-50NN"
      },
      {
         "upsellType":"coupon",
         "active":true,
         "title":"Lorem ipsum",
         "freeShipping":true,
         "amount":"10",
         "couponCode":"54G2-DHM0-50NL"
      }
   ]
}

https://commerce.campaignmonitor.com/api/v1/coupons

Get a list of all coupons

Get a coupon

# DEFINITION
GET https://commerce.campaignmonitor.com/api/v1/coupons/1a2b3c4d

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/coupons/1a2b3c4d" \
  -H "X-ApiKey: YOUR_API_KEY"

EXAMPLE RESPONSE

{
   "upsellType":"coupon",
   "active":true,
   "title":"Lorem ipsum",
   "freeShipping":true,
   "amount":"10",
   "couponCode":"55G2-DHM0-50NN"
}

https://commerce.campaignmonitor.com/api/v1/coupons/{COUPON_ID}

A single coupon with all of its details

Arguments

Argument Details
id: string, required
String based id of the coupon supplied in the response from the send of a receipt.

Delete a coupon

# DEFINITION
DELETE https://commerce.campaignmonitor.com/api/v1/coupons/1a2b3c4d

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/coupons/1a2b3c4d" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -X DELETE

https://commerce.campaignmonitor.com/api/v1/coupons/{COUPON_ID}

Arguments

Argument Details
id: string, required
String based id of the coupon supplied in the response from the send of a receipt.

Mark coupon as used

# DEFINITION
PUT https://commerce.campaignmonitor.com/api/v1/coupons/1a2b3c4d/use

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/coupons/1a2b3c4d/use" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -X PUT
  -d '{
    "reference": "1234",
    "amount": 123,
    "currency": "USD"
  }'

EXAMPLE RESPONSE

{
   "upsellType":"coupon",
   "active":true,
   "title":"Lorem ipsum",
   "freeShipping":true,
   "amount":"10",
   "couponCode":"55G2-DHM0-50NN",
   "usage": {
     "usedAt": "1410788324",
     "order": {
       "reference": "1234",
       "amount": 123,
       "currency": "USD"
     }
   }
}

https://commerce.campaignmonitor.com/api/v1/coupons/{COUPON_ID}/use

Arguments

Argument Details
id: string, required
String based id of the coupon supplied in the response from the send of a receipt.
reference: string, required
String based id of the generated order by the coupon.
amount: float, required
Amount of the generated order.
currency: string, required
Currency of the amount generated.

Products

Services related to sending product updates using the Products API. These endpoints must be used to send updates about products for our reccommendation engine.

Create product

# EXAMPLE REQUEST (SINGLE PRODUCT)
$ curl "https://commerce.campaignmonitor.com/api/v1/products" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X POST \
  -d '{
    "product_id": "ipa_12345",
    "type": "beer",
    "brand": "StefanoS",
    "title": "Refreshing IPA by StefanoS",
    "description": "This IPA is awesome and brought to you by the legendary StefanoS",
    "hidden": false,
    "url": "https://stefanos.beer/products/ipa_12345",
    "tags": [ "ipa", "beer", "refreshing" ],
    "images": [
      { "position": 1, "url": "https://stefanos.beer/img/ipa_12345_1.jpg" },
      { "position": 2, "url": "https://stefanos.beer/img/ipa_hej.jpg" }
    ],
    "variants": [
      { "price": 10.0 },
      { "price": 15.0 }
    ],
    "categories": [
      {
        "category_id": "category_1234",
        "title": "IPA category",
        "description": "A category of good IPAs",
        "url": "https://stefanos.beer/categories/category_1234"
      }
    ]
  }'
# EXAMPLE REQUEST (MULTIPLE PRODUCTS)
$ curl "https://commerce.campaignmonitor.com/api/v1/products" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X POST \
  -d '[{
    "product_id": "ipa_12345",
    "type": "beer",
    "brand": "StefanoS",
    "title": "Refreshing IPA by StefanoS",
    "description": "This IPA is awesome and brought to you by the legendary StefanoS",
    "hidden": false,
    "url": "https://stefanos.beer/products/ipa_12345",
    "tags": [ "ipa", "beer", "refreshing" ],
    "images": [
      { "position": 1, "url": "https://stefanos.beer/img/ipa_12345_1.jpg" },
      { "position": 2, "url": "https://stefanos.beer/img/ipa_hej.jpg" }
    ],
    "variants": [
      { "price": 10.0 },
      { "price": 15.0 }
    ],
    "categories": [
      {
        "category_id": "category_1234",
        "title": "IPA category",
        "description": "A category of good IPAs",
        "url": "https://stefanos.beer/categories/category_1234"
      }
    ]
  },
  {
    "product_id": "wheat_54321",
    "type": "beer",
    "brand": "StefanoS",
    "title": "Refreshing wheat beer by StefanoS",
    "description": "This lovely golden wheat is perfect on a hot Summer day.",
    "hidden": false,
    "url": "https://stefanos.beer/products/wheat_54321",
    "tags": [ "ipa", "beer", "refreshing" ],
    "images": [
      { "position": 1, "url": "https://stefanos.beer/img/wheat_54321.jpg" }
    ],
    "variants": [
      { "price": 5.0 }
    ],
    "categories": [
      {
        "category_id": "category_4321",
        "title": "Wheat category",
        "description": "A category of good wheat beers",
        "url": "https://stefanos.beer/categories/category_4321"
      }
    ]
  }]'

Create one or more new products [POST]

POST https://commerce.campaignmonitor.com/api/v1/products

Arguments

Main object (product)

Argument Details
brand: string, optional
The brand or vendor for the product, e.g. ‘Apple’.
categories: category array, optional
A list of categories that the product belong to.
description: string, optional
The description of the product, for example ‘A very nice soccer ball, updated for the needs of 2014.’.
hidden: boolean, optional
Indicates whether the product is currently hidden.
images: image array, optional
A list of images for the product.
product_id: string, required
The ID of the product.
tags: string array, optional
A list of tags for the product.
title: string, optional
The title of the product, for example ‘Soccer Ball 2014’.
type: string, optional
The type of the product, e.g. ‘ball’.
url: string, optional
The full or relative url for the product, for example ‘http://example.com/products/soccer-ball-2014’.
variants: variant array, optional
A list of product variants. The price of a product is always stored in a variant.

Category

Argument Details
category_id: string, required
The ID of the category.
description: string, optional
The description of the category.
title: string, optional
The title of the category, for example ‘Soccer Balls’
url: string, optional
The full or relative url for the category, for example ‘http://example.com/category/soccer-balls’.

Image

Argument Details
position: integer, optional
The position of the image compared to other images for the same product.
url: string, required
The url where the image is stored.

Variant

Argument Details
price: float, required
The price of the variant.

Update product

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/products/{product_id}" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X PUT \
  -d '{
    "product_id": "ipa_12345",
    "type": "beer",
    "brand": "StefanoS",
    "title": "Refreshing IPA by StefanoS",
    "description": "This IPA is awesome and brought to you by the legendary StefanoS",
    "hidden": false,
    "url": "https://stefanos.beer/products/ipa_12345",
    "tags": [ "ipa", "beer", "refreshing" ],
    "images": [
      { "position": 1, "url": "https://stefanos.beer/img/ipa_12345_1.jpg" },
      { "position": 2, "url": "https://stefanos.beer/img/ipa_hej.jpg" }
    ],
    "variants": [
      { "price": 10.0 },
      { "price": 15.0 }
    ],
    "categories": [
      {
        "category_id": "category_1234",
        "title": "IPA category",
        "description": "A category of good IPAs",
        "url": "https://stefanos.beer/categories/category_1234"
      }
    ]
  }'

Update a product [PUT]

PUT https://commerce.campaignmonitor.com/api/v1/products/{product_id}

Arguments

Delete product

Delete a product [DELETE]

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/products/{product_id}" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X DELETE'

DELETE https://commerce.campaignmonitor.com/api/v1/products/{product_id}

Product Reviews

Endpoints for getting data on existing Product Reviews from Customers.

List Product Reviews

Returns reviews from the most recently created.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/product-reviews?limit=2&page=2" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "57b5aa3b046abfb053d80b52",
      "title": "Awesome!",
      "comment": "Taste and texture were all on point! ++ would buy again.",
      "rating": 5,
      "productId": "123456789",
      "customerEmail": "happyguy@email.com",
      "archived": false,
      "visible": true,
      "isTest": false,
      "createdAt": "2016-11-30T10:20:00.000Z"
    },
    {
      "id": "57b5aa3b046abfb053d80b59",
      "title": "Quality Stuff",
      "comment": "Product was great, but shipping took two weeks.",
      "rating": 4,
      "productId": "65443335",
      "customerEmail": "mehdude@email.com",
      "archived": false,
      "visible": false,
      "isTest": false,
      "createdAt": "2016-11-20T00:00:00.000Z"
    }
  ],
  "meta": {
    "page": 2,
    "pages": 3,
    "total": 5,
    "limit": 2,
    "prevPage": "https://commerce.campaignmonitor.com/api/v1/product-reviews?page=1&limit=2",
    "nextPage": "https://commerce.campaignmonitor.com/api/v1/product-reviews?page=3&limit=2"
  }
}

List all Product Reviews [GET]

https://commerce.campaignmonitor.com/api/v1/product-reviews

OAuth Scopes: read_product_reviews, write_product_reviews

Query Parameters

Argument Details
limit: number, optional
How many Reviews to return. Default is 10.
page: number, optional
Which page of Reviews to return. Default is 1.
visible: bool, optional
Whether to return only visible (those that may appear in widgets) reviews or invisible.
archived: bool, optional
Whether to return reviews that have been archived by the user. Default is false. Pass an empty string to disable this filter.
test: bool, optional
Whether to return reviews created from test followups. Default is false. Pass an empty string to disable this filter.

Response Body

Then endpoint returns an object with a data key that is an Array with limit Product Reviews in the shop, sorted by created date (recent on top). It also returns a meta key with paging info.

Each Product Review object includes the following info:

Key Details
id: string
The Product Review’s ID. Currently unused.
title: string, optional
The Review’s title.
comment: string, optional
The Review’s long comment.
rating: number, optional
The Review’s rating, 1 to 5.
productId: string
The ID of the Product that was reviewed.
customerEmail: string, optional
The email address of the reviewer. May not exist when anonymous.
createdAt: string, optional
When the Product Review was created. Is an ISO 8601 encoded date.
archived: bool
A User may Archive a Product Review as a soft delete. Archived reviews aren’t shown in Widgets.
visible: bool
Only visible reviews can appear in Widgets.
isTest: bool
Whether this Review was created from a test FollowUp Email.

Abandoned Carts

Services related to managing Abandoned Carts. For the Email Campaigns triggered by Abandoned Carts, go to the next section.

Create

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/abandoned-carts" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
       "token":"sometoken",
       "customer":"some@customer.com",
       "currency":"USD",
       "amount":"39.99",
       "items":[
          {
             "reference":"rct",
             "variant":"rct2",
             "description":"CM Commerce subscription",
             "quantity":1,
             "amount":"39.99",
             "attributes":[{ "key": "foo", "value": "bar" }]
          }
       ]
    }'

RESPONSE

{}

Create or Update a Cart [POST]

https://commerce.campaignmonitor.com/api/v1/abandoned-carts

Arguments

Argument Details
token: string, required
Cart token or unique identifier
customer: string, required
Email address of the customer to whom the cart belongs
currency: string, required
ISO 4217 currency code
amount: number, required
The total amount for the cart
items: [object], required, see below
The items inside the cart.

Items

The items inside the cart. Object contents:

Key Details Example
reference: string, optional c_123
variant: string, optional c_123_2
description: string, required CM Commerce Hobby Plan
quantity: number, optional 1
amount: number, required 29.00
A single item’s price.
attributes: [object], optional [{ key: “foo”, value: “bar” }]
Item attributes. See below.
Attributes

Item attributes:

Key Details
key: string, required
value: string, required

Delete an abandoned cart

# DEFINITION
DELETE https://commerce.campaignmonitor.com/api/v1/abandoned-carts/1a2b3c4d

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/abandoned-carts/1a2b3c4d" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -X DELETE

https://commerce.campaignmonitor.com/api/v1/abandoned-carts/{TOKEN}

Arguments

Argument Details
token: string, required
Cart token or unique identifier.

Abandoned Cart Emails

Endpoints for viewing data of emails triggered by abandoned carts, and their customer interaction stats. For the Abandoned Carts themselves, go to the previous section.

List Abandoned Cart Campaigns

Returns a list of the Abandoned Cart Campaigns in the User’s account.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/abandoned-carts/campaigns \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "57b5aa3b046abfb053d80b52",
      "title": "Campaign for Potential Customers",
      "customerSegmentId": "57b5aa3b046abfb053d80b59",
      "enabled": true,
      "abandonedCartTemplates": [
        { "id": "57b5aa3b046abfb053d76b79" }
      ]
    },
    {
      "id": "57b5aa3b046abfb053d80b59",
      "title": "Entice Existing Customers",
      "enabled": true,
      "abandonedCartTemplates": [
        { "id": "57b5aa3b046abfb053d76b81" },
        { "id": "57b5aa3b046abfb053d76b56" }
      ]
    }
  ]
}

List all Campaigns [GET]

https://commerce.campaignmonitor.com/api/v1/abandoned-carts/campaigns

OAuth Scopes: read_abandoned_cart_campaign, write_abandoned_cart_campaign

Response Body

Then endpoint returns an object with a data key that is an Array with all the campaigns in the shop.

Each Campaign object includes the following info:

Key Details
id: string
The Campaigns’s ID. Use it when calling single-campaign endpoints.
title: string
The Campaign’s title, set by the User.
customerSegmentId: string, optional
The ID of the Campaign’s Customer Segment, if one was selected.
enabled boolean
Whether the Campaign is enabled, i.e. sending emails to customers.
abandonedCartTemplates: array[object]
A collection of all the Abandoned Cart Templates that belong to the campaign. Includes only the IDs of the templates.

View Abandoned Cart Campaign

Returns an Abandoned Cart Campaign in the User’s account.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/abandoned-carts/campaigns/57b5aa3b046abfb053d80b52 \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "title": "Campaign for Potential Customers",
    "customerSegmentId": "57b5aa3b046abfb053d80b59",
    "enabled": true,
    "abandonedCartTemplates": [
      { "id": "57b5aa3b046abfb053d76b81" },
      { "id": "57b5aa3b046abfb053d76b56" }
    ]
  }
}

Show Single Campaign [GET]

https://commerce.campaignmonitor.com/api/v1/abandoned-carts/campaigns/{CAMPAIGN_ID}

OAuth Scopes: read_abandoned_cart_campaign, write_abandoned_cart_campaign

Response Body

Then endpoint returns an object with a data key that is the Campaign for the ID. The Campaign has the following info:

Key Details
id: string
The Campaigns’s ID. Use it when calling single-campaign endpoints.
title: string
The Campaign’s title, set by the User.
customerSegmentId: string, optional
The ID of the Campaign’s Customer Segment, if one was selected.
enabled boolean
Whether the Campaign is enabled, i.e. sending emails to customers.
abandonedCartTemplates: array[object]
A collection of all the Abandoned Cart Templates that belong to the campaign. Includes only the IDs of the templates.

View Abandoned Cart Template

Returns an Abandoned Cart Template. This contains the basis for the content of each of its emails, as well as the trigger delay for an email to be sent.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/abandoned-carts/templates/57b5aa3b046abfb053d80b52 \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b68",
    "campaignId": "57b5aa3b046abfb053d89b69",
    "subject": "You forgot some goodies!",
    "title": "First Abandoned Cart Email",
    "rule": "delay",
    "period": 0,
    "periodHours": 1,
    "contentModules": []
  }
}

Show Abandoned Cart Template [GET]

Two possible endpoints:

  1. https://commerce.campaignmonitor.com/api/v1/abandoned-carts/templates/{TEMPLATE_ID}
  2. https://commerce.campaignmonitor.com/api/v1/abandoned-carts/campaigns/{CAMPAIGN_ID}/templates/{TEMPLATE_ID}

OAuth Scopes: read_abandoned_cart_template, write_abandoned_cart_template

Response Body

The response body includes a data key which contains an object representation of the requested abandoned cart template:

Key Details
id: string
The ID for this email.
campaignId: string
The ID for this template"s Campaign.
subject: string
The subject used in the emails triggered by this template. May have user variables (e.g.: {firstName}).
title: string
The template"s title, not customer-facing.
rule: string
Rule for triggering an email from this template. Currently only “delay” is supported, which is a delay from a cart being abandoned.
period: number
How many days must pass after the cart is abandoned to trigger an email from this template. Accumulates with periodHours.
periodHours: string
How many hours must pass after the cart is abandoned to trigger an email from this template. Accumulates with period.
contentModules: array
An array of the Content Modules in a template. These represent the content (copy, images, discounts, etc.) in a template. More details below.

Content Modules

{
  "contentModules": [
    {
      "position": 0,
      "type": "text",
      "context": {
        "body": "You left all of this stuff behind!"
      }
    },
    {
      "position": 1,
      "type": "abandonedCart",
      "context": {
        "quantity": "Quantity",
        "description": "Description",
        "unitPrice": "Unit Price",
        "total": "Total",
        "totalOrder": "Total",
        "buttonColor": "#1990FF",
        "primaryColor": "#1990FF",
        "secondaryColor": "#0076E4",
        "mainBackgroundColor": "#f8f8f8",
        "actionTitle": "Get All My Stuff!"
      }
    },
    {
      "position": 2,
      "type": "discountCoupon",
      "context": {
        "title": "You Stuff, At a Discount!",
        "description": "{{firstName}}, there"s no way you"re leaving all that stuff in the cart. Grab this discount and check-out now!",
        "actionTitle": "Start Shopping",
        "expiresOn": "Expires On",
        "primaryColor": "#1990FF",
        "amount": 10,
        "expiryPeriod": 1,
        "emailLimit": false,
        "couponType": 2,
        "backgroundColor": "#f8f8f8",
        "onePerUser": true,
        "usageLimit": 1
      }
    }
  ]
}

Each module has a position and a type. The 0-based position indicates where in the email the module appears (starting from top) and the type defines the kind of content.

The module"s content is in the context key. This object and its keys depend on the module"s type. These map directly to the content & settings in the Template editor, so we recommend referencing that in case any values are unclear.

View Abandoned Cart Email

Returns an Abandoned Cart Email, along with its action timestamps.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/abandoned-carts/emails/57b5aa3b046abfb053d80b52 \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b68",
    "templateId": "57b5aa3b046abfb053d89b69",
    "abandonedCartId": "57b5aa3b046abf1253d89b33",
    "to": "a@customer.com",
    "status": "sent",
    "sentAt": "2016-11-20T00:00:00.000Z",
    "deliveredAt": "2016-11-20T00:00:15.000Z",
    "openedAt": "2016-11-20T01:00:00.000Z",
    "clickedAt": "2016-11-20T01:01:10.000Z"
  }
}

Show Abandoned Cart Email [GET]

Three possible endpoints:

  1. https://commerce.campaignmonitor.com/api/v1/abandoned-carts/emails/{EMAIL_ID}
  2. https://commerce.campaignmonitor.com/api/v1/abandoned-carts/templates/{TEMPLATE_ID}/emails/{EMAIL_ID}
  3. https://commerce.campaignmonitor.com/api/v1/abandoned-carts/campaigns/{CAMPAIGN_ID}/templates/{TEMPLATE_ID}/emails/{EMAIL_ID}

OAuth Scopes: read_abandoned_cart_email, write_abandoned_cart_email

Response Body

The response body includes a data key which contains an object representation of the requested abandoned cart email:

Key Details
id: string
The ID for this email.
templateId: string
The ID for this email’s template.
abandonedCartId: string
The ID for the cart that triggered this email.
to: string
The email address to which this email was sent.
status: string
The email’s status. One of “created”, “rendered”, “rejected” or “sent”.
sentAt: string
When this email was sent. ISO 8601 encoded date.
deliveredAt: string, optional
When this email was delivered. ISO 8601 encoded date. Can be missing if not delivered.
openedAt: string, optional
When this email was last opened. ISO 8601 encoded date. Can be missing if never delivered.
clickedAt: string, optional
When this email was last clicked. ISO 8601 encoded date. Can be missing if no link was ever clicked.

Users

Services related to users using the Users API.

Current user

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/users/current" \
  -H "X-ApiKey: YOUR_API_KEY"

EXAMPLE RESPONSE

{
    "publicKey": "abcd",
    "name": {
        "firstName": "John",
        "lastName": "Doe"
    }
}

Retrieve user information [GET]

https://commerce.campaignmonitor.com/api/v1/users/current

The current API user.

Uninstall

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/users/uninstall" \
  -X POST \
  -H "X-ApiKey: YOUR_API_KEY"

Uninstall the user/app [POST]

https://commerce.campaignmonitor.com/api/v1/users/uninstall

Tells CM Commerce to uninstall the user associated with the given API key. Among other things, this automatically unsubscribes the user from a premium plan.

Newsletters

Endpoints for getting data on existing Newsletters for a shop, and their emails.

List Newsletters

Returns all the Newsletters created in a shop.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/newsletters?limit=2&page=2" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "57b5aa3b046abfb053d80b59",
      "title": "4th of July Sales",
      "liveAt": "2017-07-03:00:00.000Z",
      "audience": {
        "lists": ["marketing", "57b5aa3b046abfb053d80b52"],
        "customerSegmentKind": "id",
        "customerSegmentId": "57b5aa3b046abfb053d80b57",
        "customerSegmentInline": { "criteria": [] }
      },
      "customerLists": [],
      "customerSegments": [],
      "status": "scheduled"
    },
    {
      "id": "57b5aa3b046abfb053d80b52",
      "title": "Black Friday Announcement",
      "liveAt": "2016-11-20T00:00:00.000Z",
      "customerLists": ["57b5aa3b046abfb053d80b53"],
      "customerSegments": ["57b5aa3b046abfb053d80b57"],
      "status": "sent",
      "sentAt": "2016-11-20T00:10:15.000Z"
    }
  ],
  "meta": {
    "page": 2,
    "pages": 3,
    "total": 5,
    "limit": 2,
    "prevPage": "https://commerce.campaignmonitor.com/api/v1/newsletters?page=1&limit=2",
    "nextPage": "https://commerce.campaignmonitor.com/api/v1/newsletters?page=3&limit=2"
  }
}

List all Newsletters [GET]

https://commerce.campaignmonitor.com/api/v1/newsletters

OAuth Scopes: read_newsletter_template, write_newsletter_template

Query Parameters

Argument Details
limit: number, optional
How many Newsletters to return. Default is 10.
page: number, optional
Which page of Newsletters to return. Default is 1.
status: string, optional
Filters the Newsletters by status. Can be sent, scheduled, live or draft.

Response Body

Then endpoint returns an object with a data key that is an Array with limit newsletters in the shop. The Newsletters are sorted by sentAt descending, liveAt ascending and createdAt descending. It also returns a meta key with paging info.

Each newsletter object includes the following info:

Key Details
id: string
The Newsletter’s ID. Use it when calling single-newsletter endpoints.
title: string
The Newsletter’s title.
audience object
The Newsletter’s audience. Can be comprised of one or more lists, a segment ID or an inline segment. See below.
liveAt: string, optional
When the Newsletter is set to go live, if scheduled, or when it was set live, if sent or live. Is an ISO 8601 encoded date. Is omitted if the Newsletter is a draft.
status string
The Newsletter’s current status. Must be one of “draft”, “scheduled”, “live”, or “sent”.
sentAt string, optional
When the Newsletter was fully sent, if such is the case. Is an ISO 8601 encoded date.
customerLists (deprecated): string[]
An array of IDs of Customer Lists who will receive / have received this Newsletter. May be empty. Deprecated in favour of audience.
customerSegments (deprecated): string[]
An array of IDs of Customer Segments who will receive / have received this Newsletter. May be empty. Deprecated in favour of audience.

Audience

The Newsletter’s Audience. A Newsletter can be sent to one or more Customer Lists, with an optional segment that limits the Newsletter to a subset of subscribers on those lists.

Key Details
lists: string[]
List IDs. Can only be empty for “draft” Newsletters.
customerSegmentKind: string, optional
One of "inline", "id" or null.
customerSegmentId: string, optional
A Customer Segment’s ID. Ignored unless customerSegmentKind is "id".
customerSegmentInline: object, optional
An inline Customer Segment. Ignored unless customerSegmentKind is "inline". See Customer Segments for structure.

Newsletter Report

Returns the selected Newsletter and some stats regarding its sending status.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/newsletters/57b5aa3b046abfb053d80b52" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "title": "Black Friday Announcement",
    "liveAt": "2016-11-20T00:00:00.000Z",
    "audience": {
      "lists": ["everyone"],
      "customerSegmentKind": "inline",
      "customerSegmentInline": {
        "criteria": [{
          "criteriaName": "receipt.sent",
          "negate": true,
          "filters": []
        }]
      }
    },
    "customerLists": [],
    "customerSegments": [],
    "status": "sent",
    "sentAt": "2016-11-20T00:10:15.000Z",
    "stats": {
      "sends": 500,
      "opens": 450,
      "uniqueOpens": 300,
      "clicks": 99,
      "recipientCount": 515
    },
    "contentModules": []
  }
}

Single Newsletter Report [GET]

https://commerce.campaignmonitor.com/api/v1/newsletters/{NEWSLETTER_ID}

OAuth Scopes: read_newsletter_template, write_newsletter_template

Response Body

Then endpoint returns an object with a data key that the Newsletter object. The included info:

Key Details
id: string
The Newsletter’s ID. Use it when calling single-newsletter endpoints.
title: string
The Newsletter’s title.
audience object
The Newsletter’s audience. Can be comprised of one or more lists, a segment ID or an inline segment. See above.
liveAt: string, optional
When the Newsletter is set to go live, if scheduled, or when it was set live, if sent or live. Is an ISO 8601 encoded date. Is omitted if the Newsletter is a draft.
status: string
The Newsletter’s current status. Must be one of “draft”, “scheduled”, “live”, or “sent”.
sentAt: string, optional
When the Newsletter was fully sent, if such is the case. Is an ISO 8601 encoded date.
stats: object
An object with this Newsletter’s stats. Included keys are described below.
contentModules: array
An array of the Content Modules in a Newsletter. These represent the content (copy, images, discounts, etc.) in a Newsletter. More details below.
customerLists (deprecated): string[]
An array of IDs of Customer Lists who will receive / have received this Newsletter. May be empty. Deprecated in favour of audience.
customerSegments (deprecated): string[]
An array of IDs of Customer Segments who will receive / have received this Newsletter. May be empty. Deprecated in favour of audience.

Stats

The stats key has the following format:

Key Details
sends: number
The total number of emails that were sent for this Newsletter.
opens: number
The total number of times this Newsletter’s emails have been opened.
uniqueOpens: number
The number of unique users that have opened this Newsletter’s emails.
clicks: number
The total number of clicks on this Newsletter’s links.
recipientCount: number
How many recipients was this Newsletter sent to. May differ from sends if there are sending errors.

Content Modules

{
  "contentModules": [
    {
      "position": 0,
      "type": "text",
      "context": {
        "body": "Black Friday Sale!"
      }
    },
    {
      "position": 1,
      "type": "image",
      "context": {
        "value": "https://www.epic-store.com/black-friday-img.png",
        "url": "https://www.epic-store.com/sale",
        "alignment": "center"
      }
    },
    {
      "position": 2,
      "type": "discountCoupon",
      "context": {
        "title": "Extra Black Friday Discount",
        "description": "{{firstName}}, these are the last few hours of our Black Friday sale! As an extra incentive, this is a coupon for extra {{discount}} off your next purchase :)",
        "actionTitle": "Start Shopping",
        "expiresOn": "Expires On",
        "primaryColor": "#1990FF",
        "amount": 10,
        "expiryPeriod": 1,
        "emailLimit": false,
        "couponType": 2,
        "backgroundColor": "#f8f8f8",
        "onePerUser": true,
        "usageLimit": 1
      }
    }
  ]
}

Each module has a position and a type. The 0-based position indicates where in the Newsletter the module appears (starting from top) and the type defines the kind of content.

The module’s content is in the context key. This object and its keys depend on the module’s type. These map directly to the content & settings in the Newsletter editor, so we recommend referencing that in case any values are unclear.

List Newsletter Emails

A paginated list of all the emails sent for a Newsletter. Will be empty if Newsletter has not been sent yet. Emails are returned sorted by email address, and pagination is done by providing the email address from which to return results.

Note that if the Newsletter is currently live and sending, paginating results will not guarantee that all emails are returned. Wait for the “sent” status if an exhaustive list is required.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/newsletters/57b5aa3b046abfb053d80b52/emails?limit=2" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "57b5aa3b046abfb053d80b60",
      "to": "a@customer.com",
      "sentAt": "2016-11-20T00:00:00.000Z",
      "deliveredAt": "2016-11-20T00:00:15.000Z",
      "openedAt": "2016-11-20T01:00:00.000Z",
      "clickedAt": "2016-11-20T01:01:10.000Z"
    }, {
      "id": "57b5aa3b046abfb053d80b60",
      "to": "another@customer.com",
      "sentAt": "2016-11-20T00:00:01.000Z",
      "deliveredAt": "2016-11-20T00:00:17.000Z",
      "openedAt": "2016-11-21T10:02:00.000Z"
    }
  ],
  "meta": {
    "nextPage": "https://commerce.campaignmonitor.com/api/v1/newsletters/57b5aa3b046abfb053d80b52/emails/?from=another%40email.com&limit=2",
    "total": 500,
    "limit": 2,
    "pages": 250
  }
}

Newsletter Email List [GET]

https://commerce.campaignmonitor.com/api/v1/newsletters/{NEWSLETTER_ID}/emails

OAuth Scopes: read_newsletter_email, write_newsletter_email

Request Query Params

Key Details
from: string, optional
The email address from which to start paginating records. Must be URI encoded if present.
limit: number, optional
The maximum number of records to return at once. Very high numbers are discouraged and might result in connection timeouts.

Response Body

The response body includes a data key which contains an array of newsletter emails. The emails' format:

Key Details
id: string
The ID for this email.
to: string
The email address to which this email was sent.
sentAt: string
When this email was sent. ISO 8601 encoded date.
deliveredAt: string, optional
When this email was delivered. ISO 8601 encoded date. Can be missing if not delivered.
openedAt: string, optional
When this email was last opened. ISO 8601 encoded date. Can be missing if never delivered.
clickedAt: string, optional
When this email was last clicked. ISO 8601 encoded date. Can be missing if no link was ever clicked.

The response body also includes a meta key with further pagination information. The keys included are:

Key Details
total: number
The total number of emails for this Newsletter.
limit: number
The maximum number of records returned in this request.
pages: number
How many pages need to be requested to go through all emails. Varies with total and limit.
nextPage: string, optional
The URL form where the next page of emails can be fetched. Use it to cycle pages. May be omitted if there are no more emails to fetch.

View Newsletter Email

Returns a Newsletter’s email, along with its text & HTML contents.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/newsletters/57b5aa3b046abfb053d80b52/emails/57b5aa3b046abfb053d80b68" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b68",
    "to": "a@customer.com",
    "sentAt": "2016-11-20T00:00:00.000Z",
    "deliveredAt": "2016-11-20T00:00:15.000Z",
    "openedAt": "2016-11-20T01:00:00.000Z",
    "clickedAt": "2016-11-20T01:01:10.000Z",
    "rendered": {
      "text": "This is an email's text version...",
      "html": "<html><body>This is an email's HTML content...</body></html>",
      "subject:": "This is the Newsletter's subject."
    }
  }
}

Show Newsletter Email [GET]

https://commerce.campaignmonitor.com/api/v1/newsletters/{NEWSLETTER_ID}/emails/{EMAIL_ID}

OAuth Scopes: read_newsletter_email, write_newsletter_email

Response Body

The response body includes a data key which contains an object representation of the requested newsletter email. The rendered key is included with the email’s contents:

Key Details
id: string
The ID for this email.
to: string
The email address to which this email was sent.
sentAt: string
When this email was sent. ISO 8601 encoded date.
deliveredAt: string, optional
When this email was delivered. ISO 8601 encoded date. Can be missing if not delivered.
openedAt: string, optional
When this email was last opened. ISO 8601 encoded date. Can be missing if never delivered.
clickedAt: string, optional
When this email was last clicked. ISO 8601 encoded date. Can be missing if no link was ever clicked.
rendered: object
The rendered content for this email. Contains keys: text, html and subject

Export Newsletter Recipients

Starts an Async Job to export a Newsletter’s recipients. Once completed, the job’s result will point to a CSV file with email addresses.

Refer to the Async Jobs documentation on how to access the job’s result.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/newsletters/57b5aa3b046abfb053d80b52/recipients/async-export" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b68",
    "kind": "newsletter-recipients",
    "status": "pending"
  }
}

Create Export Job [POST]

https://commerce.campaignmonitor.com/api/v1/newsletters/{NEWSLETTER_ID}/recipients/async-export

OAuth Scopes: read_newsletter_email, write_newsletter_email

Response Body

The response body includes a data key which reflects the created Async Job’s info:

Key Details
id: string
The ID for the created AsyncJob. Use this to identify this export.
kind: string
The kind of job created. Is always newsletter-recipients on this endpoint.
status: string
The job’s status. Always pending.

Export Newsletter Emails

Starts an Async Job to export a Newsletter’s emails. Once completed, the job’s result will point to a CSV file with email addresses and activity timestamps.

Refer to the Async Jobs documentation on how to access the job’s result.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/newsletters/57b5aa3b046abfb053d80b52/emails/async-export" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b68",
    "kind": "newsletter-emails",
    "status": "pending"
  }
}

Create Export Job [POST]

https://commerce.campaignmonitor.com/api/v1/newsletters/{NEWSLETTER_ID}/emails/async-export

OAuth Scopes: read_newsletter_email, write_newsletter_email

Response Body

The response body includes a data key which reflects the created Async Job’s info:

Key Details
id: string
The ID for the created AsyncJob. Use this to identify this export.
kind: string
The kind of job created. Is always newsletter-emails on this endpoint.
status: string
The job’s status. Always pending.

Customer Lists

Services related to managing Customer Lists (for Newsletters) and subscriptions.

Get Customer Lists

Get all available customer lists.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/customer-lists" \
  -H "X-ApiKey: YOUR_API_KEY"
  -H "Accept: application/json"

EXAMPLE RESPONSE

[
  {
    "id": "57b5aa3b046abfb053d80b52",
    "title": "Weekly Newsletter Subscribers",
    "singleOptIn": false,
    "enabled": true,
    "subscribable": true,
    "subscribers": 3,
    "pending": 2,
    "unsubscribers": 1
  },
  {
    "id": "57b5aa3b046abfb053d80b53",
    "title": "New Products Announcements",
    "singleOptIn": true,
    "enabled": true,
    "subscribable": true,
    "subscribers": 3,
    "pending": 2,
    "unsubscribers": 1
  },
  {
    "id": "marketing",
    "title": "Accepted Marketing",
    "singleOptIn": true,
    "enabled": false,
    "subscribable": false,
    "subscribers": 0,
    "pending": 0,
    "unsubscribers": 0
  }
]

List all Customer Lists [GET]

https://commerce.campaignmonitor.com/api/v1/customer-lists

Arguments

These are provided via query params.

Key Details
all: boolean
Whether to include lists that are not subscribable in the return (eg: Accepts Marketing)

Return

The endpoint returns an array with all the Customer Lists in the account. Object keys are:

Key Details
id: string
The Customer List ID. This is used whenever referencing this Customer List in other endpoints.
title: string
The title picked by the user for this List. Used in user-facing interfaces.
singleOptIn: boolean
Whether this list is single opt-in. If not, a confirmation email is sent on subscription.
enabled: boolean
Whether this list is enabled. Always true except for the marketing list where it may be false.
subscribable: boolean
Whether subscribers can be added to this list.
subscribers: integer
The number of subscribers for this list.
pending: integer
The number of pending subscribers for this list. A pending subscriber used an online form to sign up, but has not confirmed the subscription yet.
unsubscribers: integer
The number of unsubscribers for this list.

Create List

Creates a new Customer List.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/customer-lists" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
       "title":"An Awesome List",
       "singleOptIn":false
  }'

RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "title": "An Awesome List",
    "singleOptIn": false,
    "enabled": true,
    "subscribable": true
  }
}

Create a Customer List [POST]

https://commerce.campaignmonitor.com/api/v1/customer-lists

OAuth Scopes: read_customer_list, write_customer_list

Arguments

Key Details
title: string
The title for the new List. Used in user-facing interfaces.
singleOptIn: boolean, optional
Whether this list is single opt-in. If not, a confirmation email is sent on subscription.

Return

The endpoint returns an object with a data key with the created list’s data in it:

Key Details
id: string
The Customer List ID. This is used whenever referencing this Customer List in other endpoints.
title: string
The title picked by the user for this List. Used in user-facing interfaces.
singleOptIn: boolean
Whether this list is single opt-in. If not, a confirmation email is sent on subscription.
enabled: boolean
Whether this list is enabled. Always true except for the marketing list where it may be false.
subscribable: boolean
Whether subscribers can be added to this list.

Update List

Updates an existing Customer List. Updates are applied partially both on PUT and PATCH requests.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/customer-lists/57b5aa3b046abfb053d80b52" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X PATCH \
  -d '{
       "singleOptIn":true
  }'

RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "title": "An Awesome List",
    "singleOptIn": true,
    "enabled": true,
    "subscribable": true
  }
}

Update a Customer List [PATCH|PUT]

https://commerce.campaignmonitor.com/api/v1/customer-lists/{LIST_ID}

OAuth Scopes: read_customer_list, write_customer_list

Arguments

Key Details
title: string
A new title for the List. Used in user-facing interfaces.
singleOptIn: boolean, optional
Whether this list is single opt-in.

Return

The endpoint returns an object with a data key with the updated list’s data in it:

Key Details
id: string
The Customer List ID. This is used whenever referencing this Customer List in other endpoints.
title: string
The title for this List. Used in user-facing interfaces.
singleOptIn: boolean
Whether this list is single opt-in. If not, a confirmation email is sent on subscription.
enabled: boolean
Whether this list is enabled. Always true except for the marketing list where it may be false.
subscribable: boolean
Whether subscribers can be added to this list.

Subscribe to List

Subscribe an email address and optional user details to a specific customer list.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/customer-lists/LIST_ID/subscriptions" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X PUT \
  -d '{
    "email": "an@email.com",
    "name": "John Snow",
    "source": "CM Commerce",
    "sourceType": "SubscriptionForm",
    "sourceId": "some-form-slug",
    "optInText": "Subscribe to receive new product updates",
    "properties": {
      "age": 42,
      "happy": true,
      "dob": "2001-12-23",
      "likes": ["wine", "cinnamon", "umami"]
    }
  }'

Subscribe an Email to a Customer List [PUT]

https://commerce.campaignmonitor.com/api/v1/customer-lists/LIST_ID/subscriptions

LIST_ID should be the id returned in the list response.

Arguments

Argument Details
email: string
The email address to subscribe to this Customer List. Must be a valid email address.
name: string, optional
The email address owner’s name. Expects first or first and last name.
properties: object, optional
Additional properties to track for this subscriber. Type inference applies the first time a property is tracked, We support string, number, boolean, array and date types.
source: string, optional
Where this subscription came from. Should be an App or company name.
sourceType: string, optional
What type of control did the user interact for subscribing. Could be a form type, page, etc.
sourceId: string, optional
A more granular ID of where the user subscribed. Could be the ID/slug of a form or subscription page.
optInText: string, optional
What opt-in text was shown to the subscriber. This is required for GDPR compliance.

Properties

Property keys can have at most 100 characters in length and must match the regex /^[a-zA-Z0-9-_]+$/. A maximum of 20 different properties are allowed per account.

The first time a property is tracked (uniqueness is ensured by key), CM Commerce tries to infer its type. The following rules apply:

List Subscribers

Returns a list’s accepted subscribers, pending subscribers (haven’t opted in yet) and unsubscribers.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/customer-lists/marketing/subscribers" \
  -H "X-ApiKey: YOUR_API_KEY"
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "57b5aa3b046abfb053d80b52",
      "email": "test@email.com"
    }
  ],
  "meta": {
    "pages": 1,
    "total": 1,
    "limit": 10,
    "searchAfter": ["test@email.com"],
    "nextPage": "https://commerce.campaignmonitor.com/api/v1/customer-lists/5b10ded082d2653410054ac3/subscribers?limit=10&searchAfter=test%40email.com"
  }
}

List all Subscribers to a Customer List [GET]

https://commerce.campaignmonitor.com/api/v1/customer-lists/{LIST_ID}/subscribers

OAuth Scopes: read_customers

Arguments

These are provided via query params.

Key Details
pending: boolean
Changes the return to a list of pending subscribers.
unsubscribers: boolean
Changes the return to a list of unsubscribers.

Return

The endpoint returns an object with a data key with the found subscribers, and a meta key with pagination info. By default, the returned subscribers are Customer objects with event & stats data.

However, when querying for pending or unsubscribers the returned subscribers include only the email key. Pagination is also different. This is for legacy reasons and is likely to change (to match the default return) in the future.

To ensure your app supports all returns and is future-proof, expect only the email address in the return, and use nextPage for pagination.

Key Details
email: string
The email address for the subscriber. Only common field across all queries.

Mass Unsubscribe

Removes one or more list’s subscribers. There are two versions of this request: one that removes a list of emails, another that removes a whole segment.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/customer-lists/LIST_ID/subscribers" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -X DELETE \
  -G \
  -d "emails[]=email1@example.org" \
  -d "emails[]=email2@example.org" \
  -d "emails[]=email3@example.org"

EXAMPLE RESPONSE

{
  "data": {
    "unsubscribed": 2,
    "failed": 0,
    "failedReasons": []
  }
}

Unsubscribe via Email List [DELETE]

https://commerce.campaignmonitor.com/api/v1/customer-lists/{LIST_ID}/subscribers

OAuth Scopes: write_customers

Arguments

These are provided via query params.

Key Details
emails: string[]
The list of emails to unsubscribe from the Customer List.

Return

Key Details
unsubscribed: number
How many emails were successfuly unsubscribed.
failed: number
How many emails failed to unsubscribe.
failedReasons: string[]
A list of errors that explain unsubscribe failures.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/customer-lists/LIST_ID/subscribers" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -X DELETE \
  -G \
  -d "segment={\"criteria\":[{\"criteriaName\":\"receipt.sent\",\"negate\":true,\"filters\":[]}]}"

EXAMPLE RESPONSE

{
  "data": {
    "asyncJobId": "5b10ded082d2653410054ac3"
  }
}

Unsubscribe via Customer Segment [DELETE]

https://commerce.campaignmonitor.com/api/v1/customer-lists/{LIST_ID}/subscribers

OAuth Scopes: write_customers

Arguments

These are provided via query params.

Key Details
segment: string
A Customer Segment in JSON format.

Return

There are two possible return formats: If the number of subscribers to remove is relatively low, they will be removed synchronously with the request and the return will mirror the Unsubscribe via Email List’s. Otherwise, an Async Job is started and it’s ID returned instead inside the data key.

The following format is returned only with status 202:

Key Details
asyncJobId: string
An Async Job’s ID.

Customer Segments

Services related to managing Customer Segments.

List Customer Segments

Returns all segments and where they’re used.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/segments" \
  -H "X-ApiKey: YOUR_API_KEY"
  -H "Accept: application/json"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "5ae9aeedc60b7e00fe9f133a",
      "name": "\"At Risk\" Repeat Customers",
      "editable": false,
      "uses": []
    },
    {
      "id": "5ae9aeedc60b7e00fe9f1330",
      "name": "First-time Buyers",
      "editable": false,
      "uses": [
        {
          "modelName": "ReceiptTemplate",
          "models": [
            {
                "id": "5ae9aeedc60b7e00fe9f1356",
                "enabled": false
            }
          ]
        }
      ]
    }
  ]
}

List all Customer Segments [GET]

https://commerce.campaignmonitor.com/api/v1/segments

OAuth Scopes: read_segments

Return

The endpoint returns an object with a data key that contains all the Customer Segments in the account. Object keys are:

Key Details
id: string
The Customer Segment’s ID. This is used whenever referencing this Customer Segment in other endpoints.
name: string
The segment’ name.
editable: bool
Whether this is a default segment (false) or a custom one (true)
uses: object[]
Where this segment is currently being used, see below.

Uses

Key Details
modelName: string
Name of the Model where a segment is used, Possible values: "AsyncJob", "Campaign", "FollowUpTemplate", "NewsletterTemplate", "ReceiptTemplate".
models: object[]
All the objects of modelName type where this segment is used. Format depends on model.

Export Segment Customers

Starts an Async Job to export a Segment’s customers. Once completed, the job’s result will point ot a CSV file with email addresses and subscription status.

Refer to the Async Jobs documentation on how to access the job’s result.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/segments/57b5aa3b046abfb053d80b52/async-export" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b68",
    "kind": "segments-export",
    "status": "pending"
  }
}

Create Export Job [POST]

https://commerce.campaignmonitor.com/api/v1/segments/{SEGMENT_ID}/async-export

OAuth Scopes: read_customers, read_segments

Response Body

The response body includes a data key which reflects the created Async Job’s info:

Key Details
id: string
The ID for the created AsyncJob. Use this to identify this export.
kind: string
The kind of job created. Is always segments-export on this endpoint.
status: string
The job’s status. Always pending.

Webhooks

Endpoints for subscribing and configuring Webhooks triggered by events on your account.

You should use webhooks to get near real-time updates on events in a shop. When one of the supported events happens (eg: a newsletter email is sent), CM Commerce will POST some data related to that event to the endpoints registered in webhooks that subscribed to that event’s topic.

When Webhook delivery fails (your endpoint can’t be reached or returns an error status code), we’ll keep trying to re-send the failed Webhooks up to a limited number of tries, in an exponential back-off fashion. Details are described below.

For security purposes, all our webhooks use JSON Web Signatures (JWS). These allow recipients to validate that each webhook originates from CM Commerce. More details on the validation are below.

Subscribable Topics

Payload

All request bodies contain two keys, meta and data. The meta key contains information about the webhook itself:

Key Details
topic: string
The Webhook’s topic. Useful if you wish to direct all webhooks to the same endpoint.
ts: number
The timestamp for when the webhook was first sent. This will stay equal for subsequent retries.

The data key’s content depends on the Webhook’s topic. The following apply:

newsletter-template/sent

# EXAMPLE WEBHOOK
$ curl "https://partner-app.com/registered/endpoint" \
  -H "Authorization: Bearer 'eyJhbGciOiJIUzI1NiIsImtpZCI6IkNsaWVudCBTZWNyZXQiLCJ0eXAiOiJKV1QifQ.eyJqaXQiOiIzOTg1Y2JlMC1lM2JlLTExZTYtYThmMy04NTMzOTYyOGMzNGEiLCJpYXQiOjE0ODU0MzE2ODIsImlzcyI6IkNvbnZlcnNpbyJ9.WZYh7Wylj5vnGRWqrgeMXdeRjIqJc9V30nyEG7QHpvk'" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "meta": {
      "topic": "newsletter-template/sent",
      "ts": 1485431966802
    },
    "data": {
      "templateId": "57b5aa3b640abfb053d80a63",
      "userId": "67b5aa3c640abfb053d80a63",
      "status": "sent",
      "title": "Black Friday opening announcement",
      "sentAt": "2017-01-26T11:57:26.675Z",
      "liveAt": "2017-01-26T11:45:28.888Z"
    }
  }'
Key Details
templateId: string
The Newsletter Template’s ID. Can be used to reference the template using the API.
userId: string
The User / Store that this template belongs to.
status: string
Template status, is “sent”.
title: string
The Newsletter’s title (store-facing, not necessarily in email content).
liveAt: string
When the template started sending. This is an ISO 8601 formatted date.
sentAt: string
When the template finished sending. This is an ISO 8601 formatted date.

newsletter-email/sent

# EXAMPLE WEBHOOK
$ curl "https://partner-app.com/registered/endpoint" \
  -H "Authorization: Bearer 'eyJhbGciOiJIUzI1NiIsImtpZCI6IkNsaWVudCBTZWNyZXQiLCJ0eXAiOiJKV1QifQ.eyJqaXQiOiIzOTg1Y2JlMC1lM2JlLTExZTYtYThmMy04NTMzOTYyOGMzNGEiLCJpYXQiOjE0ODU0MzE2ODIsImlzcyI6IkNvbnZlcnNpbyJ9.WZYh7Wylj5vnGRWqrgeMXdeRjIqJc9V30nyEG7QHpvk'" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "meta": {
      "topic": "newsletter-email/sent",
      "ts": 1485431966802
    },
    "data": {
      "emailId": "57b5aa3b046abfb053d80b52",
      "templateId": "57b5aa3b640abfb053d80a63",
      "userId": "67b5aa3c640abfb053d80a63",
      "to": "an@email.com",
      "subject": "Black Friday Sale",
      "title": "Black Friday opening announcement",
      "sentAt": "2017-01-26T11:57:26.675Z"
    }
  }'
Key Details
emailId: string
The Newsletter Email’s ID. Can be used to reference the email using the API.
templateId: string
The Newsletter Template’s ID. The template that the email belongs to.
userId: string
The User / Store that this email belongs to.
to: string
The email address to whom this email was sent.
subject: string
The subject of the email
title: string
The Newsletter’s title (store-facing, not necessarily in email content).
sentAt: string
When the email was sent. This is an ISO 8601 formatted date.

async-job/completed

# EXAMPLE WEBHOOK
$ curl "https://partner-app.com/registered/endpoint" \
  -H "Authorization: Bearer 'eyJhbGciOiJIUzI1NiIsImtpZCI6IkNsaWVudCBTZWNyZXQiLCJ0eXAiOiJKV1QifQ.eyJqaXQiOiIzOTg1Y2JlMC1lM2JlLTExZTYtYThmMy04NTMzOTYyOGMzNGEiLCJpYXQiOjE0ODU0MzE2ODIsImlzcyI6IkNvbnZlcnNpbyJ9.WZYh7Wylj5vnGRWqrgeMXdeRjIqJc9V30nyEG7QHpvk'" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "meta": {
      "topic": "async-job/completed",
      "ts": 1485431966803
    },
    "data": {
      "asyncJobId": "57b5aa3b046abfb053d80b52",
      "userId": "57b5aa3b046abbf053d80b64"
      "kind": "newsletter-recipients",
      "status": "done",
      "startedAt": "2017-01-26T11:57:26.675Z",
      "completedAt": "2017-01-26T12:02:06.665Z",
      "result": "https://receiptful.s3.amazonaws.com/async-jobs/1234567890987654321.csv"
    }
  }'

Data is the JSON representation of the completed Async Job:

Key Details
asyncJobId: string
The Async Job’s ID.
userId: string
The user on whose behalf this job is running.
kind: string
What kind of job it is.
status: string
The job’s status. Is either “done” or “failed”.
startedAt: string, optional
When this job started processing. Is an ISO 8601 encoded date. Can be null if it hasn’t started yet.
completedAt: string
When this job completed. Is an ISO 8601 encoded date.
error: string, optional
An error message that indicates a problem when processing the job. There is no result if this is present.
result: string, optional
The final result from processing this job. What it is depends on job kind.

abandoned-cart-email/sent

# EXAMPLE WEBHOOK
$ curl "https://partner-app.com/registered/endpoint" \
  -H "Authorization: Bearer 'eyJhbGciOiJIUzI1NiIsImtpZCI6IkNsaWVudCBTZWNyZXQiLCJ0eXAiOiJKV1QifQ.eyJqaXQiOiIzOTg1Y2JlMC1lM2JlLTExZTYtYThmMy04NTMzOTYyOGMzNGEiLCJpYXQiOjE0ODU0MzE2ODIsImlzcyI6IkNvbnZlcnNpbyJ9.WZYh7Wylj5vnGRWqrgeMXdeRjIqJc9V30nyEG7QHpvk'" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{
    "meta": {
      "topic": "abandoned-cart-email/sent",
      "ts": 1485431966893
    },
    "data": {
      "userId": "57b5aa3b0461234053d80b52"
      "emailId": "57b5aa3b046abfb053d80b52",
      "templateId": "57b5aa3b046abfb053d80b53",
      "campaignId": "57b5aa3b046abfb053d80b56",
      "abandonedCartId": "57b5aa3b046abfb053d80b59",
      "to": "some@customer.com",
      "status": "sent"
      "sentAt": "2017-01-26T11:57:26.675Z",
      "subject": "You forgot your goodies!"
    }
  }'

Data is the JSON representation of the sent Abandoned Cart email:

Key Details
emailId: string
The email’s ID.
templateId: string
The email template’s ID.
campaignId: string
The Abandoned Cart Campaign’s ID.
abandonedCartId: string
The ID of the Abandoned Cart that triggered this email.
userId: string
The User’s ID.
to: string
The email address of the customer that received this email (also the owner of the Abandoned Cart).
status: string
The email’s status. Is “sent”.
sentAt: stringl
When the email was sent. Is an ISO 8601 encoded date.
subject: string
The email subject.

Retry Mechanism

Webhooks retry up to 6 times, for a total of 7 attempts. Multiple failures are grouped by endpoint and retried in batches. If 5% or more of a batch of retries fails consecutively, all webhooks in that batch are skipped and an attempt is counted for each.

The retry progression is (in time elapsed from first attempt):

  1. 10min
  2. 35min
  3. 1h 30min
  4. 4h 20min
  5. 10h 30min
  6. 1d 3h
  7. 3d

After all attempts are through, the webhooks are discarded.

Security Signature

# EXAMPLE WEBHOOK
$ curl "https://partner-app.com/registered/endpoint" \
  -H "Authorization: Bearer 'eyJhbGciOiJIUzI1NiIsImtpZCI6IkNsaWVudCBTZWNyZXQiLCJ0eXAiOiJKV1QifQ.eyJqaXQiOiIzOTg1Y2JlMC1lM2JlLTExZTYtYThmMy04NTMzOTYyOGMzNGEiLCJpYXQiOjE0ODU0MzE2ODIsImlzcyI6IkNvbnZlcnNpbyJ9.WZYh7Wylj5vnGRWqrgeMXdeRjIqJc9V30nyEG7QHpvk'" \
  -H "Content-Type: application/json" \
  -H "Accept: application/json" \
  -X POST \
  -d '{ ... }'
/* JavaScript */
const jws = require('jws');

const authorization = req.get('Authorization');
// > 'Bearer eyJhbGciOiJIUzI1NiIsImtpZCI6IkNsaWVudCBTZWNyZXQiLCJ0eXAiOiJKV1QifQ.eyJqaXQiOiIzOTg1Y2JlMC1lM2JlLTExZTYtYThmMy04NTMzOTYyOGMzNGEiLCJpYXQiOjE0ODU0MzE2ODIsImlzcyI6IkNvbnZlcnNpbyJ9.WZYh7Wylj5vnGRWqrgeMXdeRjIqJc9V30nyEG7QHpvk'

const [, encodedToken] = authorization.split(' ');
const token = jws.decode(encodedToken);
// > {
// >   header: { alg: 'HS256', kid: 'Client Secret', typ: 'JWT' },
// >   payload: {
// >     jit: '3985cbe0-e3be-11e6-a8f3-85339628c34a',
// >     iat: 1485431682,
// >     iss: 'Conversio'
// >   },
// >   signature: 'WZYh7Wylj5vnGRWqrgeMXdeRjIqJc9V30nyEG7QHpvk'
// > }

jws.verify(encodedToken, token.header.alg, 'a-secret');
// > true
## Ruby
require 'JWT'

_, encoded_token = request.headers['Authorization'].split
payload, header = JWT.decode(encoded_token, nil, false)
# > payload = {"jit"=>"3985cbe0-e3be-11e6-a8f3-85339628c34a", "iat"=>1485431682, "iss"=>"Conversio"}
# > header = {"alg"=>"HS256", "kid"=>"Client Secret", "typ"=>"JWT"}

JWT.decode(encoded_token, 'a-secret', true, algorithm: header['alg'], iss: 'Conversio', verify_iss: true, verify_iat: true)
# > [{"jit"=>"3985cbe0-e3be-11e6-a8f3-85339628c34a", "iat"=>1485431682, "iss"=>"Conversio"}, {"alg"=>"HS256", "kid"=>"Client Secret", "typ"=>"JWT"}]

A JSON Web Token (JWT) is signed and encoded into the Authorization header of the Webhook’s request using the Bearer schema. The token’s header includes the following keys:

Key Details
alg: string
Has the value “HS256”. It’s the algorightm used for the HMAC signature.
typ: string
Has the value “JWT”. Indicates this is a JSON Web Token.
kid: string
Hints at what secret was used for signing the Token. Is “Client Secret” when the webhook is registered for a Partner App, or “API Key” when the webhook was registered through an API.

The token’s body itself includes the following keys:

Key Details
jti: string
Has a random, unique value. Two tokens with the same jti could mean an attacker is re-using tokens to fabricate authorized webhooks.
iss: string
Has the value “Conversio”.
iat: string
UNIX time of when the token was generated (when webhook request is sent).

This token is then serialized using JWS Compact Serialization and included in the Authorization header using the Bearer schema.

Webhooks recipients should validate that every request is properly signed. This acts as guarantee that the webhook is valid and was sent by CM Commerce.

Validating the signatures is a process made simple by programming libraries. The same library used during OAuth can be used here, just follow the examples on the right.

View Webhooks

Returns all Webhooks registered for the current shop. If authorized through OAuth, only those webhooks created by the authorized PartnerApp will be listed.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/webhooks" \
  -H "X-ApiKey: YOUR_API_KEY"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "57b5aa3b046abfb053d80b52",
      "topic": "newsletter-email/sent",
      "endpoint": "https://www.endpoint.com/cmcommerce-webhook"
    }
  ]
}

List all Webhooks [GET]

https://commerce.campaignmonitor.com/api/v1/webhooks

OAuth Scopes: read_webhook, write_webhook

Response Body

Then endpoint returns an object with a data key that is an Array with all the webhooks in the shop. It will limit output to the currently authenticated Partner App webhooks if authorized through OAuth.

Each webhook includes the following info:

Key Details
id: string
The Webhook ID. Use it when calling single-webhook endpoints.
topic: string
The event that triggers this webhook.
endpoint: string
Where the webhook’s payload is sent, when triggered. Must be a URI.
partnerApp: string, optional
The ID of the Partner App that created this webhook. Included only when authorization is made with the API key.
# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/webhooks/57b5aa3b046abfb053d80b52" \
  -H "X-ApiKey: YOUR_API_KEY"

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "topic": "newsletter-email/sent",
    "endpoint": "https://www.endpoint.com/conversio-webhook"
  }
}

Show Single Webhook [GET]

https://commerce.campaignmonitor.com/api/v1/webhooks/{WEBHOOK_ID}

OAuth Scopes: read_webhook, write_webhook

Response Body

Then endpoint returns an object with a data key that is itself an object with the Webhook’s properties. It will include the Partner App if authorized with an API key. The following keys are returned:

Key Details
id: string
The Webhook ID. You used it to call this endpoint.
topic: string
The event that triggers this webhook.
endpoint: string
Where the webhook’s payload is sent, when triggered. Must be a URI.
partnerApp: string, optional
The ID of the Partner App that created this webhook. Included only when authorization is made with the API key.

Create Webhooks

Create a new Webhook for the currently authenticated shop. If authorized through OAuth, the Webhook will be assigned to the authorized Partner App.

Only one Webhook for a unique topic & endpoint combination can exist for each Shop. Thus, trying to create multiple webhooks for the same topic and endpoint will result in errors.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/webhooks" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X POST \
  -d '{
        "endpoint": "https://www.your-endpoint.com/webhooks",
        "topic": "newsletter-email/sent",
      }'

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "topic": "newsletter-email/sent",
    "endpoint": "https://www.your-endpoint.com/webhooks"
  }
}

EXAMPLE ERROR RESPONSE

{
  "errors": [
    "The chosen topic is invalid"
  ]
}

Create Webhook [POST]

https://commerce.campaignmonitor.com/api/v1/webhooks

OAuth Scopes: write_webhook

Request Body

Key Details
topic: string
The topic to subscribe with this Webhook.
endpoint: string
URL where to publish this Webhook’s payload, when triggered.

Response Body

When successful, the endpoint returns the newly created webhook. The returned data mimics that of the show endpoint:

Key Details
id: string
The new Webhook’s ID.
topic: string
The event that triggers this webhook.
endpoint: string
Where the webhook’s payload is sent, when triggered. Must be a URI.
partnerApp: string, optional
The ID of the Partner App that created this webhook. Included only when authorization is made with the API key.

Any errors during creation will be identified by a 400 status code and a JSON object with an errors Array with string explanations of what went wrong.

Update Webhooks

Update an existing webhook with new data. Can change either the topic or endpoint of an existing webhook.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/webhooks/57b5aa3b046abfb053d80b52" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X PATCH \
  -d '{
        "endpoint": "https://www.your-other-endpoint.com/webhooks"
      }'

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "topic": "newsletter-email/sent",
    "endpoint": "https://www.your-endpoint.com/webhooks"
  }
}

EXAMPLE ERROR RESPONSE

{
  "errors": [
    "The chosen topic is invalid"
  ]
}

Update Webhook [PATCH/PUT]

https://commerce.campaignmonitor.com/api/v1/webhooks/{WEBHOOK_ID}

OAuth Scopes: write_webhook

If your client doesn’t support the PATCH method, PUT can be used to the same effect.

Request Body

Key Details
topic: string, optional
The topic to subscribe with this Webhook. Can’t be null.
endpoint: string, optional
URL where to publish this Webhook’s payload, when triggered. Can’t be null.

Response Body

When successful, the endpoint returns the newly created webhook. The returned data mimics that of the show endpoint:

Key Details
id: string
The updated Webhook’s ID.
topic: string
The event that triggers this webhook.
endpoint: string
Where the webhook’s payload is sent, when triggered. Must be a URI.
partnerApp: string, optional
The ID of the Partner App that created this webhook. Included only when authorization is made with the API key.

Any errors during creation will be identified by a 400 status code and a JSON object with an errors Array with string explanations of what went wrong.

Delete Webhook

Delete an existing Webhook to stop receiving data at the endpoint.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/webhooks/57b5aa3b046abfb053d80b52" \
  -H "X-ApiKey: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -X DELETE

Delete Webhook [DELETE]

https://commerce.campaignmonitor.com/api/v1/webhooks/{WEBHOOK_ID}

OAuth Scopes: write_webhook

Successful requests return nothing.

Async Jobs

An Async Job is created on certain API endpoints and user actions that we expect will take a long time to complete. Generally, when a job is created, you’ll receive a Job ID that you can poll using this API to:

  1. Check if the job’s completed;
  2. Get the job’s result; and
  3. Check the job for errors.

Due to the presumably large size of an Async Job’s results and how they’ll be less relevant as time advances, Async jobs expire 1 week after they’ve finished processing, being automatically removed.

List Async Jobs

Returns all the Async Jobs created for the authenticated shop. When using OAuth, only jobs started by the authenticated app are returned.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/async-jobs" \
  -H "X-ApiKey: YOUR_API_KEY"

EXAMPLE RESPONSE

{
  "data": [
    {
      "id": "57b5aa3b046abfb053d80b52",
      "kind": "newsletter-recipients",
      "status": "done",
      "startedAt": "2017-01-03T16:32:27.741Z",
      "completedAt": "2017-01-03T16:37:20.417Z",
      "result": "https://commerce.campaignmonitor.com/async-jobs/57b5aa3b046abfb053d80b52.csv"
    },
    {
      "id": "57b5aa3b046abfb053d80b54",
      "kind": "newsletter-recipients",
      "status": "pending"
    },
    {
      "id": "57b5aa3b046abfb053d80b57",
      "kind": "newsletter-recipients",
      "status": "failed",
      "startedAt": "2017-01-02T05:33:22.123Z",
      "completedAt": "2017-01-02T05:33:45.412Z",
      "error": "Something terrible has happened. Get in touch with support tout de suite!"
    }
  ]
}

List all Jobs [GET]

https://commerce.campaignmonitor.com/api/v1/async-jobs

OAuth Scopes: read_async_job

Response Body

The endpoint returns an object with a data key that is an Array with all the Async Jobs in the shop. It will limit output to the currently authenticated Partner App webhooks if authorized through OAuth.

Each Async Job includes the following info:

Key Details
id: string
The Async Job ID. Use it when calling single-job endpoints.
kind: string
What kind of job this is. Currently only supports “newsletters-recipients”.
status: string
The job’s status. One of “pending”, “done” or “failed”.
startedAt: string, optional
When this job started processing. Is an ISO 8601 encoded date. Is null if it hasn’t started yet.
completedAt: string, optional
When this job completed. Is null if it hasn’t finished yet. There’s a result or error if set. Is an ISO 8601 encoded date.
error: string, optional
An error message that indicates a problem when processing the job. There is no result if this is present.
result: string, optional
The final result from processing this job. Contents depend on job kind.
partnerApp: string, optional
The ID of the Partner App that created this Async Job. Included only when authorization is made with the API key.

Get Async Job

Returns the requested Async Job. When using OAuth, only jobs started by the authenticated app can be accessed.

# EXAMPLE REQUEST
$ curl "https://commerce.campaignmonitor.com/api/v1/async-jobs/57b5aa3b046abfb053d80b52" \
  -H "X-ApiKey: YOUR_API_KEY"

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "kind": "newsletter-recipients",
    "status": "done",
    "startedAt": "2017-01-03T16:32:27.741Z",
    "completedAt": "2017-01-03T16:37:20.417Z",
    "result": "https://commerce.campaignmonitor.com/async-jobs/57b5aa3b046abfb053d80b52.csv"
  }
}

Get an Async Job [GET]

https://commerce.campaignmonitor.com/api/v1/async-jobs/{ASYNC_JOB_ID}

OAuth Scopes: read_async_job

Response Body

The endpoint returns an object with a data key. The data key is an object with the Async Job’s properties. It will include the Partner App if authorized with an API key. The following keys are returned:

Key Details
id: string
The Async Job’s ID. The ID used to call this endpoint.
kind: string
What kind of job this is. Currently only supports “newsletters-recipients”.
status: string
The job’s status. One of “pending”, “done” or “failed”.
startedAt: string, optional
When this job started processing. Is an ISO 8601 encoded date. Is null if it hasn’t started yet.
completedAt: string, optional
When this job completed. Is null if it hasn’t finished yet. There’s a result or error if set. Is an ISO 8601 encoded date.
error: string, optional
An error message that indicates a problem when processing the job. There is no result if this is present.
result: string, optional
The final result from processing this job. Contents depend on job kind.
partnerApp: string, optional
The ID of the Partner App that created this Async Job. Included only when authorization is made with the API key.

Partner Apps API

This API comprises of management endpoints for Partner Apps. Because they’re unrelated to any Store, authentication is done through HMAC.

Get Partner App

Returns the saved info for the authenticated Partner App.

# EXAMPLE REQUEST
$ curl https://commerce.campaignmonitor.com/api/v1/partners/ \
  -H "Accept: application/json" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1N2I1YWEzYjA0NmFiZmIwNTNkODBiNTIifQ.sxd8uG4EkeIXHsIIVELrfGTIZcaTFE9a9YY-8HGHuOQ

EXAMPLE RESPONSE

{
  "data": {
    "id": "57b5aa3b046abfb053d80b52",
    "name": "Epic Forms",
    "email": "hello@epicforms.com",
    "website": "https://epicforms.com",
    "logo": "epicforms-logo.jpg",
    "redirectUri": "https://epicforms.com/oauth/auth"
  }
}

Show Current Partner App [GET]

Response Body

Returns JSON with a data key which contains the info for the authenticated Partner App:

Key Details
id: string
The Partner App’s ID. This is also the client_id used in OAuth.
name: string
The name of this Partner App.
email: string
The contact email for this Partner App.
website: string
The Partner App’s homepage.
logo: string
The Partner App’s logo, used in the OAuth authorize page. Can be a URL or a data URI.
redirectUri: string
The redirect URI used during OAuth. This value must match the argument received in the authorize call.

Update Partner App

Updates the saved info for the authenticated Partner App. Use this to update a logo or an OAuth redirect URI.

# EXAMPLE REQUEST
$ curl https://commerce.campaignmonitor.com/api/v1/partners/ \
  -H "Accept: application/json" \
  -H "Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiI1N2I1YWEzYjA0NmFiZmIwNTNkODBiNTIifQ.sxd8uG4EkeIXHsIIVELrfGTIZcaTFE9a9YY-8HGHuOQ" \
  -X PATCH \
  -d '{
        "name": "A Great Name 2",
        "email": "another_contact@partner.com",
        "website": "www.rebranded.com",
        "logo": "data:image/png;base64,iVBORw0...ggg==",
        "redirectUri": "https://www.rebranded.com/oauth/auth"
      }'

EXAMPLE RESPONSE

{
  "data": {
    "name": "A Great Name 2",
    "email": "another_contact@partner.com",
    "website": "www.rebranded.com",
    "logo": "",
    "redirectUri": "https://www.rebranded.com/oauth/auth"
  }
}

Update Partner App [PATCH]

Only the attributes that are present in the body will be updated. The logo must be a base64 encoded data URI.

Updateable Attributes

Key Details
name: string
The name of this Partner App.
email: string
The contact email for this Partner App.
website: string
The Partner App’s homepage.
logo: string
The Partner App’s logo, used in the OAuth authorize page. Must be a data URI.
redirectUri: string
The redirect URI used during OAuth. This value must match the argument received in the authorize call.

Errors

The CM Commerce API uses the following error codes:

Error Code Meaning
400 Bad Request – Something required is missing of the request is malformed
401 Unauthorized – Your API key is wrong
403 Forbidden – The requested resource is hidden for administrators only
404 Not Found – The specified endpoint, receipt or coupon could not be found
405 Method Not Allowed – You tried to access a resource with an invalid method
406 Not Acceptable – You requested a format that isn’t json
413 Request Entity Too Large – You sent too much data to us
429 Too Many Requests – You’re exceeding the API rate limit
500 Internal Server Error – We had a problem with our server. Try again later.
503 Service Unavailable – We’re temporarially offline for maintenance. Please try again later.