Cart & catalog promotions

Cart and Catalog promotions (Promo Engine), enable brands to run modern-day promotions with a primary focus on items on cart and catalog. Unlike PoS promotions, these are event-driven, AI-powered, rule & activity-based, and product or activities-based incentives. These allow an array of benefits delivering instant gratification during product search or checkout.

PoS promotions are built for sales and not for relationships

Benefits

BrandCustomer
Personalize PromotionsTargeted promotions
Discount optimization
Flexible program setup
Diverse benefits
Personalized experience
Instant gratification
Relevant offers & more visibility
Convenient setup & ease of usageManage all from one place
Create & optimize on the go
Advanced budgeting control
No OTP or coupon code
Faster checkout
Visibility & ControlReal-time monitoring
Measure and optimize spends
Multivariate testing
Activate/deactivate
Earn or exchange points for rewards

Cart and Catalog Promotions bring together Capillary’s market-leading capabilities to provide

  • Personalized and right in time catalog discounts for customers
  • Equipped with AI-powered personalization & propensity models.
  • product and activity-based offers
  • Seamless checkout experience without the need to search for coupons or promo codes. Auto-applies during checkout.
  • Multiple discount choices at various stages to help choose the best deal with no mental effort.
  • Relevant & customized discounts nudge customers toward a purchase during the journey optimized discounting.
  • Convenient for orgs to upsell & cross-sell.
  • Helps to configure strategies based on customer, product, store, location, and customer activities.

Sample use cases

  1. Fuel distributors can use the Promotion Engine to incentivize partners and individuals on purchases beyond fuel products. It offers fleet owners rewards. For example, when drivers make purchases they get promotions like free refreshments such as tea, coffee, biscuits, and other similar items on their regular fueling.

The following are examples of some live promotions.

  • Segment-based: Four-wheeler owners can get free filter coffee ($4/-) or mini cappuccino ($5/-) when customers fuel for $100. Avail once in 7 days and max 5 times.
  • Quantity or Unit level: Avail a discount of $1/gallon when you purchase fuel over 2 gallons. Offer capped to 10 gallons/day and a maximum of 100 gallons in a month.
  • Wallet points can mean much more: Redeem 2000 points and get Main Grade fuel worth $50. Offer valid till July 31, 2021, on select stations on specific fuel categories.
  1. Fashion retail brands can go beyond popular small ticket items and think more about driving experience to build loyalty:
  • Know customers better and engage more: Customers increasingly recognize the value of their data. Offer rewards and better experience as motivation to share their data. For example, unlock 10% off Denim products up to $20 on date of birth update or email address update.
  • Milestone-based: Get 10% off on the next five transactions with a minimum cart amount of $100 for customers who complete $1000 in an annual purchase.
  • Experiential hooks: Gift matching accessories or products to create that experiential hook and gratification. Shop for clothing products worth $200 and get a free Duffle Bag or anti-theft bag.
  1. Grocery or supermarket chains can incentivize frequent shoppers with seasonal promotions and upsell long-tail products or bundle them with their regular purchases.
  • Day & Time-based: Get an additional 5% off on your grocery purchases over $100 when you shop on Wednesdays between 11 AM - 1 AM. Avail a maximum discount of $50 in a single transaction and $200 annually.
  • Restrictions:- Buy 3 milk packets and get 50% off on custard flavors. Can be availed twice in a single transaction, 5 times in a month, and max 10 times per customer on selected stores
  • Catalog/SKU: With every purchase of frozen products get 20% off on bacon. Offer applicable on category purchases above $100.
    To start with creating a promotion see Create Promotions (Cart/Catalog Promotions).

📘

  • Applicable to all promotion types.

You can add any relevant information to a promotion using the promotion custom fields. It could be to store any promotion-related information such as T&C, Image URL, and offer URL.

See how to create custom fields in Cart Promotion Settings.

There are five different types of cart/catalog promotions. The configuration flow and options might vary for each promotion type.

Loyalty Promotion

These are general promotions to target customers for selected audiences with our AI-powered campaigns tools. For example, get 20% off on Arrow shirts for customers who transacted in the last 90 days.

Use case: Target customers who consume extra dark chocolates based on their preference and purchase history.
Example: Get flat 60% off on extra dark chocolates between June 27, 2021, and July 10, 2021, at Store North Expressway 1 and 3.
To know how to configure, see Loyalty Promotion under Create Promotion.

Loyalty earning promotion

The promotion is unlocked when customers complete a milestone or perform a loyalty activity (customer registration, profile update, and transaction).

Use Case: Make customers realize the value of the data and offer incentives through promotions when they provide more details.
Example: Get a flat 15% off on your purchase when you sign-up for email updates. The offer applies to the first 250 customers and each customer can avail the offer only once.

The offer is valid for stores only in the North Zone between July 5, 2021, to July 31, 2021.

To know how to configure, see Loyalty earning promotion under Create Promotion.

POS promotion

This is not specific to any audience group and anyone who makes transactions at POS can avail it. There is no need to broadcast these promotions to customers.

Use Case: Promotion targeted at clearance of category Wafers. Such promotions are not broadcasted but configured at POS level. These are traditional promotions that run at POS and are not specific to loyalty or non-loyalty members.
Example: All Wafers at $2.9, save $1.5, In-store every Saturday and Sunday between 10 AM- 6 PM in select stores: Store East 1, Store East 2, Store East 3, Store East 4, Store East 5. Offer Valid from Jun 27, 2021, - Jul 10, 2021. Also, the offer is valid on 1st Wafer of each transaction.
To know how to configure, see POS promotion under Create Promotion.

Rewards promotion

These are promotions that customers can earn while making a purchase using reward points.

Use Case: Customers can choose to exchange their reward points for cash, buy any promotion or product.
Example: Redeem 2000 points and get a main grade fuel promotion worth $50. Offer valid till 31 July on select stations on specific fuel categories.
To know how to configure, see Rewards promotion under Create Promotion.

Code linked promotion

Code linked promotions are the physical coupon codes which all customers can redeem irrespective of their loyalty status. These can also be used as Influencer Codes. You can issue promo codes to either your loyalty or anonymous customers via partner or physical coupons. This helps in improving engagement and acquisition.

Promo codes can be used by anyone who has the code during the time of checkout to avail the benefits based on code validations. You can link any type of promotion to the code like combo promotions, fixed amount, percentage based discounts, free product, or bundled pricing.

Code linked promotions are generally distributed directly in the stores or through email campaigns. Both can be availed by customers either at in-store or e-commerce websites through their coalition partners depending on their validity.

A code can be only used once and is unique for each customer.

Promo codes become invalid when the promotion expires.
Promo codes are applicable to both loyalty and non-loyalty customers.
Promo codes can be redeemed multiple times as per the configuration set.
Use Case 1: Number of transactions across which the code can be redeemed.
Example: For a promotion X is created, you can restrict the redemption for up to 10 transactions.

Use case 2: Limit the maximum discount across redemptions.
Example: There is a promotion with code to provide 10% off on every transaction a customer makes, limit max discount across redemptions to 1000.
Customer can continue redeeming the code n number time till the discount disbursed does not cross 1000.

Use Case 3: Handle trending Influencer Marketing successfully through these promotion restrictions. Brands can promote themselves on various social media platforms through influencers, who can further gift these promo codes to customers. Brands can enable a limit on the number of times a promo code can be used, limit number of transactions a promo code can allow etc.
Example: Mansi is an Instagram influencer. Brand provides her with a code called HOLIMAN100. She can share the promo code with her followers. The brand can limit the redemptions count to 1000.
So the first 1000 users to use this code will get the benefit.
To know how to configure, see Code linked promotion under Create Promotion.

Earned Promotions

The filter will target the audience who earned promotions during a specific period.

743

Example: Filter users who have earned promotions more than 3 times in July month.
Consider Zoha has earned 2 promotions on July 7, and 3 promotions on July 10, and Raj has earned 1 promotion on July 10.
Who will make it to the filter list? - Zoha; As we want a user who has earned more than 3 promotions in the selected time range.

Create promotions

To create each type of promotion, see the following section. The flow changes at Step 8 according to the type of promotion.
Create promotion (all types)
This section provides detailed instructions on how to configure each type of promotion. According to the type of promotion that you want to create, navigate to the respective section after Step 7.

You can have an overall of 250 active promotions for an org (all types of promotions). However, it can be increased based on the requirement.
To create a cart or catalog promotion, follow these steps:

  1. Open the campaign to add a promotion, navigate to the Promotions tab.
1188
  1. Click Create promotion.
793
  1. In Promotion name, enter a name for the promotion.

Re-use the Expired or Disabled Promotion names

Previously, promotion engine only permitted the use of unique promotion names, which means that a previously used promotion name cannot be reused, even if the promotion has expired or been disabled.

For example, brands might want to run a promotion for 5 days every month. For this, they would want to keep the same promotion name every time they run this promotion.

Another case could be launching independence day promotion every year, for this also, they would want to keep the same promotion name.

Hence to support the brands, a new update is introduced:

  • Users can use the expired or disabled promotion names in cart promotions
  • Users can update an existing promotion to use the same name

This update eliminates the need to create new names for promotions with similar offers, saving valuable time and effort for marketing teams.

Differentiation between promotions can be achieved through unique Promotion IDs and promotion duration.

  1. In Promotion description, enter a brief description of the promotion.
  2. In Promotion duration, set the start date and end date of the promotion using the calendar boxes.
  3. In Promotion type, choose the desired promotion type.
  4. Enable Issue promotion in deactivated state to allow customers to manually activate the promotion to auto-apply for a transaction. For example, you can allow customers to activate 5% off on groceries. Whoever activates the offer will get flat 5% off on grocery items in their next transaction.
    This is applicable only for Loyalty promotion, Loyalty earning promotion, and Rewards promotion.
1563
  1. Click Next to continue.
  2. According to the type of promotion, configure other things and click Create promotion to save.
  • Loyalty promotion
  1. Define qualifying cart conditions and benefits.
  2. Add metadata in the promotion if required.
  • Loyalty earning promotion
  1. Configure promotion earning condition (activity or milestone-based).
  2. Define qualifying cart conditions and benefits.
  3. Add metadata in the promotion if required.
  4. Configure promotion earning notifications and expiry reminders.
  • POS promotion
  1. Define qualifying cart conditions and benefits.
  2. Add metadata in the promotion if required.
  • Rewards promotion
  1. Configure promotion earning condition (Direct trigger)
  2. Define qualifying cart conditions and benefits.
  3. Add metadata in the promotion if required.
  4. Configure promotion earning notifications and expiry reminders.
  5. After creating new reward promotion, you need to link the program to the org's Marvel rewards catalog. For details, see Linking Reward Promotion to Marvel Reward.
  • Code linked promotion
  1. Define qualifying cart conditions and benefits.
  2. Add metadata in the promotion if required. You will see option to configure promo codes once you click on Save.
779
  1. Generate promo codes for code linked promotions.

📘

  • Applicable only for Loyalty earning promotion

This is the first step of the Loyalty Earning Promotion where you can configure conditions to unlock the promotion. You can define the condition to unlock the promotion either activity-based or milestone-based.

For activity-based promotion unlocking

  1. In Configure earning, select Single activity.
814
  1. Select earning activity: Select the activity for which you want to unlock the promotion and click Continue.
OptionDescription
Makes a transactionSelect this to define the earning condition on new transaction activity.
RegistersSelect this to define the promotion earning condition on the new customer registration activity.
Updates profileSelect this to define the promotion earning condition on the customer's profile update activity.
337
  1. Define earning scope: You can define promotion unlocking only when the selected activity is performed at a specific store(s), zone(s), or concept(s). For example, unlock promotion only when a customer makes a transaction at the store ABC.
  • Click Customize to add scope.
  • Select desired options according to the selected scope (stores, zones, or concepts).
  • Click Done to save
781
  • Click Continue to proceed.
  1. Define earning conditions: You can configure the unlocking condition using rule expressions. For example, unlock the promotion for the transaction activity with a transaction value of more than $100.
  • In Criteria name, enter the name of the criteria.
  • In the expression box, define the condition that you need to evaluate.
  • Click Continue to proceed.

If no condition is required to avail of the promotion, just enter true.

453
  1. Additional Settings: Set the earning cap and validity of points earned through the promotion and click Continue to proceed.
1013
  • Maximum earning per customer: Enable this option to limit a customer from earning this promotion and enter your preferred times in the box that appears. For example, a customer can earn the promotion only twice.
  • Restrict earning days: Enable this option to limit the period during which a customer can earn the promotion. Enter the number of days in From the date of issual.
    This can help customers to make purchases before the offer lapses. Limited period offers are more effective than long-running offers.
660
  • Set expiry of the earned promotion: After a customer unlocks or earns the promotion, you can define the validity of the promotion.
    a. Along with the promotion: Select this option to expire the promotion on the promotion end date.
    b. From the date of earning: Select this option to keep the promotion active for a specific number of days from the earning date. For example, you can set to expire promotion in 7 days from the date of earning the promotion.

For milestone-based earning

You can select an audience group and set a target for them to achieve to unlock promotions.

To configure, do the following.

  • In Configure earning, select Activity milestone.
  1. Select milestone group: Select an audience group that you want to target and click Continue to proceed.

To add a new audience or target group, log on to Intouch and navigate to the Profile icon > Organization Settings > Master Data Management > Data Model >
SALES TARGETS

878
  1. Select milestone: Select the target that the selected audience group must achieve to unlock the promotion and click Continue to proceed.
885
  1. In Additional Settings, set the earning cap and validity of the points earned through the promotion.
  • In XYZ, set the earning cap.
  • Click Continue.

Define promotion availing condition and promotion benefit

📘

  • Applicable to all promotion types.

You can define the cart evaluation condition for customers to qualify for the promotion and the actual benefit the customers could get with the promotion.

  1. In the new promotion configuration, navigate to the Availing conditions and benefits section.
  2. Click Add Conditions/benefits to first define the qualifying cart condition.
  • The condition can be based on the entire cart items, cart amount, or items of specific product brands, categories, or attributes.
600

To add conditions/benefits, do the following.

  1. In Define qualifying conditions, set the cart evaluation condition
488
  1. In Select cart property, select any of the following options to base the earning condition on.
600
OptionDescription
Cart amountTo define the qualifying condition on the entire cart amount.
For example, avail the promotion only for customers whose cart value is >= $100.
Count of items in the cartTo define the qualifying condition on the count of items added to the cart.
For example, avail the promotion only for customers whose cart count > 5.
Sum of line item amount for the selected productTo define the qualifying condition on the price of line items of specific products, categories, brands, or attributes in the cart.
Use Select product to add your preferred products, attributes, or categories.
For example, avail promotion only if the sum of the price of cart items of only shirts (product category) exceeds $200.
Sum of line item quantity for the selected productTo define the qualifying condition on the count of line items of specific products, categories, or attributes in the cart.
Use Select product to add your preferred products, attributes, brands, or categories.
For example, avail promotion only if the count of specific cart items (shirts - product category) exceeds 3.
Cart includes one or more selected productsTo avail promotion only if the cart contains products, categories, or attributes.
Use Select product to add your preferred products, attributes, brands, or categories.
For example, avail promotion only if the cart contains the product with SKU123.

Supported operators: equal to(=), greater than(>), or greater than equal to(>=)

  1. In Select benefit, click Define benefits to set the benefit the customer gets after fulfilling the configured condition.
968
  1. In the Discount applied on, select your preferred option.
  • Select Complete cart to apply the promotion discount on the entire cart.
  • Select Select products in cart to make the promotion discount applicable to specific products in the cart. You can either upload SKUs manually using List of SKU codes, or Include or Exclude products of a specific brand(s), category(es), or attribute(s).
299
  1. In the Benefit type, select your preferred discount type.
  • Fixed amount: To provide a flat amount discount. For example, get $10 off on the purchase of an electronic gadget.
  • Percentage based: To provide a percentage discount on the transaction amount. For example, get 20% off on t-shirts (product category).
  • Free product: To run buy one get one offer. You also need to specify the Applicable quantity. This is applicable only for Discounts applied on Select products in Cart.
  • Fixed target amount: To provide a fixed price for items (bundle). For example, get 3 cokes for 50, or get a (chips packet + Coke) for 40. This is applicable only for Discount applied on Select products in Cart.
  1. Click Done.
  2. Click Continue.

Limit scope of the promotion by store entity and day

To drive sales at particular stores/days, you can use the scope filter.

  1. Add Scope
  2. Add restrictions
548

Add store/date level scope

To add scope and restrictions, do the following.

  1. In Define Scope, click Add scope/restrictions.
  • Store entity scope: To limit the promotion to specific stores, in Limit to specific store entities, click Customize and select whether to limit by store, concept, or zone.
312
  • Day scope: To limit the promotion to specific dates or days, in Limit to a specific day/time scope, click Customize.
    a. In Days/month scope, select your preferred scope
OptionDescription
DaysSelect to limit the promotion for selected days of a month.
You will see the month dates (1-31).

1. In the Dates of the month select the dates on when customers can avail of promotion.
2. You will see the Start time and Duration in hours options. Select the time period for which customers can avail of the promotion.
For example, on the 1st of every month, at 4:00 PM for two hours.
WeeksSelect to limit the promotion for selected weeks (Monday - Sunday).

1. In Days of the week select all weekdays or a specific weekday on which customers can avail promotions.
You will see the Start time and Duration in hours options. Select the time period for which customers can avail the promotion.
For example, on Thursday, Saturday, and Sunday for three hours.
Does not repeatThe promotion is valid only once.

b. On Days of the week, select the days on which the promotion is valid.

📘

  • This field is visible only when Week is selected in the Days/month scope.
301

c. In Start time, set the time on which the promotion starts.

314

d. In Duration in hours, enter the validity duration of the promotion.
e. Click Done.
f. Click Continue.

Add cart level restrictions

In Add restrictions, configure the following options.

OptionDescription
Number of times the promotion could be redeemed in a single cartEnter the number of times a promotion can be redeemed in a single cart.
Enable limit on the discount due to the promotion in a single cartEnable this option to limit the discount amount in a single cart and enter the respective value in the field provided.
Enable limit on the number of times a customer could avail the promotionEnable this option to limit the number of times a customer can avail the promotion and enter the respective value in the field provided.
Enable limit on the number of transactions a customer could avail the promotionEnable this option to limit the number of transactions a promotion is applicable for and enter the respective value in the field provided.
Enable limit on total discount a customer could avail across redemptionsEnable this option to limit the total discount amount a customer can avail of throughout the promotion this enters the respective value in the field provided.
Enable limit on the number of times customers could avail the promotionEnable this option to limit the number of times a customer can avail the promotion and enter the respective value in the field provided.
Enable limit on the number of transactions in which customers could avail the promotionEnable this option to limit the number of transactions on which the promotion is applicable. For example, by a customer to avail the promotion and enter the respective value in the field provided.
Enable limit on total discount customers could avail across redemptionsEnable this option to limit the total discount a customer can receive through promotion and enter the respective value in the field provided.
Refresh the limit after a specified periodTo choose when the limit is reset.

1. Never: The limit does not get reset.
2. Days: Select the number of days after which the limit is reset.
3. Weeks: Select the number of days after which the limit is reset.
NOTE: This option appears after you enable various limitations.

Add meta-information

  1. Navigate to Additional Information.
  2. Enter the values for required fields. Ensure that you enter all the mandatory fields to proceed.
532
  1. Enter the field values and click Continue.

Preventing Fraudulent redemptions in cart promotions

Background

In cart promotions, when an offer is applied by the cashier on a cart and processed for payment, the customer has received the benefit but the promotion has not yet been redeemed into the system.
At the same time if another cashier applies the same promotion to another cart, the capillary system proceeds ahead as it cannot reject any redemption. This led to customers getting benefits beyond the allowed number of redemptions.

In a typical cart promotion related transaction, below is the sequence of events :

  1. Customer makes the purchase and goes for checkout
  2. The cashier adds the items to the cart and checks for applicable offers
  3. Cart promotions returns the applicable offers (At this point promotions are not redeemed but merely evaluated for the cart and is indicative of the benefits)
  4. Cashier applies the offers and proceeds for payment (Customer has received the benefit hence Capillary cannot reject any redemption)
  5. Capillary receives the transaction (via transactionAdd API)
  6. The transactionAdd API internally calls the cart promotions module to redeem the promotions and update the redemption KPIs . Here two scenarios could arise,
    • Redemption identifier is valid and irrespective of the breach in KPI we record the redemption.
    • Redemption identifier is invalid. Currently these are rejected by the cart promotions module

With step 4 & 6 being asynchronous, it leads to a potential loophole where the promotion benefit has been given to the customer but the corresponding redemption has not happened in the cart promotions

Enhancement done:

  1. Brands can prevent customer/cashier from exploiting the gap in system design and prevent them from getting benefits beyond the allowed number of redemptions
    1. A feature flag to enable and disable locking across cart promotions and gift vouchers is added
    2. For every cart identifier, we compute the promotion redemption KPIs at both customer and promotion level. These computations are transient or temporary in nature and block the usage of the promotion(s) for new cart identifiers. In the evaluate payload, a unique cart identifier to be sent by cart promotions
    3. POS will echo the same identifier for the ongoing transaction if a second evaluate/getOffers call is made to cart promotions
    4. For the same cart identifier, if a new request is received for the same customer the transient values will be reversed and cart to be evaluated as new
    5. Once the transaction is received, the transient values are marked as permanent.
    6. In case the transaction is canceled or timeout, the transient state can be released by below methods
      1. External - API call with the same cart identifier.
      2. Time based trigger -Brand can set up a default time to release the lock in case the external trigger is not received
  2. As a brand,you can/want to see the active cart evaluation & disable the locking of the applied promotions/earn instances once they are in the transient state so that it does it not lead to conflicts later
    1. Once the Cashier starts the txn ,POS sends the getOffers call
    2. Systems locks the offers & updates the KPIs
    3. If customer tries to toggle on/off, system disables the activate/deactivate action in below manner
      1. For mode=discount the failure to happen at promotionId level
      2. For mode=payment vouchers the failure to happen at earnid level
    4. Either the customer is on offers screen OR customer opens the app and goes to offers screen
    5. Mobile app makes a getCustomerPromotions call AND
    6. Cart promotions sends the customer promotions along with temp redemptions and cart details
    7. Customer sees the cart in progress and disabled offers
    8. addTxn is delayed
    9. Customers will see the offers in a locked state. Now the only recourse is to either wait OR Contact customer support OR Offers auto unlock after 24 hrs
Image 1: Evaluation log of the cart, option to release the cart

Image 1: Evaluation log of the cart, option to release the cart

Image 2: Cart discarded/released

Image 2: Cart discarded/released

Example

Offer configuration

Offer : Purchase items worth 1000 and get a buy 1 get 1 on coke

Below are the redemption, discount and transaction restrictions at earn level

maxusage
earn restrictionsredemption50
discount3000
transaction10

Below are the cart/event level restriction

cart/event level10

Assuming customer has made 1 transaction worth 1000 and earned the offer

So customer has,

E1max
redemption5
discount300
transaction1

Now customer goes for the transaction where he/she wants to redeem the coke offer

Step 1
Cart >> Customer purchased a coke worth Rs.100

qtyrateamount
cartcoke1100100

Step 2
Cashier scans the items and makes the /evaluate call to get the cart promotions applicable on the cart

Internally since customer has two earns, below temp redemptions will be recorded

Earn 1 >> temporary redemptions take place and offer is locked

maxusagetemp redemption
earn restrictionsredemption501
discount3000100
transaction101
cart/event level101

Step 3 -> Preventing accidental & fraud transaction

Now if another transaction comes for the customer, this offer will not be applied since the max transaction level limit is hit. This is how temp redemptions prevent any excessive redemption even if the transaction has not reached the Capillary system.

Step 4

Once the transaction is added, i.e. transactionAdd call is sent to Capillary & processed

Restrictions view

maxusagetemp redemption
earn restrictionsredemption510
discount3001000
transaction210
cart/event level100
maxusagetemp
earn restrictionsredemption500
discount30000
transaction200
cart/event level100

For more examples, refer to this

Click here for more technical details

Claim cart promotions and gift vouchers

Now brands can issue cart promotions and gift vouchers directly from different orchestrators, enabling them to offer personalized incentives to their customers during their different journeys.

You can define the owner of the promotion via 3 flows:

  1. Create promotion
  2. Update promotion
  3. Claim promotion

Creating a POS promotion via API with owner as Journey and OUTBOUND when allowMultipleOwners=true :

Request URL:

{{host}}/v1/promotion-management/promotions

Request body:

{
"name": "cart promotions in journeys testing",
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "POS",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": 1,
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": 10,
"includeItemsFromConditionSet": false
}
},
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": 1
}
]
},
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"ownershipCriteria": {
"owners": {
"JOURNEY": [
{
"id": [
"49","50"
]}],
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
}] },
"allowMultipleOwners": true
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"createdBy": 100,
"createdOn": 0,
"lastUpdatedBy": 100,
"startDate": 1681369313,
"endDate": 1681887696000,
"campaignId": 111946
}

Response body:

{
"data": {
"id": "64b663d2314bf82c5229d6dd",
"name": "cart promotions in journeys testing",
"orgId": 100458,
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "POS",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": "1.000000",
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": "10.000000",
"includeItemsFromConditionSet": false
}
},
"createdBy": 75081547,
"createdOn": 1689674706750,
"lastUpdatedBy": 75081547,
"lastUpdatedOn": 1689674706750,
"startDate": 1681369313,
"endDate": 1681887696000,
"campaignId": 111946,
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": "1.000000"
}
]
},
"earnLimitedToSpecificAudience": false,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"ownershipCriteria": {
"owners": {
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
}
],
"JOURNEY": [
{
"id": [
"49",
"50"
]
}
]
},
"allowMultipleOwners": true
}
}
}

Creating a POS promotion via API with owner as Journey and OUTBOUND with allowMultipleOwners= false

Request URL:

{{host}}/v1/promotion-management/promotions

Request body:

{
"name": "cart promotions in journeys testing",
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "POS",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": 1,
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": 10,
"includeItemsFromConditionSet": false
}
},
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": 1
}
]
},
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"ownershipCriteria": {
"owners": {
"JOURNEY": [
{
"id": [
"49","50"
]}],
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
}] },
"allowMultipleOwners": false
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"createdBy": 100,
"createdOn": 0,
"lastUpdatedBy": 100,
"startDate": 1681369313,
"endDate": 1681887696000,
"campaignId": 111946
}

Response body:

{
"errors": [
{
"code": 740,
"message": "multiple owners not allowed in promotion"
}
]
}

Creating a Customer(Loyalty) promotion via API with owner as Journey and OUTBOUND when allowMultipleOwners=true :

Request URL:

{{host}}/v1/promotion-management/promotions

Request body:

{
"name": "cart promotions in journeys testing(cx promo)",
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "CUSTOMER",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": 1,
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": 10,
"includeItemsFromConditionSet": false
}
},
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": 1
}
]
},
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"ownershipCriteria": {
"owners": {
"JOURNEY": [
{
"id": [
"49"
]}],
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
}] },
"allowMultipleOwners": true
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"createdBy": 100,
"createdOn": 0,
"lastUpdatedBy": 100,
"startDate": 1689590116,
"endDate": 1689762916,
"campaignId": 111946
}

Response body:

{
"data": {
"id": "64b66b0a62390747424c27b2",
"name": "cart promotions in journeys testing(cx promo)",
"orgId": 100458,
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "CUSTOMER",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": "1.000000",
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": "10.000000",
"includeItemsFromConditionSet": false
}
},
"createdBy": 75081547,
"createdOn": 1689676554406,
"lastUpdatedBy": 75081547,
"lastUpdatedOn": 1689676554406,
"startDate": 1689590116,
"endDate": 1689762916,
"campaignId": 111946,
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": "1.000000"
}
]
},
"earnLimitedToSpecificAudience": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"ownershipCriteria": {
"owners": {
"JOURNEY": [
{
"id": [
"49"
]
}
],
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
}
]
},
"allowMultipleOwners": true
}
}
}

Updating a promotion with owner type when allowMultipleOwners=true :

Request URL:

{{host}}/v1/promotion-management/promotions/64b663d2314bf82c5229d6dd

Request body:

{
"name": "cart promotions in journeys testing(pos promotion)",
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "POS",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": 1,
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": 10,
"includeItemsFromConditionSet": false
}
},
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": 1
}
]
},
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"createdBy": 100,
"createdOn": 0,
"lastUpdatedBy": 100,
"startDate": 1681369313,
"endDate": 1681887696000,
"campaignId": 970687,
"ownershipCriteria": {
"owners": {
"REWARDS": [
{
"campaignId": 123,
"id": [
"1"
]}],
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
}] },
"allowMultipleOwners": true
}
}

Response body:

{
"data": {
"id": "64b663d2314bf82c5229d6dd",
"name": "cart promotions in journeys testing(pos promotion)",
"orgId": 100458,
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "POS",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": "1.000000",
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": "10.000000",
"includeItemsFromConditionSet": false
}
},
"createdBy": 75081547,
"createdOn": 1689674706750,
"lastUpdatedBy": 75081547,
"lastUpdatedOn": 1689677340494,
"startDate": 1681369313,
"endDate": 1681887696000,
"campaignId": 970687,
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": "1.000000"
}
]
},
"earnLimitedToSpecificAudience": false,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"expiryDateChangeJobList": [],
"ownershipCriteria": {
"owners": {
"REWARDS": [
{
"campaignId": 123,
"id": [
"1"
]
}
],
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
}
]
},
"allowMultipleOwners": true
}
}
}

Updating a promotion with owner type when allowMultipleOwners=false :

Request URL:

{{host}}/v1/promotion-management/promotions/64b94d605874fa0b43076e70

Request body:

{
"name": "cart promotions in journeys testing",
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "POS",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": 1,
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": 10,
"includeItemsFromConditionSet": false
}
},
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": 1
}
]
},
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"ownershipCriteria": {
"owners": {
"JOURNEY": [
{
"id": [
"50"
]}]
},
"allowMultipleOwners": false
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"createdBy": 100,
"createdOn": 0,
"lastUpdatedBy": 100,
"startDate": 1681369313,
"endDate": 1681887696000,
"campaignId": 111946
}

Response body:

{
"errors": [
{
"code": 741,
"message": "New owners not allowed in promotion"
}
]
}

Claim promotion with owner type as OUTBOUND

Request URL:

{{host}}/v1/promotion-management/promotions/64b663d2314bf82c5229d6dd/claim

Request body:

{
"type": "OUTBOUND",
"campaignId": 123,
"id": [
"1"
]
}

Response body:

{
"data": {
"id": "64b663d2314bf82c5229d6dd",
"name": "cart promotions in journeys testing(pos promotion)",
"orgId": 100458,
"priority": 0,
"active": true,
"messageLabel": "test!",
"type": "POS",
"condition": {
"type": "PRODUCT",
"productCondition": {
"criteriaList": [
{
"entity": "SKU",
"operator": "IN",
"values": [
"SKU21",
"SKU22",
"SKU23",
"SKU24",
"SKU25"
]
}
],
"kpi": "QUANTITY",
"value": "1.000000",
"operator": "EQUALS"
}
},
"action": {
"type": "PRODUCT_BASED",
"productBasedAction": {
"type": "PERCENTAGE",
"value": "10.000000",
"includeItemsFromConditionSet": false
}
},
"createdBy": 75081547,
"createdOn": 1689674706750,
"lastUpdatedBy": 75081547,
"lastUpdatedOn": 1689677534181,
"startDate": 1681369313,
"endDate": 1681887696000,
"campaignId": 111946,
"promotionRestrictions": {
"Cart": [
{
"kpi": "REDEMPTION",
"limit": "1.000000"
}
]
},
"earnLimitedToSpecificAudience": false,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
},
"mode": "DISCOUNT",
"maxIssuancePerCustomer": 1,
"isStackable": false,
"ownershipCriteria": {
"owners": {
"REWARDS": [
{
"campaignId": 123,
"id": [
"1"
]
}
],
"OUTBOUND": [
{
"campaignId": 123,
"id": [
"1"
]
},
{
"campaignId": 123,
"id": [
"1"
]
},
{
"campaignId": 123,
"id": [
"1"
]
}
]
},
"allowMultipleOwners": true
}
}
}

Get unclaimed promotions only

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=DESC&sortOn=NAME&unclaimedOnly=true&campaignId=111946

Response body:

{  
"data": [  
{  
"promotionId": "64b670ff314bf82c5229d93f",  
"promotionName": "test1",  
"promotionType": "CUSTOMER",  
"startDate": 1689618600000,  
"endDate": 1689877799999,  
"isActive": true,  
"customFieldValues": {  
"image_url": "1",  
"partner 1 liability value": "1"  
}  
}  
]  
}

Get all promotions

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=DESC&sortOn=NAME&campaignId=111946

Response body:

{
"data": [
{
"promotionId": "64b670ff314bf82c5229d93f",
"promotionName": "test1",
"promotionType": "CUSTOMER",
"startDate": 1689618600000,
"endDate": 1689877799999,
"isActive": true,
"customFieldValues": {
"image_url": "1",
"partner 1 liability value": "1"
}
},
{
"promotionId": "64b663d2314bf82c5229d6dd",
"promotionName": "cart promotions in journeys testing(pos promotion)",
"promotionType": "POS",
"startDate": 1681369313,
"endDate": 1681887696000,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b66b0a62390747424c27b2",
"promotionName": "cart promotions in journeys testing(cx promo)",
"promotionType": "CUSTOMER",
"startDate": 1689590116,
"endDate": 1689762916,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
}
]
}

Get promotions by filtering on ownerId and ownertype and promotion type

When only owner type is passed:

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=ASC&sortOn=NAME&limit=50&ownerType=JOURNEY

Response body:

{
"data": [
{
"promotionId": "64b66b0a62390747424c27b2",
"promotionName": "cart promotions in journeys testing(cx promo)",
"promotionType": "CUSTOMER",
"startDate": 1689590116,
"endDate": 1689762916,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b663d2314bf82c5229d6dd",
"promotionName": "cart promotions in journeys testing(pos promotion)",
"promotionType": "POS",
"startDate": 1681369313,
"endDate": 1681887696000,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b66342314bf82c5229d6ca",
"promotionName": "demo-pos-17Jul-12PM",
"promotionType": "POS",
"startDate": 1681369313,
"endDate": 1681887696000,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b6796a314bf82c5229da66",
"promotionName": "test_random",
"promotionType": "POS",
"startDate": 1689593013,
"endDate": 1689852213,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b67b5b62390747424c2b1b",
"promotionName": "test_random2",
"promotionType": "POS",
"startDate": 1689593013,
"endDate": 1689852213,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b67b6a314bf82c5229da76",
"promotionName": "test_random3",
"promotionType": "POS",
"startDate": 1689593013,
"endDate": 1689852213,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
}
]
}

When wrong owner type is passed:

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=ASC&sortOn=NAME&limit=50&ownerType=CAMPAIGN

Response body:

{
"timestamp": 1689864382301,
"errorCode": 400,
"message": "Validation Failed",
"errorDetails": [
"Failed to convert property value of type 'java.lang.String' to required type 'com.capillary.promotionengine.bo.OwnerType' for property 'ownerType'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [com.capillary.promotionengine.bo.OwnerType] for value 'CAMPAIGN'; nested exception is java.lang.IllegalArgumentException: No enum constant com.capillary.promotionengine.bo.OwnerType.CAMPAIGN"
]
}

When owner type and owner Id both are passed:

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=ASC&sortOn=NAME&limit=50&ownerType=JOURNEY&ownerId=101

Response body:

{
"data": [
{
"promotionId": "64b6796a314bf82c5229da66",
"promotionName": "test_random",
"promotionType": "POS",
"startDate": 1689593013,
"endDate": 1689852213,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b67b5b62390747424c2b1b",
"promotionName": "test_random2",
"promotionType": "POS",
"startDate": 1689593013,
"endDate": 1689852213,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
},
{
"promotionId": "64b67b6a314bf82c5229da76",
"promotionName": "test_random3",
"promotionType": "POS",
"startDate": 1689593013,
"endDate": 1689852213,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
}
]
}

When owner type is correct and owner Id is wrong:

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=ASC&sortOn=NAME&limit=50&ownerType=JOURNEY&ownerId=79

Response body:

{
"data": []
}

When only owner id is passed:

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=ASC&sortOn=NAME&limit=50&ownerId=101

Response body:

{
"timestamp": 1689864610000,
"errorCode": 400,
"message": "Validation Failed",
"errorDetails": [
"Owner type is required to search by owner Id"
]
}

When owner type, owner id, and promotion type is passed:

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=ASC&sortOn=NAME&limit=50&ownerType=JOURNEY&ownerId=49&promotionTypes=CUSTOMER

Response body:

{
"data": [
{
"promotionId": "64b66b0a62390747424c27b2",
"promotionName": "cart promotions in journeys testing(cx promo)",
"promotionType": "CUSTOMER",
"startDate": 1689590116,
"endDate": 1689762916,
"isActive": true,
"customFieldValues": {
"f1": "v1",
"f2": "v2"
}
}
]
}

When owner type, owner id is correct and promotion type is wrong:

Request URL:

{{host}}/v1/promotion-management/promotions/filters?active=true&order=ASC&sortOn=NAME&limit=50&ownerType=JOURNEY&ownerId=49&promotionTypes=POS123

Response body:

{
"timestamp": 1689864807145,
"errorCode": 400,
"message": "Validation Failed",
"errorDetails": [
"Failed to convert property value of type 'java.lang.String' to required type 'java.util.List' for property 'promotionTypes'; nested exception is org.springframework.core.convert.ConversionFailedException: Failed to convert from type [java.lang.String] to type [com.capillary.promotionengine.bo.PromotionType] for value 'POS123'; nested exception is java.lang.IllegalArgumentException: No enum constant com.capillary.promotionengine.bo.PromotionType.POS123"
]
}

Please note:

  1. No validations on owners is currently done
  2. Unclaimed, if set to true will return only promotions which have no owners of any type in the promotion meta. This will be added as part of query param
  3. allowMultipleOwners=true
    1. Will allow multiple owners to claim the promotion
    2. You can delete the existing owner as well as add the new owner
    3. Can only be updated from false to true. No other flow is supported.
  4. allowMultipleOwners=false
    1. Only one type of owner will be allowed
    2. Owner can’t be added/replaced/removed