Example Loyalty Scheme
This guide provides an end-to-end example of how to setup a loyalty scheme. The example loyalty scheme has the following characteristics:
- Customers earn 1% points on their purchases that are valid for 1 year
- Customers are given 100 points for signing up to a newsletter
- Customers in the loyalty scheme are given early access to a sale
- Customers can choose to spend their points on their purchases
For this example scheme, customers won't be automatically enrolled in the scheme.
For more details on loyalty schemes see the the following guides:
- Loyalty Schemes Overview
- Management Tooling - Loyalty Schemes
- Loyalty Schemes Management using the Builder API
Properties Setup
The first thing we need to do is create the property we're going to use to uniquely identify entries in the loyalty scheme.
For this scheme it will be a unique customer ID (a UUID):
Scheme Setup
Next, we'll create the loyalty scheme. Go to the "Loyalty" section of the tooling and click "Add Loyalty Scheme". The "Create Loyalty Scheme" page is displayed:
Give the scheme a name and choose the "User ID" property as the "Scheme Entry Property".
Now we have a loyalty scheme we can start creating discounts that use the loyalty scheme. However, there are no customers in the scheme and since we don't want customers to be automatically enrolled we need to enrol them.
Enrolling Customers in the Scheme
For this example we will enrol a customer using the management tooling. In a more realistic scenario you may integrate with your customer management system to automatically enrol customers using the Builder API.
On the loyalty scheme listing page, click the scheme you have created and click the "Create New Entry" button. The "Add Entry" sidebar is displayed:
- Add a unique "Entry Identifier" (e.g.
48892b39-2407-4d62-aba5-003a0117aa3a
as we are using our customer UUID). - Leave the "Balance" as 0 as we don't want to give the customer any points
- Choose "Staging" for the "Data Instance" as we are testing the scheme.
Click the "Create Entry" button.
Accruing Points
Newsletter Sign-up
The first discount we will create is to give the customer 100 points for signing up to a newsletter.
To do this we'll create some properties so we can notify the system a user has signed-up to a newsletter.
We'll create a top level "Events" property of type Object
:
We'll now create a child property called "Name":
We'll now create a discount that gives 100 points when an event name of SignedUpToNewsletter
is passed to the evaluation endpoint of the Processor API.
Note, since customers shouldn't be automatically enrolled in the scheme, we add a condition to check they are part of the scheme already.
Go to the Discounts section of the tooling and click the "Add discount" button.
Give the discount a name of "Newsletter Sign-up - Award Loyalty Points".
Click "Add Condition", edit the condition and click "Add" next to "Eligibility". Add an expression as shown below:
This ensures only customers who are already enrolled in the scheme get the points when they sign-up to the newsletter.
Click "Done" on the "Eligibility" expression sidebar and then "Done" on the "Condition" sidebar.
Click "Add Action" and choose "Accrue Loyalty Points". Edit the action and complete the form as shown below:
Click "Done". The discount should appear as below:
Click the "Save" button.
Processor API Example
Below are example request and responses from the evaluate endpoint.
Request
{
"events": {
"name": "SignedUpToNewsletter"
},
"customer": {
"userId": "48892b39-2407-4d62-aba5-003a0117aa3a"
},
"settings": {
"dataInstance": "Staging",
"commit": true
}
}
Response
{
"actions": [
{
"id": "c65ff99c-807b-443b-8d0a-0f15fcf2334f",
"discountId": "d7e43bb5-1de8-4976-b34b-0d01492709d2",
"type": "AccrueLoyaltyPoints",
"loyaltySchemeId": "05a35e84-8e55-409f-9f87-76d55cbd0e6c",
"qualifiedCouponCode": null,
"pointsAccrued": 100,
"startDate": null,
"expiryDate": null,
"displayMessages": []
}
],
"basket": null,
"aggregates": {
"total": 0,
"totalAmountOff": 0
},
"costs": [],
"commitId": "37c5e2eb-4079-4dbd-a1db-607bf232b0a6",
"evaluationLog": null
}
Note, the client application would need validation to only pass this SignedUpToNewsletter
event if they haven't signed-up previously otherwise users can keep subscribing/un-subscribing and re-subscribing.
Now if you lookup the entry in the tooling you will see the balance and transactions have been updated:
Discount to earn points on purchases
Next we'll setup a discount to allow customers to earn 1% of points on their purchases that are valid for 1 year. Note, since customers shouldn't be automatically enrolled in the scheme, we add a condition to check they are part of the scheme already.
Add a discount with the name "Accrue Points for Purchases".
Click "Add Condition", edit the condition and click "Add" next to "Eligibility". Add an expression as shown below:
Click "Done" on the "Eligibility" expression sidebar and then "Done" on the "Condition" sidebar.
Click "Add Action" and choose "Accrue Loyalty Points". Edit the action and complete the form as shown below:
Click "Done". The discount should appear as below:
Click the "Save" button.
Processor API Example
Below are example request and responses from the evaluate endpoint.
Request
{
"basket": {
"items": [
{
"quantity": 2,
"price": 58.99
}
]
},
"costs": [
{
"name": "Shipping",
"value": 5.99
}
],
"context": {
"currencyCode": "GBP"
},
"customer": {
"userId": "48892b39-2407-4d62-aba5-003a0117aa3a"
},
"settings": {
"dataInstance": "Staging",
"commit": true,
"explain": false
}
}
Response
{
"actions": [
{
"id": "f1ea04b4-5d52-4973-ae62-e220194355dd",
"discountId": "5c0b024b-e371-449e-9339-b1e40ad5138d",
"type": "AccrueLoyaltyPoints",
"loyaltySchemeId": "ebc6bec7-0b36-4860-bf1c-112e6bb2ea65",
"qualifiedCouponCode": null,
"pointsAccrued": 1,
"startDate": null,
"expiryDate": "2025-07-19T15:18:57.2018921",
"displayMessages": []
}
],
"basket": {
"total": 117.98,
"totalAmountOff": 0,
"items": [
{
"total": 117.98,
"totalAmountOff": 0,
"actions": []
}
]
},
"aggregates": {
"total": 123.97,
"totalAmountOff": 0
},
"costs": [
{
"name": "Shipping",
"value": 5.99,
"totalAmountOff": 0,
"actions": []
}
],
"commitId": "d095d352-21ce-4316-ab28-c254ec77bc55",
"evaluationLog": null
}
Discount to give customers in the loyalty scheme early access to a sale
We'll setup a sale for Black Friday 2024 (29 November) to give 10% off when customers spend 100 GBP.
Firstly we'll create a discount that gives members of the loyalty scheme the discount from the 25 November.
Add a discount with the name "Sale - Early Access". Set the start date to 25 November 00:00 and end date to 29 November 23:59.
Click "Add Condition" and edit the condition. Choose a "Type" of "Minimum Spend" and add an entry for GBP 100. Add an eligibility expression for "Active in scheme" as in the previous discount.
Click "Done" on the "Eligibility" expression sidebar and then "Done" on the "Condition" sidebar.
Click "Add Action" and choose "Amount Off Basket". Edit the action and complete the form as shown below:
Click "Done". The discount should appear as below:
Click the "Save" button.
We'll now create a discount to give customers not part of the loyalty scheme the discount on 29 November. Note, this discount checks the customer isn't part of the loyalty scheme, otherwise on Black Friday both discounts would apply for members of the loyalty scheme.
Add a discount with the name "Sale". Set the start date to 29 November 00:00 and end date to 29 November 23:59.
Click "Add Condition" and edit the condition. Choose a "Type" of "Minimum Spend" and add an entry for GBP 100. Add an eligibility expression for "Active in scheme" "Is equal to" "false" like below:
Click "Done" on the "Eligibility" expression sidebar and then "Done" on the "Condition" sidebar.
Click "Add Action" and choose "Amount Off Basket". Set this up in the same way as the "Sale - Early Access" discount.
Click "Done". The discount should appear as below:
Click the "Save" button.
Processor API Example
Request
You can preview the future discount using the utcNow
setting. E.g.
{
"basket": {
"items": [
{
"quantity": 2,
"price": 58.99
}
]
},
"costs": [
{
"name": "Shipping",
"value": 5.99
}
],
"context": {
"currencyCode": "GBP"
},
"customer": {
"userId": "48892b39-2407-4d62-aba5-003a0117aa3a"
},
"settings": {
"dataInstance": "Staging",
"commit": false,
"explain": false,
"utcNow": "2024-11-25T10:00:00Z"
}
}
Response
{
"actions": [
{
"id": "2a918852-4b2e-45b2-b62d-e6e2e75aee5d",
"discountId": "5c0b024b-e371-449e-9339-b1e40ad5138d",
"type": "AccrueLoyaltyPoints",
"loyaltySchemeId": "ebc6bec7-0b36-4860-bf1c-112e6bb2ea65",
"qualifiedCouponCode": null,
"pointsAccrued": 1,
"startDate": null,
"expiryDate": "2025-11-25T10:00:00",
"displayMessages": []
},
{
"id": "69f63a33-2f3d-4e61-814e-87d41662ac11",
"discountId": "bd56920e-2e2b-4223-b11f-3e1e7ed4575b",
"type": "AmountOffBasket",
"qualifiedCouponCode": null,
"amountOffType": "PercentOff",
"value": 10,
"amountOff": 11.79,
"displayMessages": []
}
],
"basket": {
"total": 106.19,
"totalAmountOff": 11.79,
"items": [
{
"total": 106.19,
"totalAmountOff": 11.79,
"actions": [
{
"id": "69f63a33-2f3d-4e61-814e-87d41662ac11",
"subItemId": 1,
"amountOff": 5.9
},
{
"id": "69f63a33-2f3d-4e61-814e-87d41662ac11",
"subItemId": 2,
"amountOff": 5.89
}
]
}
]
},
"aggregates": {
"total": 112.18,
"totalAmountOff": 11.79
},
"costs": [
{
"name": "Shipping",
"value": 5.99,
"totalAmountOff": 0,
"actions": []
}
],
"commitId": null,
"evaluationLog": null
}
Discount to allow customers to spend points on purchases
We need to create a property to notify the evaluation process if the customer has chosen to spend their points. Note this isn't required if customer's points should be automatically spent.
We'll create a boolean property called "SpendPoints" on the "Customer" object:
Now we'll create the discount to spend points.
Add a discount with the name "Pay with Points".
Click "Add Condition", edit the condition and click "Add" next to "Eligibility". Add an expression as shown below:
Click "Done" on the "Eligibility" expression sidebar and then "Done" on the "Condition" sidebar.
Click "Add Action" and choose "Pay with Loyalty Points". Edit the action and complete the form as shown below:
A ratio of 0.01 points to GBP is used (100 points gives 1 GBP off)
Click "Done". The discount should appear as below:
Click the "Save" button.
Processor API Example
Below are example request and responses from the evaluate endpoint.
Request
{
"basket": {
"items": [
{
"quantity": 2,
"price": 58.99
}
]
},
"costs": [
{
"name": "Shipping",
"value": 5.99
}
],
"context": {
"currencyCode": "GBP"
},
"customer": {
"userId": "48892b39-2407-4d62-aba5-003a0117aa3a",
"spendPoints": true
},
"settings": {
"dataInstance": "Staging",
"commit": false,
"explain": false
}
}
Response
{
"actions": [
{
"id": "f4e08406-25c1-4500-9ac4-453abad6bea4",
"discountId": "5c0b024b-e371-449e-9339-b1e40ad5138d",
"type": "AccrueLoyaltyPoints",
"loyaltySchemeId": "ebc6bec7-0b36-4860-bf1c-112e6bb2ea65",
"qualifiedCouponCode": null,
"pointsAccrued": 1,
"startDate": null,
"expiryDate": "2025-07-19T16:10:16.294221",
"displayMessages": []
},
{
"id": "631b54e9-d830-424a-a087-217a1f5f48bd",
"discountId": "d5222096-c086-4d96-8675-87f8f4b17962",
"type": "AmountOffBasket",
"qualifiedCouponCode": null,
"amountOffType": "AmountOff",
"value": 1,
"amountOff": 1,
"displayMessages": []
},
{
"id": "8f29726b-72dd-470d-bc0d-f04a49d86f10",
"discountId": "d5222096-c086-4d96-8675-87f8f4b17962",
"type": "RedeemLoyaltyPoints",
"loyaltySchemeId": "ebc6bec7-0b36-4860-bf1c-112e6bb2ea65",
"qualifiedCouponCode": null,
"pointsRedeemed": 100,
"displayMessages": []
}
],
"basket": {
"total": 116.98,
"totalAmountOff": 1,
"items": [
{
"total": 116.98,
"totalAmountOff": 1,
"actions": [
{
"id": "631b54e9-d830-424a-a087-217a1f5f48bd",
"subItemId": 1,
"amountOff": 0.5
},
{
"id": "631b54e9-d830-424a-a087-217a1f5f48bd",
"subItemId": 2,
"amountOff": 0.5
}
]
}
]
},
"aggregates": {
"total": 122.97,
"totalAmountOff": 1
},
"costs": [
{
"name": "Shipping",
"value": 5.99,
"totalAmountOff": 0,
"actions": []
}
],
"commitId": null,
"evaluationLog": null
}
Discount Ordering
Note, with the current discount ordering AccrueLoyaltyPoints
is evaluated first. This is not what we want here because this will accrue points on the total before it has been discounted.
In the example request and response below, the customer has over 20000 points:
Request
{
"basket": {
"items": [
{
"quantity": 1,
"price": 200
}
]
},
"context": {
"currencyCode": "GBP"
},
"customer": {
"userId": "48892b39-2407-4d62-aba5-003a0117aa3a"
},
"settings": {
"dataInstance": "Staging",
"commit": false,
"explain": false
}
}
Response
{
"actions": [
{
"id": "7ec108e6-09ad-498d-9802-4cc3bd3278b1",
"discountId": "5c0b024b-e371-449e-9339-b1e40ad5138d",
"type": "AccrueLoyaltyPoints",
"loyaltySchemeId": "ebc6bec7-0b36-4860-bf1c-112e6bb2ea65",
"qualifiedCouponCode": null,
"pointsAccrued": 2,
"startDate": null,
"expiryDate": "2025-07-22T13:51:11.1155437",
"displayMessages": []
},
{
"id": "e3ee1003-19b1-4ad6-ba5f-a7d326a2b42b",
"discountId": "d5222096-c086-4d96-8675-87f8f4b17962",
"type": "AmountOffBasket",
"qualifiedCouponCode": null,
"amountOffType": "AmountOff",
"value": 200,
"amountOff": 200,
"displayMessages": []
},
{
"id": "f68580ac-ada6-4c5f-a1a9-6b1acd78c56b",
"discountId": "d5222096-c086-4d96-8675-87f8f4b17962",
"type": "RedeemLoyaltyPoints",
"loyaltySchemeId": "ebc6bec7-0b36-4860-bf1c-112e6bb2ea65",
"qualifiedCouponCode": null,
"pointsRedeemed": 20000,
"displayMessages": []
}
],
"basket": {
"total": 0,
"totalAmountOff": 200,
"items": [
{
"total": 0,
"totalAmountOff": 200,
"actions": [
{
"id": "e3ee1003-19b1-4ad6-ba5f-a7d326a2b42b",
"subItemId": 1,
"amountOff": 200
}
]
}
]
},
"aggregates": {
"total": 0,
"totalAmountOff": 200
},
"costs": [],
"commitId": null,
"evaluationLog": null
}
The total has been reduced to zero, but they have accrued 2 points.
We will re-sequence the discounts so accruing points is done last.
Generally you want discounts with AccrueLoyaltyPoints
and PayWithLoyaltyPoints
actions to be after discounts that take money off the order.
Go to the Discount section of the tooling and click the "Priorities" link in the sub nav. Re-order the discounts:
Click the "Save" button. Now when we call the evaluation endpoint no points are accrued.
{
"actions": [
{
"id": "30a2bdc6-20d3-4b76-95ae-a16b9a6fb540",
"discountId": "d5222096-c086-4d96-8675-87f8f4b17962",
"type": "AmountOffBasket",
"qualifiedCouponCode": null,
"amountOffType": "AmountOff",
"value": 200,
"amountOff": 200,
"displayMessages": []
},
{
"id": "40a33fee-641f-4d37-82b8-828334b87da3",
"discountId": "d5222096-c086-4d96-8675-87f8f4b17962",
"type": "RedeemLoyaltyPoints",
"loyaltySchemeId": "ebc6bec7-0b36-4860-bf1c-112e6bb2ea65",
"qualifiedCouponCode": null,
"pointsRedeemed": 20000,
"displayMessages": []
}
],
"basket": {
"total": 0,
"totalAmountOff": 200,
"items": [
{
"total": 0,
"totalAmountOff": 200,
"actions": [
{
"id": "30a2bdc6-20d3-4b76-95ae-a16b9a6fb540",
"subItemId": 1,
"amountOff": 200
}
]
}
]
},
"aggregates": {
"total": 0,
"totalAmountOff": 200
},
"costs": [],
"commitId": null,
"evaluationLog": null
}