Skip to main content

Loyalty Tiers

Tier Structure

Each tier has:

FieldTypeDescription
idstringUnique identifier
tierintegerLevel number (1 = base, higher = better)
minAmountdecimalMinimum 12-month spend to qualify
rewardRuleIdstringLinked reward rule for point calculation
redemptionCapabilitydecimalMax % of booking payable via wallet
metadataJSONBAdditional tier data (name, icon, color, etc.)

Example Tier Configuration

TierLevelMin SpendReward RuleRedemption
Silver1Rs 01% cashback20%
Gold2Rs 50,0002% cashback30%
Platinum3Rs 200,0003% cashback50%

Opt-In Flow

Guest calls POST /api/loyalty/opt-in
→ LoyaltyService.optIn(accountId)
→ Assigns base tier (lowest tier number)
→ Sets loyaltyStartDate = today
→ Sets loyaltyEndDate = today + 1 year - 1 day
→ Sets tierNextUpdateDate = today + 2 years - 1 day
→ Creates wallet if not exists

Tier Evaluation Rules

Tier only upgrades, never downgrades (except for 2+ year re-evaluation).

On Checkout (daily, 4 AM)

After each checkout, the system re-evaluates the guest's tier based on 12-month spend. If spend exceeds the next tier's threshold, the tier is upgraded.

Annual Renewal (daily, 5 AM)

When tierNextUpdateDate passes:

  • Resets amountSpentLast12Months to zero
  • Extends dates by 1 year
  • Preserves current tier

Long-Term Re-Evaluation (daily, 6 AM)

For members 2+ years in the program:

  • Re-evaluates tier based on recent spend
  • Allows both upgrade and downgrade
  • Renews dates

Manual Re-Evaluation

After tier config changes (create/update), admins can trigger re-evaluation:

POST /api/v1/admin/loyalty-tiers/re-evaluate

This scans all members and upgrades any who qualify for a higher tier.

Tier Progression Response

The GET /api/loyalty endpoint returns:

{
"loyalty": { "id": "...", "accountId": "...", "loyaltyTierId": "...", "amountSpentLast12Months": 75000 },
"tier": { "id": "...", "tier": 2, "minAmount": 50000, "redemptionCapability": 30 },
"benefits": [{ "benefitType": "ROOM_UPGRADE", "isRedeemable": true }],
"rewardRule": { "amountSpent": 10000, "rewardPoints": 200, "expiryDays": 365 },
"nextTier": { "tier": 3, "minAmount": 200000 },
"amountToNextTier": 125000
}

Benefits

Benefits are linked to tiers via the loyalty_tier_benefit M2M table. Admin endpoints:

GET    /api/v1/admin/loyalty-tiers/{id}/benefits    # list benefits for tier
POST /api/v1/admin/loyalty-tiers/{id}/benefits # set benefits (replaces all)

Each benefit has:

FieldTypeDescription
categorystringGrouping (e.g., UPGRADE, DISCOUNT, SERVICE)
benefitTypestringSpecific benefit (e.g., ROOM_UPGRADE, EARLY_CHECKIN)
isRedeemablebooleanWhether guest can actively redeem
maxRedeemPerYearintegerAnnual redemption limit

Scheduled Jobs

JobCronPurpose
updateTiersOnCheckout0 0 4 * * * (4 AM)Upgrade tiers post-checkout
renewExpiredLoyalty0 0 5 * * * (5 AM)Annual renewal
changeTierForLongTermMembers0 0 6 * * * (6 AM)2+ year re-evaluation

All cron expressions are configurable via properties (e.g., loyalty.scheduler.checkout-update).