Set up promotion upsell messages

When working with promotions, you can configure promotion upsell messages for your shoppers.

Promotion upsell messages let your shoppers know if they are close to qualifying or have successfully qualified for a promotion. For example, if you have a promotion that says “Buy Two Dog Bowls Get a Free Collar”, when a shopper has put one dog bowl in their shopping cart, the upsell message might say “Buy another dog bowl and you’ll get a free collar!” Once they have put two dog bowls in their cart, the message changes to “Congratulations! You’re getting a free collar!”

Merchandisers can use the administration interface to select upsell messages to associate with promotions. To use these upsell messages, they must be associated with widgets so that they can be displayed in the appropriate locations.

This section describes how to create message tags and promotional upsell widgets using the REST API. For information on working with promotion upsell messages using the administration interface, refer to Manage Promotions.

The following are the steps to create promotion upsell messages. Some of these steps are, or can be, performed using the administration interface. You may not need to perform all of these steps, they are provided for context:

Understand promotion upsell messages

This section describes promotion upsell messages that are created using the REST API. For information on using the administrative interface, refer to Manage upsell messages. Upsell messages are displayed using messaging widgets that read tags indicating which and where messages appear. For example, promotion upsell messages can be displayed on the shopper’s checkout page, the site’s home page and the product description page.

There are three types of promotion upsell messages:

  • Not Qualified – This message indicates that the shopper has not yet qualified to receive the promotion.
  • Partially Qualified – This message indicates that the shopper is close to obtaining a promotion. The message may include specific actions that the shopper can take to obtain the promotion. You can provide placeholder variables that allows you to specify the values needed for a shopper’s cart qualification. This type of message also allows you to implement closeness qualifiers that you use to identify criteria that trigger messages.
  • Success – This message indicates that the shopper has reached the criteria needed to receive the promotion.

Note that you can create only one of each type of upsell message per promotion.

Promotions are associated to an order once a pricing operation is initiated. During the pricing operation, each promotion is evaluated. Once a promotion qualifies, it is removed from further evaluation. Upsell messages are specific to individual promotions and cannot be used across promotions.

Should the shopper no longer qualify for a promotion, the partially qualified message, or the unqualified message if the cart does not meet the qualifying criteria, replaces the success message.

A threshold level can be set for partially qualified messages. This allows you to set a specific threshold which, when the shopper reaches the level, displays the partially qualified message. This threshold is read by the pricing engine that uses the threshold as a boundary condition. For example, if you set a threshold for $30, once a shopper’s cart reaches $30, the promotion becomes qualified and a qualified upsell message is presented.

If the promotion has the same tag for all of the upsell messages, the partially qualified message will replace the not qualified message when the closeness qualifier fires. The success message will replace the partially qualified message when the promotion is applied, and the partially qualified message will replace the success message if the shopper no longer qualifies for the promotion. The not qualified message will replace the partially qualified message if the closeness qualifier no longer fires.

For additional information on promotion upsell messages, refer to Manage upsell messages.

Use the promotion upsell API

You can set up promotion upsell messages using the administration interface, as described in Manage upsell messages, or using the REST API with the endpoints listed in this section.

Create message tags

Messages use tags, in conjunction with promotion upsell messaging widgets, to indicate where an upsell message should appear on the storefront. A merchandiser uses the administration interface to select the tags associated with each message. A single upsell message can be associated with multiple tags.

To create or update message tags, use the messageTags API by issuing a POST command in /ccadmin/v1/messageTags. Use the message tag endpoints to work with tag item types.

Message tag endpoints allow you to manage tags, and include the following:

  • createMessageTag
  • getMessageTag
  • updateMessageTag
  • listMessageTags
  • deleteMessageTag

Refer to the API documentation for additional information on using these endpoints.

Use the createMessageTag endpoint to create and name a tag. The following example creates a tag named FREE_SHIPPING_HOMEPAGE_BANNER, indicating that this tag displays a message on the banner of the home page. When you create tags, name them with a term or phrase that will help you identify their use. For example, a tag named “FREE_SHIPPING_HOMEPAGE_BANNER” indicates that the message appears in the banner on the home page, or “CART_UPSELL” indicates that the message is displayed on the shopper’s cart:

// createMessageTag:
{
  "name": "FREE_SHIPPING_HOMEPAGE_BANNER"
}
// returns:
{
  "repositoryId" : "mt200006",
  "name" : "FREE_SHIPPING_HOMEPAGE_BANNER"
}

Note: Message tags are case sensitive. Also, when naming your message tags, do not use the following characters: < >, { }, {{ }} or " ".

You must remember to publish your new tags so that promotions and widgets can reference them. For information on publishing, refer to Understand publishing.

Work with promotion upsell messages

When you create a new message, provide a message and a tag value. The tag value is the name of the tag that you created and the message value is the text of the message that is displayed to the shopper. This text can be localized.

For example:

{
  "unqualifiedMessages": [
   { "message": "Spend $100 and get free shipping!",
     "tags": [
   { "name": "CART_UPSELL" },
   ] } ]
 }

The process of creating or updating a message differs only that you provide an existing message ID if updating.

Note: If you update a promotion without providing an ID, the system will create a new message, overwriting the message you are trying to update.

The following example updates an unqualified message with new text and creates an additional tag:
// Change any of the contents EXCEPT IDs.
// NOTE: The presence of the message ID indicates this is an existing message.
// This example changes the message, and adds a tag named "LOYALTY_CART". 
{
  "unqualifiedMessages": [
    { "repositoryId": "tm100003" 
      "message": " Spend $100 or 10 loyalty points and get free shipping!",
    "tags": [
      { “repositoryId: “tm100003”
        "name": "FREE_SHIPPING_HOMEPAGE_BANNER" },
      { "name": "LOYALTY_CART" } ] } ]
 }

Work with promotion endpoints

Use the following promotion endpoints to set up and configure upsell messages with closeness qualifiers and promotions:

  • getPromotion – This endpoint displays the upsell messages.
  • updatePromotion – This endpoint allows you to update both new and existing messages, as well as apply tags. There are three properties available on promotions that are relevant to upsell messages: unqualifiedMessages, qualifiedMessages, and closenessQualifier.

Use the updatePromotion endpoint to manage promotion messages by issuing a PUT command to /ccadmin/v1/promotions/{ID} to initiate a call for a specific promotion.

Use placeholder variables

Partially qualified messages can use placeholder variables to indicate where a value should be inserted. Placeholder variables are identified with double brackets ({{ }}). For example, if the shopper has put two dog bowls in the cart, you could present a message like “Buy 2 more dog bowls and get a free collar!” To do this, you would create the following message: “Buy <b>{{QuantityStillNeeded}}</b> more dog bowls and get a free collar!” Note that formatting should be put outside of the place holder brackets. Putting formatting tags within the double brackets will result in an error.

Be careful when crafting your message and avoid plural or singular tenses. You cannot create messages that change based on tense. For example, if you say “Buy 1 more bowl!” when you work with more than one object, the message would be “Buy 2 more bowl!” You messages should be more generic, for example, “You’ve almost got all of your bowls! You need X more to get free shipping!”

These variables, which are computed during the pricing operation, are as follows:

  • {{AmountSpent}} – The shopper’s current qualifying amount spent.
  • {{AmountStillNeeded}} – Identifies the amount still needed by the shopper to qualify for the promotion.
  • {{QuantityBought}} – Identifies the number of qualifying items in the shopper’s cart.
  • {{QuantityStillNeeded}} – Indicates the minimum number of items needed in the shopper’s cart to qualify for the promotion.

Note that this list contains the accepted place holders. Any other placeholder variables that you create, even if you use the curly braces ({{ }}), is treated as literal text and will be seen by your shoppers.

When you create a message, you can indicate where you want a dynamic variable by using the dynamic variable-specific syntax. When a widget queries for messages, these numbers are calculated dynamically and then returned in the message. For example, to create the partially qualified message “You’re almost there! Spend X and you’ll get free shipping!” you would provide the message ID, and the necessary tags.

{
  "closenessMessages":
   { "repositoryId": "tm100003" 
     "message" : “You’re almost there! Spend {{AmountStillNeeded}}, and you’ll get free shipping!",
   "tags": [
     { "name": "FREE_SHIPPING_HOMEPAGE_BANNER" }]} 
}

Understand closeness qualifiers

Closeness qualifiers set the boundaries on how close a shopper is to qualifying for a promotion by holding a condition value and the corresponding message for that condition. Use the updatePromotion endpoint to create a closeness qualifier. The following example creates a closeness qualifier that displays the partially qualified message, also known as a closeness message, when the shopper’s cart hits $35:

{
  "closenessQualifiers" : [
    {
      "closenessMessages" : [
        { 
          "message" : "<b> You’re almost there! Spend {{AmountStillNeeded}}, and you’ll
               get free shipping!"</b>",
          "tags" : [{"name" : "FREE_SHIPPING_HOMEPAGE_BANNER"}]
        } ] } ],
}

The process of creating or updating a closeness qualifier differs only that you provide an existing ID if updating.

To delete a qualifying condition, pass an empty array for the closenessQualifiers property value.

The following is an example getPromotion call:

...
{
  "unqualifiedMessages": [
    {
      "repositoryId": "tm100001",
      "text": "Spend $100 and get free shipping!",
      "tags": []
    }
  ],
  "qualifiedMessages": [
    {
      "repositoryId": "tm100003",
      "text": "Congratulations! This order is shipping for free!",
      "tags": [
        { "name": "CART_UPSELL" },
        { "name": "FREE_SHIPPING_HOMEPAGE_BANNER" }
      ]
    }
  ],
 "closenessQualifiers": [
   {
     "repositoryId": "2015",
     "closenessMessages": [
       {
         "text": "You’re almost there! Spend {{AmountStillNeeded}} and you’ll
            get free shipping!",
         "tags": [
           { "name": "FREE_SHIPPING_HOMEPAGE_BANNER" }
         ]
        }
       ]
      }
     ],
       "templateValues" : [
      {"customer_alert_spend_value" : 35 } ]
   }
 ...

The following is a list of the promotion templates that support closeness qualifiers and their threshold value names in the templateValues property. For information on working with promotion templates, refer to Create a promotion. Threshold value names are required when providing input for closeness qualifiers. The following table describes the threshold value names used by each promotion template:

Promotion Template Threshold Value Name
item/bogo closeness_value
item/bogoSortBy closeness_value
item/buyItemXGetGWP closeness_value
item/spendYGetGWP customer_alert_spend_value
item/spendYInXGetItemDiscount customer_alert_spend_value
item/spendYInXGetItemDiscountSortBy customer_alert_spend_value
order/buyXGetOrderDiscount closeness_value
order/spendYGetOrderDiscount spend_close_value
order/spendYInXGetOrderDiscount customer_alert_spend_value
order/tieredOrderDiscount spend_close_value
shipping/buyXGetShippingDiscount closeness_value
shipping/spendYGetShippingDiscount spend_close_value
shipping/spendYInXGetShippingDiscount customer_alert_spend_value

Work with order store endpoints

The order store endpoint payloads contain the upsell messages. This includes priceOrder, updateCurrentProfileOrder, updateOrder and createOrder endpoints.

Each pricing endpoint response contains a list of promotion upsell messages that contain a text and a tags property. The text property sets the message value, while the tags property indicates the name or names of the associated tags. For example:

},
  "pricingMessages": {
    "promotionUpsellMessages":[
    {
      "text":"Spend $45 get free shipping!",
      "tags":["BANNER_UPSELL", "FOOTER_UPSELL"]
    },
    {
      "text":"You’re almost there! Spend $100 and you’ll get free shipping!",
      "tags":["CART_UPSELL"]
    },
    {
      "text":"Add one more dog bowl and get a free collar!",
      "tags":["CART_UPSELL"]
    },
    {
      "text":"Buy any 2 All Natural Chew Toys and get 50%!",
      "tags":["CART_UPSELL"]
    }
  ]},

You can use the /ccstore/v1/orders/getUpsellMessages call to return unqualified or success messages. For example:

{
  "promotionUpsellMessages":[
    {
      "text":"Spend $45 and you’ll get free shipping!",
      "tags":["CART_UPSELL"]
    },
    {
      "text":"Congratulations! You have qualified for a free collar!",
      "tags":["FREE_SHIPPING_HOMEPAGE_BANNER","CART_UPSELL"]
     }]
 }

Create promotion upsell widgets

To display your upsell messages, you create promotion upsell widgets that are used on page layouts. The promotion upsell widget can be added to any layout or page where messages are needed. You can also use multiple instances of the widget on different or the same pages. Messages are available to promotion messaging widgets using tags that are associated with the messages. This allows the relevant promotion message to be displayed in the correct location.

A messaging widget allows you to display particular upsell messages. Messages use the tags that you created earlier in Create message tags to communicate with the widget. Using widgets allows you to select the available tags, as well as specify a threshold for how many messages to display.

The widget uses the tags field to identify the message that will be displayed by the widget. The field can contain a single tag name, or a comma-separated list of tag names. The maximum number of messages that can be displayed is configured using the messageLimit field.

If there are widgets configured to display promotion messages with the same tag on more than one location on storefront layout, the system cannot display a different message from the sequenced list in each location. You must ensure that your messages use different tags.

The promotion upsell widget uses the promotion upsell container view model, which holds all of the upsell messages obtained from processing and getUpsellMessages endpoint calls. The widget instances interact with the view model to get messages with matching tags. This view model also makes endpoint calls to get non-qualified messages from the getUpsellMessage endpoint. The cart view model also populates the promotion upsell container view model with promotion messages that come from pricing calls.

A promotionUpsell widget could be created in a way similar to the following example. The widget.json file might contain the following:

{
  "config": {
    "tags":"CART_UPSELL",
    "messageLimit":"1"
  },
  "availableToAllPages": true,
   "global": false,
   "globalEnabled": false,
   "i18nresources": "promotionUpsell",
   "imports": [],
   "javascript": "promotion-upsell",
   "jsEditable": false,
   "name": "Promotion Upsell Widget",
   "version": 1
}

The config.json file might contain the following:

{
  "widgetDescriptorName": "promotionUpsell",
  "properties": [
    {
      "id": "tags",
      "type": "stringType",
      "name": "tags",
      "helpTextResourceId": "tagsHelpText",
      "labelResourceId": "tagsLabel",
      "defaultValue": ""
    },
    {
      "id": "messageLimit",
      "type": "stringType",
      "name": "messageLimit",
      "helpTextResourceId": "messageLimitHelpText",
      "labelResourceId": "messageLimitLabel",
      "defaultValue": "1",
      "required": true
    }
  ]
}

The widget’s JavaScript might be similar to the following, which you could store in a file named promotion-upsell.js:

define(
//-------------------------------------------------------------------
// DEPENDENCIES
//-------------------------------------------------------------------
  ['knockout', 'pubsub', 'viewModels/promotionUpsellContainer'],
//-------------------------------------------------------------------
// MODULE DEFINITION
//-------------------------------------------------------------------
  function(ko, pubSub, promotionUpsellContainer) {
  "use strict";
  return {
   /** Widget root element ID */
   WIDGET_ID: 'promotionUpsell',
   onLoad : function(widget) {
     widget.messageLimit = widget.messageLimit && null != widget.messageLimit()
       && widget.messageLimit != "" ? parseInt(widget.messageLimit()) :
       parseInt("1");
     widget.promotionUpsellContainer = promotionUpsellContainer.getInstance();
     widget.widgetTags = widget.tags && null != widget.tags() && widget.tags()
       != "" ? widget.tags().split(","):[];
     widget.promotionUpsellMessages = ko.pureComputed(function() {
       var promoMessages = widget.promotionUpsellContainer.
           promotionUpsellMessages().filter(function(message, index) {
         var widget = this;
         var displayMessage = false;
         widget.widgetTags.forEach(function(widgetTags) {
           for (var i=0; i<message.tags.length; i++) {
             if(message.tags[i] == widgetTags) {
               displayMessage = true;
               break;
             }
           }
         });
       return displayMessage;
       }, widget);
      return promoMessages.slice(0,widget.messageLimit);
     }).extend({ rateLimit: 500 });
     widget.items = ko.computed(function(){
       return widget.cart().allItems();
     }).extend({ rateLimit: 1000 });
     widget.getNonQualifiedMessages = function () {
       if (widget.cart().items().length == 0) {
         widget.promotionUpsellContainer.getNonQualifiedMessages();
       }
     };
     widget.getNonQualifiedMessagesSubsciption = function () {
     widget.items.subscribe(function(newVal) {
       if (newVal.length == 0) {
         widget.promotionUpsellContainer.getNonQualifiedMessages();
       }
      });
     };
     if(!widget.promotionUpsellContainer.
         isNonQualifiedMessagesSubscribedToQuantity) {
       widget.promotionUpsellContainer.isNonQualifiedMessagesSubscribedToQuantity
         = true;
       widget.getNonQualifiedMessages();
       $.Topic(pubSub.topicNames.PAGE_LAYOUT_UPDATED).subscribe(widget.
         getNonQualifiedMessagesSubsciption);
       $.Topic(pubSub.topicNames.USER_LOGIN_SUCCESSFUL).subscribe(widget.
         getNonQualifiedMessages);
       $.Topic(pubSub.topicNames.USER_LOGOUT_SUCCESSFUL).subscribe(widget.
         getNonQualifiedMessages);
       $.Topic(pubSub.topicNames.USER_AUTO_LOGIN_SUCCESSFUL).subscribe(widget.
         getNonQualifiedMessages);
       }
     }
   }
 }
 );

The locale resources, which are part of the configuration and provide text, might be similar to this:

{
  "resources": {  
    "tagsHelpText":"Add the list of tags that this widget uses to display promotions.",
    "tagsLabel":"List of tags this this widget uses to display promotions.",
    "messageLimitLabel":"Message Limit Label",
    "messageLimitHelpText":"The HelpText message limit."
  }
}

The display.template file might contain the following:

<div id="CC-promotionUpsell">
  <!-- ko foreach : {data: $data.promotionUpsellMessages(), as: 'message'}-->
    <div class="cc-rich-text" data-bind="html: message.text"/>
  <!-- /ko -->
</div>

If you have multiple widgets you must query whatever mechanism you use for storing the results of the API call for that specific widget.