JFM 2023 | Loyalty+ Releases

Step Function - Points Allocation Strategy & Issue Coupon Strategy

Problem Statement:
Currently we support 3 types of points allocation - Fixed and proration on % and points multiplier.
There are requirements from brands who want to define equal intervals of X transaction amount and allocate fixed Y points or coupons for every X amount.

Use Case:

  • As a marketing manager, I would like to allocate fixed points to the customers whose transaction lies in fixed equal intervals.
    Eg: On every spend of 150, allocate 6 points.
  • As a marketing manager, I would like to allocate a fixed number of coupons to the customers whose transaction lies in fixed equal intervals.

Feature Description:

Issue Points through Step Function

  • We have introduced a new “Allocation Type” in the Points Earn condition called “Prorate based on Step function”, where you can allocate fixed points in steps.
  • Quoting the above example, on every spend of 150, customers get 6 points. So, if the transaction amount of a customer falls between 151 - 300, the customer gets 6 points. If the transaction amount is between 301 - 450, customers get 12 points and so on.
  • You need to define 2 things :
    • Step size = The transaction amount interval (above eg - 150)
    • Point per step = The fixed points to be allocated (above eg - 6)
  • Because this strategy works on a source value, hence like other proration strategies, this also works, only in the Transaction Add event.

Issue Coupons through Step Function

  • The step function allocation of coupons has been added at the action level.
  • Under the Loyalty workflows, in the “Issue coupon action” , now exists an “Earn Strategy” which allows users to issue coupons in steps across tiers. Here also, the step size would be the same for all tiers, but the no. of coupons to be issued for each tier per step can differ.

Points Transfer Functionality

Problem Statement:

  • There needs to be certain velocity limits or rules which should apply to Points transfer functionality.
  • Today there are no such restrictions, and anyone can transfer any number of points to another user or user group. This can lead to unwanted fraudulent activities.

Use Case:

  • As a brand manager, I want to apply velocity limits in transferring of points so that I can configure additional layers to prevent misuse of the points by transfer.
  • For examples,
    If a brand manager wants to restrict the points transfer limit to max 200 points per day and max number of transfers to 2 times only for a program.

Feature Description:

  • This feature exists both for Group Points transfer and Individual points transfer, for those brands using Group Loyalty set-ups.
  • So there can be 4 combinations of points transfer in case of group loyalty:
    • Individual → Group
    • Group → Individual
    • Individual → Individual
    • Group → Group
  • Brands can define:
    • Points transfer limit for daily (For a day) , Weekly (Past 7 days), and Monthly( Past 30 days). Eg - Users cannot transfer more than 500 points from one account to another in a day.
    • The frequency of Point transfer for daily (For a day) , Weekly (Past 7 days), and Monthly( Past 30 days). Eg - Users cannot transfer points more than 3 times from one account to another in a day.

Manual Points Adjustments

Problem Statement:

  • Currently we do negative points adjustments only when a customer is returning the bill after redeeming all the points that he/she would have earned on the original bill.
  • But in some use cases, there may not be the link to the original transaction and yet some points need to be reverted. This generally happens in case of third party vendors.
    In such cases, the brands would want to deduct points manually and create a new PA entry with negative points, to adjust the points balance.

Use Case:

  • A transaction was done and the brand imported the points with the bill_id. Now when a customer returns the bill via a credit card of let's say HDFC, HDFC doesn’t know what was the original bill. And hence there is no way to link the original and the return bill. In such cases, HDFC would want to create a new PA entry with all points as returned. This will be similar to negative PA entry but only the return value will be -ve. Thus overall the points will be reduced for the customer.

Feature Description:

  • To support this, there are 2 features introduced:
    • Manual adjustments through API
    • Manual adjust through Import framework
  • A new “Negative Points Adjustment” API to accept a request body and mark a particular entry as a negative return entry.
  • Mandatory fields will be
    • user identifiers like mobile , userId, externalId etc,
    • reason for manual adjustment
    • points to deduct
  • A new import profile “Manual Points Adjustment” profile will allow you to create negative points entries.

API Document :

Input

Query Params:

  • identifierName(possible values: userId, externalId, mobile etc)
  • identifierValue
  • source(INSTORE, WEB_ENGAGE, WECHAT etc)

Request Body

  • reasonOfReturn : Free flowing text. Max character limit -50
  • pointsToBeAdjusted: point values which need to deducted for the user
  • pointsAwardedId
  • programId
  • promotionId
  • promotionIdentifier
  • pointsAwardedRefType, supported values -
    • bill_regular
    • bill_promotions
    • line_item_regular
    • line_item_promotions
    • customer_promotions

Contraints on Input:

  • reasonOfReturn, pointsToBeAdjusted are mandatory params.
  • If promotionIdentifier is passed, programId can not be empty/null.
  • If promotionId and promotionIdentifier both are set, it is an invalid input combination. Either of 1 needs to be passed and not both.
  • points value should be greater than 0.

API signature

Resource Information:

URLv2/customers/lookup/negativePointsAdjustment
AuthenticationYes
HTTP methodPOST
Batch SupportNo

Request URL

{host}/v2/customers/lookup/negativePointsAdjustment?identifierName=id&identifierValue={userid}&source=INSTORE

Sample request body

{

    "pointsToBeAdjusted": "100.00",

    "programId": 2117,

    "reasonOfReturn": "testing"

}

Sample Response

{

    "status": "success",

    "pointsAvailable": "2399.000",

    "message": "points deducted successfully for the user ",

    "warnings": []

}

Ledger Explode APIs

Problem Statement:

So far we provided a based ledger API that gave brands and their customers a summary view of activity level earnings. However details around the actual break up was not available.

Feature Description:

  • With the new ledger explode APIs customers can see the transaction or activity details. To get started use the below API for any activity details,
  • API URL
    /v2/pointsLedger/getLedgerExplodeInfo?event_log_ids=58365864,56203478&customFields=boolean&extendedFields=boolean&maxConversionDate=boolean&billDetails=bool
  • These have been implemented for the following events :
    New Bill
    CustomerRegistration
    TransactionAdd
    GroupTransactionAdd
    GenericEvent
    CustomerPromotionImport
    BillPointsPromotionImport
    LineitemsPointsPromotionImport
    TargetCompleted
    Goodwill allocation
    Points redemption
    Points transfer

API URL
/v2/pointsLedger/getLedgerExplodeInfo?event_log_ids=58365864,56203478&customFields=boolean&extendedFields=boolean&maxConversionDate=boolean&billDetails=bool

Explode API for New bill/ TransactionAdd/ GroupTransactionAdd

1.CDP side change to get bill and line item details Make a controller for get CustomerLedger inffo

  1. GET /v2/pointsLedger/getLedgerExplodeInfo?event_log_ids=58365864, 56203478&customFields=boolean&extendedFields=boolean&maxConversionDate=boolean&billDetails=bool

  2. Pass event id to explode_service

  3. Test Scenarios:

  4. Successful request should returns 200 OK

  5. Should invoke explode service with expected event_log_id array

  6. Given two event_log_id if one of them is invalid or not found then return null for that id and return object for valid id.

  7. Create a new service class in “com/capillary/api/explode/service”

  8. Invokes thrift to get the event details from emf (it’s part of 6th subtask so that subtask has to be completed before this.)

  9. Once we event details, we can get even-type and based on event type we’ll get further details.

  10. If eventType in (NewBill, TransactionAdd, GroupTransactionAdd)

    i. Then get bill and line items details.

  11. call getTransactionsWithLineitemsForUser() to get bill and lineitem details

Test Scenarios:

  1. Should invoke getTransactionsWithLineitemsForUser with customerId
  2. Should return bill and line-items details

Response Object Structure:

{
    "eventLogId": "30405652",
    "eventTypeName": "TransactionAdd",
    "eventDetail": {
        "eventTime": "",
        "maxConversionDate": "2022/12/12: 12:00:00"
    },
    "billDetails": {
        "type": "loyalty",
        "billNumber": "543653",
        "discount": "10",
        "billAmount": "190",
        "note": "this is test",
        "grossAmount": "200",
        "source": "Instore",
        "storeCode": "hil.admin",
        "tillCode": "hil.admin.1"
        "pointsEarned": {
            "regular": [{
                "value": "22",
                "isTransferable": true,
                "expiresOn": "2022/11/11: 11:00:00"
              }
            ],
            "promised": [
              {
                "value": "200",
                "conversionDate": "2022/11/11: 11:00:00"
              }
            ]
            "promo": [
              {
              "promotionName": "",
              "promotionId": "",
              "value": "33",
              "expiresOn": "2022/11/11: 11:00:00"
              "isTransferable": false
              }
            ],
            
        },
        "lineItems": [
            {
              "itemCode": "4756766",
              "source": "Instore",
              "amount": 10.5,
              "rate": 10.5,
              "qty": 1.0,
              "pointsEarned": {
                "maxConversionDate": "2022/12/12: 12:00:00"
                "regular": [
                  {
                    "value": "22",
                    "isTransferable": true,
                    "expiresOn": "2022/11/11: 11:00:00"
                  }
                  ],
                "promised": [
                  {
                    "value": "200",
                    "conversionDate": "2022/11/11: 11:00:00"
                  }
                ]
                "promo": [
                  {
                    "promotionName": "",
                    "promotionId": "",
                    "value": "33",
                    "expiresOn": "2022/11/11: 11:00:00"
                    "isTransferable": false
                  }
            },
            }
        ]
    },
    "customFields": [
        {
            "name": "gender",
            "value": "male"
        },
        {
            "name": "txn_source",
            "value": "neuApp"
        }
    ],
    "extendedFields": [
        {}
    ],
    "paymentModes":["UPI","CASH"]
}

2.CDP side change to get custom fields.

For each “event_id” we can get the corresponding custom_id and its value

get from custom\_fields\_data table where assoc\_id={ bill\_id  }

3.CDP side change to get extended fields

ExtendedFieldsMongoDaoImpl .getExtendedFields gives us the ExtendedFieldInfo which contains all extended fields related to the event . We can return ExtendedFieldInfo .getExtendedFields() to get the list of extended field key value pair

4.Deciding on Request Params that will be supported

getCustomFields
getExtendedFields
getBillDetails(reviewed)
getPaymentMode(new)
getMaxConversionDetails(new)

5.Loyalty side change to get Transaction Earn points for bill and lineitem

add Promise points(new) ,regular,promo points to transaction earn points response.

6.Loyalty side change to get eventName and eventDetails

  1. Add a thrift contract to getEventDetails(eventLogId) in thrift-ifaces-emf.

  2. We need to implement the thrift method in EMF and consume the response in explode api

  3. We get a object entity “src/main/java/com/capillary/shopbook/emf/impl/data/model/EventLog.java”

  4. Thrift structure of eventDetails:

    eventDetails: {
    1:event_subject_id,event_name
    2: eventTime,
    }

Test Scenarios:

  1. Given valid event_log_id should return eventDetails.
  2. Given invalid event_log_id should throw exception not found

Advanced Points Breakup View

Problem Statement:

  • Currently, our Membercare is used by customer support executives or brands’ help level managers, to guide customers with their detailed breakup of the bill.
  • A standard bill/invoice would not contain a detailed breakup of the points issued to the customer on that bill. It would simply display the total points issued on that bill.
  • To know the detailed view, end users tend to call the customer support, and the kind of Advanced view of the points detail we showed on Membercare was very confusing, with all the technical jargons used.

Use case:

  • As a customer support executive or loyalty manager, I would like to have a simple bill-like view of a Transaction on Membercare, to better understand the events taking place in a bill and give a clear summary of the bill to my customers.

Feature Description:

  • With new improvised points break up view you can see and understand the allocation at lineitem & bill level.
  • Old view would focus on program level allocations which does not help 99% of our customers and hence cumbersome to understand.
  • New view focuses on line item level and bill level break up to help users better understand the allocations done.


Referral programs Enhancements

Problem Statements :

  • Currently, the referral codes are system generated and the brands cannot customize them.
  • Brands may want to customize these codes and increase the recall factor for the codes.
  • Currently in the referral program architecture in our system, we have a functionality called reward referrer on 1st txn of referee or many other rules that can be written on referee code.
  • But the challenge is this works, only when the referral code is passed in the transaction API.
  • Even though the referee enrolls using the referral code of the referrer, the referrer will not get the benefit unless the referral code is passed in transaction API.

Use Cases:

  • As a brand marketing manager, I should be able to define the referral code format that my customers use to invite their friends & family so that I can simplify it and improve recall.

  • As a brand, I want to issue rewards to referrer and referee without explicitly passing the referral code in each transaction. System should identify the referrer and execute.

    Feature Description:

  • On Engage+ under the campaign settings, find the Referral Configuration Settings. Here you can customize your referral codes.

  • Now, for referral, the system will not require the referral code to be passed in the Add txn call.

  • Eg : If a rule is written, lets say
    referrerCode.refereeRegCount<=3 OR
    referrerCode.refereeTxnCount <= 5

  • System will fetch the code that was used by the customer on registration to validate the referrer and issue points as per the configured action.
    The same code will have to be passed to trigger campaign related coupon benefits as well.


Points Unlock APIs - Part 1

Problem Statement:

  • Currently we are defining the promised points window in the Loyalty system.
  • This window is hard coded and cant be changed irrespective of any customer action.
  • The only way to unlock these promised points is through external trigger, which works at a bill level. So once the trigger is sent to the Transaction Update event, the promised points on the entire bill will get converted to redeemable points.
  • But what if brands want to convert points only for a particular line item and not the entire bill. This is not possible today.

Use cases:

  • As a System Integrator ,I would like to be able to to configure fixed return windows for different line items , allocate promised points on each line item and convert them to redeemable points according to each line item return window, so that , The users can get regular points on each line item, as and when the return window for the line items gets over and don't have to wait for the default return windows to get over.
  • As a Loyalty Program Manager, I would like to be able to give my customer an option to end the return window for any transaction or any line item in the transaction and immediately convert promised points to regular points.
  • Based on an external trigger, the user must be able to relinquish the return window of delivered products, and the system must be able to convert points corresponding to that line item prematurely into redeemable points so that the user is able to rapidly realize benefits and as a brand, I get to minimize my returns and improve those operations

Feature Description:

  • A new Points Unlock API is released, which lets brands unlock promised points at any time, for any specific line item or entire bill depending on the business requirement.
  • The customers will not have to wait for their return window to get over to unlock their points and can relinquish the return window whenever they want to.
  • The API will be able to convert promised points even if the delay strategy is
    • Fixed delays from return period
    • Fixed delays from transaction item extended field
    • External Trigger
  • Please find below, a sample response.
  • In Phase 1, this is only supported for the TransactionAdd event.
{  
   "pointsUnlocked": [  
       {  
           "billNumber": "bill-79845882",  
           "pointsUnlocked": "10.000",  
           "programId": 2379  
       },  
       {  
           "billNumber": "bill-79845882",  
           "itemCode": "kidswear101",  
           "pointsUnlocked": "10.000",  
           "programId": 2379  
       },  
       {  
           "billNumber": "bill-79845882",  
           "itemCode": "accessory_purse",  
           "pointsUnlocked": "10.000",  
           "programId": 2379  
       }  
   ],  
   "warnings": \[]  
}

Reason:

To unlock points when the customer wants to forgo return window period to convert promised points to regular points for any transaction or line-item, to configure return window for each line-item and convert them into regular points according to each line-item return window.

Request:

POST /v2/points/unlockPromisedPoints?entityType=CUSTOMER&entityId=121212

Request Params:

entityType: USERGROUP2/CUSTOMER
entityId: 121212

Request Body:

{
    "eventName": "TransactionAdd",
    "billNumber": "16484",
    "eventLogId": 684034,
    "lineItemIds": [64384,64743,94745],
    "itemCodes": ["gd739","gd123"],
    "billDate":"2022-02-12",
    "sourceStoreId":1122,
    "sourceTilId":323,
    "sourceProgramId":2121
}

FieldsMandatory in request
eventNametrue
billNumberfalse
eventLogIdfalse
lineItemIdsfalse
itemCodesfalse
billDatefalse
sourceStoreIdfalse
sourceTilIdfalse
sourceProgramIdfalse

Request Body Combination:

Event NameBill Level ConversionLineItem Level Conversion
Generic

Combination 1 - eventLogID

Combination 2 - promotionId Combination 3 - promotionIdentifier

NA
CustomerPromotionImport

Combination 1 - eventLogID

Combination 2 - promotionId Combination 3 - promotionIdentifier

NA
TargetCompleted

Combination 1 - eventLogID

Combination 2 - promotionId Combination 3 - promotionIdentifier

NA
LineitemsPointsPromotionImportCombination 1 - billNumber Combination 2 - eventLogId Combination 5 - promotionId

Combination 3 - lineItemId, billNumber and eventLogId

Combination 4 - itemCode, billNumber and eventLogId

BillPointsPromotionImportCombination 1 - billNumber Combination 2 - eventLogId Combination 5- promotionId

Combination 3 - lineItemId, billNumber and eventLogId

Combination 4 - itemCode, billNumber and eventLogId

TransactionAdd|GroupTransactionAddCombination 1 - billNumber Combination 2 - eventLogId

Combination 3 - lineItemId, bilNumber and eventLogId

Combination 4 - itemCode, billNumber and eventLogId

Validation of request body combination will happen on api side

Validation:

  • the billNumber belongs to the customerId

Use Dao from RegularTxnDaoMysqlImpl - **Indexing already exists in loyalty_log for orgId and billNumber

public List<LoyaltyLogDto> getLoyaltyLogByOrgIdAndBillingNumber(Long orgId, String billNumber)
  • the lineitemId belongs to the billNumber
  • the lineitemId belongs to the customerId
  • the itemCode exists in billNumber
  • the itemCode exists in customerId

Use Dao from RegularTxnDaoMysqlImpl method getLineItemsByLoyaltyLogId -

public List<LoyaltyBillLineitemsDto> getLineItemsByLlId(Long orgId, Long llId, Long userId)
  • the billNumber should be unique, if not then we throw the error - Request failed. Multiple bills exist for the request with billNumber {{billId1}}, {{billId2}}, {{billId3}} …

Response:

Bill level point unlock response

{
  "pointsUnlocked": [
    {
      "billNumber": 374,
      "pointsUnlocked": 6,
      "programId" : 56
    },
    {
      "billNumber": 374,
      "itemCode": 4364,
      "pointsUnlocked": 12,
      "programId" : 78
    },
    {
      "billNumber": 374,
      "itemCode": 4365,
      "pointsUnlocked": 15,
      "programId" : 90
    }
  ]
}

Line item level point unlock response

{
  "pointsUnlocked": [
    {
      "billNumber": 374
      "itemCode": 7583,
      "pointsUnlocked": 24,
      "programId" : 12
    },
    {
      "billNumber": 374
      "itemCode": 4364,
      "pointsUnlocked": 12,
      "programId" : 34
    }
  ]
}

Customer promotion import point unlock response

{
  "pointsUnlocked": [
    {
      "pointsUnlocked": 24,
      "programId" : 12,
      "promotionIdentifier":"id1"
      "promotionId":12
      "promotionName":"promotion 1"
    }
  ]
}

📘

For bill level conversion of points only bill number and points converted will be given.

Error scenarios:

  • Throw warning when no promised points are found against billNumber / eventLogId
No promised points found for given billNumber | eventLogId
  • Throw error when promised points are already converted into regular points for the given identifier.
Points already unlocked for given billNumber | lineItemId | eventLog
  • Throw error when any eventLogId | billNumber | lineItemId not found
eventLog | lineItemId | billNumber not found.
  • Throw error when any mandatory params is not provided.
Missing required data required data - {param1}, {param2}
  • Throw error when there is conflict when duplicate promised points are found which cannot be resolved.
“Request failed. Multiple bills exist for the request with billId {{billId1}}, {{billId2}}, {{billId3}} …”
  • Throw error when converting promised points for a particular line item and params - billNumber and lineItem are not passed or else if any one of it missing then throw error.
{billNumber | lineItemId} is required. | billNumber and lineItemId is required
  • Throw error when any of the following params is not passed: eventName and entity.
{eventName | entity} is required.
  • Throw error when converting bill points and if any params required by it are not passed: eventLogId, billNumber and referenceId.
Required one of the following for bill points conversion - eventLogId or billNumber or referenceId

Code Flow:

  • We will be making the new API required for points unlock in
src/main/java/com/capillary/api/v2/impl/resource/PointsResource.java
  • Facade Layer we will be using -
src/main/java/com/capillary/api/v2/impl/service/facade/PointsV2Facade. java
  • Thrift layer -
src/main/java/com/capillary/api/v2/impl/service/external/EmfServiceV2. java

Promised points with “0” days delay

Earlier, brands were not able to convert the promised points into regular points or redeemable points on the same day to provide instant gratification to their customers. There are scenarios where customers end up splitting the bill to get benefit on the same visit.

Now, with this latest addition, brands are allowed to enter “0” days in the delayed accrual strategy (i.e., the number of days after which the promised points will convert to regular points) under points earn condition.

To get started,

  • Go to Loyalty+ → Strategies → Reward Currency → Add earn condition → Create the earn condition and enable delayed accrual → Enter 0 days (Refer to the ss below)

Now expire of promised points manually

As of now, there is no way to expire the promised points once issued. The points have to convert in regular/redeemable state and then they could be expired via import. There are cases where brands or a Capillary Poc wrongly issued promised points and have to revoke them so that they can limit the brands liability exposure due to implementation errors.

So, now a new option titled “Expire promised points” is made available under the points expiry import profile. With this latest addition, brands can right away expire the promised points whenever they want with a reason mapped to the expired points for remembrance.

To get started,

  • Go to organization settings → Data Import → Upload the appropriate csv file & submit → Choose Profile → Under the Points deductions import profiles, choose any of the three points expiry profiles depending on the requirement → Under the “Configure template”, the last option says "Expire promised points".
  • This “Expire promised points” is a check box option (refer to the ss below). When it is checked and submitted, the points in the promised state would expire for the specific set of customers.

Milestone enhancements

Event notification for the change in milestone achieved value on return of purchases

As of now, whenever a customer makes a purchase, all the milestone values which can be impacted with that purchase will be impacted, and the information of the new milestone achieved value, etc.. will be sent as an event notification.

However, whenever a customer returns a transaction, the milestone value which previously increased because of that purchase will also be decreased accordingly. But there is no event notification for such instances. To understand with an example:

Step 1: Milestone on lifetime purchases created, and milestone value is 10,000.
Step 2: Customer made a transaction worth 3000.
Step 3: Customer’s milestone achieved value increased from 0 → 3000
Step 4: Brand will get an event notification about the above step.
Step 5: After days, the customer returned the purchase of step-2.
Step 6: Now the milestone achieved value will decrease from 3000 → 0.
Step 7: But brands/customers are not getting any event notification of the same.

Now, with this latest enhancement, brands will get notified even in the case of return transactions about the decreased milestone value.

Following example shows the value in the notification:

If the “Name” key is “ReturnBill”, it’s a return transaction where milestone value is decreased by the “currentEventTargetValue” (400 here). We are not returning negative since it can lead to integration issues.

Achieved milestone value in add transaction API response

As of now, whenever brands want to know about the milestone's information (like milestone achieved value, current milestone value, etc..) using the AddTxn API, that is not possible. So because of that, they are depending on other APIs, and that takes time & effort.

Now, with this latest enhancement, brands can get the milestone’s information using the AddTxn itself. This can be achieved by making “rawSideEffects” value as true, whenever they call the AddTxn API.

When AddTxn is called with “rawSideEffects” as true, it will have following information along with other regular information.

Return enhancements

Re-evaluation of return in the event of earn capping

Let’s say a brand is running a program with 10% earn rate with bill/event level capping of 1000.

What’s happening now: Now, if a customer buys 2 items of 11000 each, the customer will only earn points on the 1st line item (1000pts). This is because, as per the capping, 1000 is the highest and that is already achieved with the 1st line item itself. If the customer is returning the 1st line-item, after the return re-evaluation, the customer will end up earning 0 point though the net payment is 11000.

What will happen now: After this enhancement, the customer will get 1000 points even though the 1st line item is returned. This is because, even though the 1st line item is returned, still the 2nd line item is eligible to get the points as per the configured capping condition.

(No screenshot as this is a backend login)

Re-evaluation of return in the event of achieved promos/earning.

Let’s say, a brand is running a promotion, that with a minimum purchase of 10000, customers can earn 1000 points with that transaction.

What’s happening now: Now, if a customer makes a purchase of 10000 ( 2 line items each worth 5000), the customer will get the 1000 points as per the promotion. If the customer returns 1 line item for whatever reason, points return is happening on pro-ratio (.i.e., only 500 points are getting reversed).

What will happen now: After this enhancement, all the 1000 points which customers received will be returned. This is because, without that returned line item of worth 5000, the bill wouldn’t have crossed 10000 in the first place, and therefore the customer is not eligible for any points as per the promotion.

(No screenshot as this is a backend login)

Goodwill points support in Group Loyalty

You can now allocate goodwill points to user groups. Refer the API here.

Behavioural event support for UserGroup2

As of now, the behavioural events didn’t work for user groups. The behavioural events would only work for individual customers. Now, behavioral events can be configured for user groups as well.

This is possible at the action level.When configuring an action like Points allocation, issue coupons, etc. you will be able to see a drop down to select “individual” or” User group”. On selecting the user group option, that particular action in the behavioural events will work for the groups in your system.

Below screenshot helps in understanding:

Bug fixes in re-evaluation of return transactions

As of now, whenever someone returns some items, re-evaluation of the return bill used to happen based on the return date but not as per the purchase date. Because of this what used to happen is, if there is a promotion running when the customer returns the bill, the customer used to get those promotional points even though customers were not supposed to get them.

Following example helps in understanding better:**
Step 1: Customer made a purchase on 10th march.
Step 2: Brand is running a promotion from March 20th to March 30th. (Say 100 bonus points)
Step 3: Customer returned the item on March 25th which was bought on step1.
Step 4: Return re-evaluation happens, and customers used to get 100 points as the return bill processing date is 25th March where a promotion is active in that duration.

However, step - 4 is wrong. Customers should not get any points because when purchase of the product happened, no promotion was running. This issue occurred because return bill processing happened on the return date not on the purchase date.

With this new enhancement, in step - 4, when re-evaluation is happening, it will take the purchase date instead of the return date as the bill processing date. Because of this enhancement, even if a promotion is happening during the return, customers won’t be evaluated for the promotion.

No screenshot as this is a backend logic change.

Behavioural event payload getting passed in pointsIssued event notification

As of now, whenever brands want to know any information about points issued, they are using the “pointsIssued” payload. However, this payload does not have the “Remarks” field which contains the vendor information that brands are looking for.

The event “additionalAttributes” contains the “Remarks” information, but it would require additional effort to make additional API calls, and that is a slight inconvenience.

With this enhancement, now brands will be able to get the “Remarks” from the “pointsIssued” itself. So, they don’t have to make multiple API calls to get the “Remarks” information.

They just have to check: “triggeringActivity” -> “additionalAttributes” -> “Remarks”

Following API payload helps in understanding better:

Minor changes to new UI of coalition & subscription programs

As of now, both in coalition & subscription programs creation flow, there is an option called “Benefits Limit” which users have to configure while configuring them. Basically, this is to put a limit on the amount of benefits/loyalty promotions customers can get from either coalition or subscription programs.

Also, earlier if one promotion is linked to a subscription or coalition program, it cannot be deleted. The coalition or subscription program has to end, to end the promotion linked with the program.

Now, we have made 2 new enhancements in the new UI of coalition and subscription programs where the above issues won’t be there.

Enhancement made:

  1. Benefits limit option is removed, as the limit will be already configured in the loyalty promotion itself. Whatever limit that previously used to stay here won’t matter, as that will always be overridden by the restrictions configured in the loyalty promotions.
  2. Now when a loyalty promotion/benefit is linked to a coalition or subscription program, that can be deleted very easily by clicking on the delete icon along each benefit.

Refer to the ss below:

Milestone / Target Loyalty reporting

We are launching the milestone/target loyalty report.

This is Phase -1 in which we have created global databricks notebooks for all the clusters.You can export and schedule this report as per the brands requirement.

The brands for which the data has been onboarded successfully for the milestone report are :

Unilever, TATA, Shell, Redtag, Corteva, Metro, Kanmo, Bukl Enperprise (Demo)

Please find the notebooks for India, SG and EU clusters below :

👉IN - https://capillary-india.cloud.databricks.com/#notebook/543193/command/543194

👉SG - https://dbc-463ee9a0-fda6.cloud.databricks.com/?#notebook/398685/command/399316

👉EU - https://dbc-73b168c8-6c00.cloud.databricks.com/?#notebook/115375/command/115376

Make sure you have access to clusters before using the above notes.

PS - We will soon release the report on Insights+.

New workflow to upload custom milestones for B2B businesses

Earlier, in order to upload a customer list in a milestone, users had to do it through the data import functionality which was a bit challenging, and would give an error if any at the end of the import flow, when the user had already gone through multiple steps.

  • With this enhancement, users can now upload the csv file for the custom enrolled milestones then and there without switching to the data import UI and that too in a much simpler way.
  • On the same lines, as soon as the customer list is uploaded and Saved, a trigger would be sent to the customers present in the list, who have been enrolled in the milestone.

Find a detailed document here : here

Find the documentation on the support portal here: here

Handling retro transactions

Business context
Retroactive transactions, also known as retro transactions, refer to transactions that are applied to a loyalty program account after the transaction has taken place. These are the transactions where the processing date is more than the actual transaction date, which sometimes results in unfair loss to either brand or customer.

This is one of the very common scenarios in the aviation industry. Customers do not provide their loyalty information while traveling, but come back again in the future to avail the loyalty benefits.

Take for example, a customer made a flight journey on 20th March but not given loyalty details on that date. Instead, at some point in the future (say 20th april), wishes to avail the benefits of that journey, and so reaches out to customer service for the same. In this case, the processing date (20th April) is more than the transaction date (20th March).

This might lead to a problem, because the customer might have upgraded/degraded from a tier in this time period. Say, the customer might be on the silver tier on 20th March and Gold tier on 20th April. If the journey is processed as per 20th April, benefits will be given as per the gold slab even though the customer is on the silver slab on the date of the transaction.

Until now, we only have the ability to process these retro transactions based only on the processing date (20th April in above example) not the transaction date (20th March).

The enhancement
With this enhancement, now brands will have the ability to choose what date to use for retro transactions as per their policies. It will be an org level setting, where the brand can enable this option. When this is enabled, retro transactions will be processed based on the actual transaction date, and when not enabled, these retro transactions will be processed as per the processing date.

(As of now, this enablement is provided only through backend, so please reach out to the sustenance team to enable this for your org. Very soon, we will be provide an UI option to do the same)

In membercare, a clear differentiation will be visible whether the transaction is processed as per the “transaction date” or the “processing date”.

Getting target information even for the inactive periods

This is an enhancement to the GetUserTargets API’s response. As of now, whenever this API is called, it provides “only active targets” information from the user target tables.

With this enhancement, this API can get responses even for inactive periods, when called with “includeInactive” as “true”. This enhancement basically helps in showing the targets even when they are zero providing a better customer experience at the end point.

There are 3 request params for this API, they are

  1. trackingDate,
  2. targetRuleId
  3. includeInactive.

API Signature : v3/users/{{userId}}/targetGroups

Let’s understand with an example:
We created two targets(T1, T2) for three periods (P1: Jan to Mar, P2: April - June, P3: July - Sep).
A customer enrolled during the period P2. So, this customer is inactive during P1.

After this enhancement, if this API is called with “includeInactive” as “true” during P2, it will create return all the combination (Target periods * Targets) irrespective of active/inactive. Now the response contains target level information for all the 6 combinations.

Response for the above will be:
(P1 - T1), (P1 - T2), (P2 - T1), (P2 - T2), (P3 - T1), (P3-T2) target-period combinations information. For the response which is created artificially for inactive periods (in this case P1 period because customer is not active in that period, P3 period as call is made during P2 .i.e., P3 didn’t happened yet):

  1. target achieved value will be “0” and
  2. target id will be “null”

P.S: When trackingDate, trackingRuleId are passed, they will be honoured too accordingly.

Show points issued & communication information for sub-targets

This is also an enhancement to the existing GetUserTargets API, and this enhancement can greatly enhance the end-user experience in the following ways.

As of now, we don’t have the ability from the API to know about the points issued details, communications details that happened whenever a sub-target is achieved.

Let’s understand with below example:

Let’s say, the target value is 10,000. But the brand decided to motivate customers at few of the stages in the journey, as that can push the customers to transact more subconsciously.

A brand might want to issue 100 points when the customer reaches 5000 target value. The moment a customer reaches 5000, the customer will get 100 points and a communication will be sent.

With this enhancement, the information of “points issued & communications details” for these sub-targets achievements will also be available from the API.

Following screenshot helps better understanding:

The key “milestones” contains this information.
Whenever a sub-target is achieved (basically, when isAcheived = true):

  1. Information of points issued for that achievement (how many redeemable points, delayed points, external triggered points) and
  2. Communication ids (message id) will be available in the response body.