LoyaltyLion

Integrate LoyaltyLion in Bloomreach Engagement using Omniconnect! This integration allows you to use LoyaltyLion functions in Bloomreach Engagement. Use this integration to feed events and customer property updates from LoyaltyLion, such as tiers, points, earnings, vouchers, upgrades, or downgrades, into Bloomreach Engagement.

Use cases

You can use LoyaltyLion for tasks such as:

  • Welcome emails
  • Monthly updates about loyalty points
  • Warnings about the expiration of loyalty points
  • Emails about the next tier
  • Emails about upgraded tiers
  • Reminders about unused vouchers

How to set it up

🚧

Prerequisites

  • A Bloomreach Engagement project with integrations access
  • Ability to use LoyaltyLion API to set up webhooks
  • Knowledge of JavaScript

1. Set up Omniconnect

This integration makes use of the Omniconnect feature in Bloomreach Engagement. To set up Omniconnect:

  1. Go to your Bloomreach Engagement environment
  2. Go to Data & Assets > Integrations > + Add new integration
  1. Find Omniconnect and click on + Add integration
  2. Give the integration a name and click on Save integration
  3. Click on the Transformation tab
  4. Paste the transformation function into the appropriate text field
  1. Adjust the email_id customer identifier name, if required
  1. Go back to the Settings tab and copy the Omniconnect URL

2. Configure LoyaltyLion

Use the LoyaltyLion API to enable webhooks on the required topics. The topics refer to different actions that will trigger webhooks to send data to Bloomreach. Decide which topics suit you and configure them in the LoyaltyLion API. You can use Postman, for example.

The following topics were used in the transformation function.

Requirements for the initial integration

  • customers/update
  • program_events/customer.tier_upgraded
  • program_events/customer.tier_downgraded
  • program_events/customer.points_earned
  • program_events/customer.claimed_reward
  • program_events/customer.approaching_tier_upgrade

The customers/update topic triggers a customer update call. All program_events topics trigger events with names taken from the text following the ".", and prefixed with loyalty_lion. For example, program_events/customer.tier_upgraded > loyalty_lion_tier_upgraded.

Customer properties tracked

  • loyalty_lion_customer_updated_at
  • loyalty_lion_points_approved
  • loyalty_lion_points_pending
  • loyalty_lion_points_spent
  • loyalty_lion_rewards_claimed
  • loyalty_lion_tier_name

Events tracked and their properties

  • loyalty_lion_approaching_tier_upgrade
    • current_tier_default
    • current_tier_hidden
    • current_tier_id
    • current_tier_lower_bound
    • current_tier_name
    • current_tier_number
    • current_tier_upper_bound
    • email
    • next_tier_default
    • next_tier_hidden
    • next_tier_id
    • next_tier_lower_bound
    • next_tier_name
    • next_tier_number
    • next_tier_upper_bound
  • loyalty_lion_tier_downgraded
    • email
    • new_tier_default
    • new_tier_hidden
    • new_tier_id
    • new_tier_lower_bound
    • new_tier_name
    • new_tier_number
    • new_tier_upper_bound
    • previous_tier_default
    • previous_tier_hidden
    • previous_tier_id
    • previous_tier_lower_bound
    • previous_tier_name
    • previous_tier_number
    • previous_tier_upper_bound
  • loyalty_lion_tier_upgraded
    • email
    • new_tier_default
    • new_tier_hidden
    • new_tier_id
    • new_tier_lower_bound
    • new_tier_name
    • new_tier_number
    • new_tier_upper_bound
    • previous_tier_default
    • previous_tier_hidden
    • previous_tier_id
    • previous_tier_lower_bound
    • previous_tier_name
    • previous_tier_number
    • previous_tier_upper_bound
  • loyalty_lion_points_earned
    • activity_id
    • activity_merchant_id
    • activity_order
    • activity_resource
    • activity_state
    • activity_value
    • email
    • rule_id
    • rule_name
    • rule_title
    • transaction_created_at
    • transaction_id
    • transaction_points_approved
    • transaction_points_pending
    • transaction_resource
    • transaction_adjustment
  • transaction_claimed_reward
    • email
    • discount_amount
    • discount_type
    • reward_type
    • title
    • voucher_code

📘

Have a look at the Postman collection code for further assistance

Transormation function

This function handles webhooks for different topics in different formats, though some common elements exist. It sets some common payload data at the start and then uses a switch statement based on the incoming topic to add the specific data required for that event. Depending on the topic, it generates either a customer update or an event. An email_id identifier, which can be edited, is required.

/**
 * Handler is the entry point for the function that enables the transformation of the data.
 * @param data
 * @returns {*}
 */
function handler(data) {
    const topicParts = data.topic.split( "/" );
    const email = topicParts[0] == "customers" ? data.payload.customer.email : data.payload.properties.customer.email;
    const properties = topicParts[0] == "customers" ? {} : {
        "email": email
    };
    const timestamp_name = topicParts[0] == "customers" ? "update_timestamp" : "timestamp";
    const timestamp_value = topicParts[0] == "customers" ? data.payload.customer.updated_at : data.created_at;
    const output = [ {
        "name": topicParts[0].replace( "program_", "customers/" ),
        "data": {
            "customer_ids": {
                "email_id": email
            },
            "properties": properties,
            [ timestamp_name ]: Math.round( Date.parse( timestamp_value ) / 1000 )
        }
    } ];
    const body = output[0].data;	//for easier referencing later
    
    // If this is an event, set the name based on Loyalty Lion topic.
    if (topicParts[0] == "program_events") {
    	body.event_type = topicParts[1].replace("customer.", "loyalty_lion_")
    }

    switch ( topicParts[1] ) {
        case "update": {
        	// Customer properties update
            body.properties.loyalty_lion_points_approved = data.payload.customer.points_approved;
            body.properties.loyalty_lion_points_pending = data.payload.customer.points_pending;
            body.properties.loyalty_lion_points_spent = data.payload.customer.points_spent;
            body.properties.loyalty_lion_rewards_claimed = data.payload.customer.rewards_claimed;
            body.properties.loyalty_lion_customer_updated_at = body.update_timestamp;
            body.properties.loyalty_lion_tier_name = data.payload.customer.loyalty_tier_membership.loyalty_tier.name;

            break;
        }
        case "customer.tier_upgraded":
        case "customer.tier_downgraded": 
        case "customer.approaching_tier_upgrade": {
        	// These three are very similar, but have slightly different tier object names within the payload
        	const tierObjects = ["previous_tier","next_tier","current_tier","new_tier"];
        	
        	// Loop through all available tier objects and set into properties
        	for (const obj of tierObjects) {
	            for (const prop in data.payload.properties[obj]) {
	            	body.properties[obj + "_" + prop] = data.payload.properties[obj][prop];
	            }
        	}

            break;
        }
        case "customer.points_earned": {
        	// This has a more complex structure than most. transaction > activity > rule is a nested structure
            for (const prop in data.payload.properties.transaction) {
            	if (prop != "activity") {
	            	body.properties["transaction_" + prop] = data.payload.properties.transaction[prop];
            	}
            }
            for (const prop in data.payload.properties.transaction.activity) {
            	if (prop != "rule") {
	            	body.properties["activity_" + prop] = data.payload.properties.transaction.activity[prop];
            	}
            }
            if(data.payload.properties.transaction.activity) {
	            for (const prop in data.payload.properties.transaction.activity.rule) {
		            body.properties["rule_" + prop] = data.payload.properties.transaction.activity.rule[prop];
	            }
			}
            break;
        }
        default: {
        	// Any other event we aren't specifically catering for can be handled in this generic way - includes customer.claimed_reward.
            for (const prop in data.payload.properties) {
				// capture all properties except customer
            	if (prop != "customer") {
	            	body.properties[prop] = data.payload.properties[prop];
            	}
            }
        }
    }

    return output;
}

Postman collection code

{
  "info": {
    "_postman_id": "77b293f0-dbf1-491d-b96a-7439f77f8242",
    "name": "Loyalty Lion API",
    "schema": "https://schema.getpostman.com/json/collection/v2.1.0/collection.json",
    "_exporter_id": "28889212"
  },
  "item": [
    {
      "name": "List Webhooks",
      "request": {
        "method": "GET",
        "header": [],
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Delete Webhook",
      "request": {
        "method": "DELETE",
        "header": [],
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks/123456",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks",
            "123456"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Create Webhook - approaching_tier_upgrade",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "raw",
          "raw": "{\"webhook\":{\"topic\":\"program_events/customer.approaching_tier_upgrade\",\"address\":\"{{webhookUrl}}\"}}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Create Webhook - update",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "raw",
          "raw": "{\"webhook\":{\"topic\":\"customers/update\",\"address\":\"{{webhookUrl}}\"}}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Create Webhook - tier_upgraded",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "raw",
          "raw": "{\"webhook\":{\"topic\":\"program_events/customer.tier_upgraded\",\"address\":\"{{webhookUrl}}\"}}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Create Webhook - tier_downgraded",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "raw",
          "raw": "{\"webhook\":{\"topic\":\"program_events/customer.tier_downgraded\",\"address\":\"{{webhookUrl}}\"}}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Create Webhook - points_earned",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "raw",
          "raw": "{\"webhook\":{\"topic\":\"program_events/customer.points_earned\",\"address\":\"{{webhookUrl}}\"}}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks"
          ]
        }
      },
      "response": []
    },
    {
      "name": "Create Webhook - claimed_reward",
      "request": {
        "method": "POST",
        "header": [],
        "body": {
          "mode": "raw",
          "raw": "{\"webhook\":{\"topic\":\"program_events/customer.claimed_reward\",\"address\":\"{{webhookUrl}}\"}}",
          "options": {
            "raw": {
              "language": "json"
            }
          }
        },
        "url": {
          "raw": "https://api.loyaltylion.com/v2/webhooks",
          "protocol": "https",
          "host": [
            "api",
            "loyaltylion",
            "com"
          ],
          "path": [
            "v2",
            "webhooks"
          ]
        }
      },
      "response": []
    }
  ],
  "auth": {
    "type": "basic",
    "basic": [
      {
        "key": "password",
        "value": "{{secret}}",
        "type": "string"
      },
      {
        "key": "username",
        "value": "{{token}}",
        "type": "string"
      }
    ]
  },
  "event": [
    {
      "listen": "prerequest",
      "script": {
        "type": "text/javascript",
        "exec": [
          ""
        ]
      }
    },
    {
      "listen": "test",
      "script": {
        "type": "text/javascript",
        "exec": [
          ""
        ]
      }
    }
  ]
}

Limitations

Loyalty Lion sends quite a lot of data with each payload in a rather nested structure. The transformation function only takes selected attributes and flattens the structure for the Engagement events. Therefore, not everything is included by default. You may have different requirements for which data points you want to capture.