A customer applies points at checkout. The screen hangs, so they tap the button again. A moment later, the balance has changed twice.
For the customer, this is a trust problem. For the retailer, it is a disagreement between the cart, order, payment, loyalty account and marketing report. The discount can look perfectly clear on screen while several systems hold different versions of what happened.
I’m Anton Fokin, CEO of Qtim. This article treats a loyalty program as an operational system: where duplicate deductions come from, why a balance needs an event history, how returns expose missing rules and what teams should decide before the first high-traffic campaign.
The stakes go beyond points. Deloitte’s 2025 Consumer Loyalty Program Survey covered 5,564 adult loyalty-program members in the United States. Among respondents speaking about their favorite brand’s program, 72% said it made them more likely to buy from that brand, while 56% said it led them to spend more. The figures describe a specific U.S. sample and favorite programs, but they show why reliability matters: loyalty mechanics influence both store choice and basket size.
One button crosses the entire order flow
On screen, a loyalty program looks compact: a balance, campaign terms and an “Apply points” button. Behind that button sit the customer profile, promotion rules, cart, order, payment, returns, CRM, analytics and support. Each system updates on its own schedule.
The cart may have reserved the points while the payment service is still processing the charge and the app is displaying a cached balance. Each value can be correct for its own moment and still produce the wrong story for the customer.
Design therefore starts with events. The team needs to define when points are reserved, when a deduction becomes final, which event releases a reservation and what happens after a full or partial cancellation.
One question anchors the model: which system has the authority to make the final change to the loyalty account? Without a clear owner, the website, mobile app, point-of-sale system and CRM can all submit commands for the same purchase.
A retry should return the first result
The most damaging failure often begins with a reasonable recovery attempt. The customer taps “Apply points,” the response is delayed and the app retries. The server may have completed the first operation even though the confirmation never reached the phone.
AWS describes safe retries through idempotent APIs. The client sends a unique request identifier; the service recognizes a duplicate and returns the result of the operation it has already completed. Recording the identifier and changing the data must happen atomically, as a single transaction.
For a loyalty program, the same operation ID should travel through the cart, loyalty service, order and error log. A retry with that ID returns the previous result instead of creating another deduction. If the ID arrives with different parameters, the service should reject it with a traceable error because the customer’s intent has changed.
Accruals need the same protection. A payment service, checkout system or integration may resend an event after a timeout. Without duplicate detection, one purchase can earn points twice, and the problem may surface only during the next order or a campaign-budget reconciliation.
The balance is only the last line of the ledger
“Balance: 2,400” answers one question: how much is available now? Support needs the history behind that number. Which order earned the points? What has already been spent? Which reservation is still active? When did some points expire? Which event corrected an error?
Square’s Loyalty API records each balance change as an event, including point accumulation, reward redemption and expiration. Events remain immutable, while a reversal creates a separate record instead of rewriting the past. That is one vendor’s implementation, but the underlying principle travels well: calculate the current balance from an auditable chain of actions.
An event ledger gives three teams a shared view. Support can explain a specific deduction without comparing several admin panels. Engineers can reproduce the request sequence. Finance and marketing can reconcile program costs with orders, returns and expired rewards.
Corrections should be events too. When an operator simply edits the number in a profile, the reason disappears. A compensating entry preserves the original operation, author, reason and outcome.
Returns expose rules that checkout can hide
Orders and points have different lifecycles. An order can be created, partially paid, split, cancelled or returned item by item. At the same time, its points may be pending, available, reserved for another purchase or expired.
A minimum state map connects those lifecycles:
- At checkout, reserve the requested amount.
- After the agreed order event, finalize the deduction.
- After failed payment or reservation expiry, release the points.
- After a return, create a compensating operation according to the program rules.
This is where engineering reaches a business decision. What happens to points earned on a returned item? How should a promotional multiplier be recalculated? What if the customer has already spent the reward? How does a partial return change the account?
The system can execute any rule that has been specified clearly. The owner of the loyalty program has to agree on those answers before development. A transition table makes the agreement testable: initial state, event, next state, permitted retry and action on failure.
Peak traffic needs an explicit failure mode
Campaign traffic rarely spreads evenly across the day. A newsletter, the start of a sale or the final hours before points expire can send thousands of customers to the same operation at once. The service has to validate rules, read the balance, create a reservation and synchronize the result with the order.
The business usually has three degradation strategies:
- Block checkout until the loyalty service recovers. This preserves strict consistency and stops sales during the outage.
- Complete the order without points and explain the limitation. The team then needs a clear way to honor or compensate the original offer.
- Queue the operation and show an intermediate status. This requires a processing deadline and protection against stale commands.
The dangerous option is silent degradation. The interface displays an old balance and lets the customer continue even though another channel has already changed it. The product makes a promise that the operational system cannot keep.
Before a campaign, monitor at least the error rate for accruals and deductions, the delay between an order status and the related loyalty operation, the number of retries, the age of queued messages and discrepancies found during reconciliation. Average service availability can look healthy while the critical purchase path is slowing down.
Different products create the same architectural pressure
In the 4fresh project, Qtim migrated an online store from 1C-Bitrix to a custom solution and developed its loyalty mechanics: an internal currency, referral programs and a premium club. Customer profiles and order history moved at the same time. That connected reward rules directly to customer data and the commercial flow of the store.
In Studycats, six educational courses were brought together on one platform with a shared referral program. The published flow is straightforward: a friend code leads to a purchase, the purchase earns Catcoins, and Catcoins can be exchanged for discounts and promo codes. The same internal currency works across all six courses.
The products are different, but they raise the same questions. Who counts as one user? Which event confirms a purchase? How is a retry recognized? Where does the event history live? What can support see? Once one benefit works across channels and order types, its rules run through the entire product.
The public case studies confirm the product mechanics and scope. They do not disclose the transaction architecture, so the examples should not be read as claims about their internal implementation.
Six questions to answer before a mass campaign
Take one order from campaign eligibility to return and answer six questions:
- Event: what triggers an accrual, reservation, deduction, cancellation and compensation?
- Source: which system owns the final history of loyalty operations?
- Retry: how is one request recognized across all connected services?
- State: which intermediate statuses can the customer, support team and analysts see?
- Return: how do full and partial cancellations affect earned and spent points?
- Failure: what happens to the order when the loyalty service, checkout or integration is unavailable?
Only then is it useful to design screens, APIs, queues, monitoring and test scenarios. An unanswered question will return later as a disagreement between systems.
The load test should include simultaneous deductions from two channels, a retry after timeout, a partial return, cancellation at the reservation-expiry boundary, redelivery of the same event and queue recovery.
If points change the order total, treat them like money
A loyalty program survives peak traffic when every operation can be identified once, moved through explicit states, reconstructed from a ledger and reconciled with the order. Support can explain what happened, marketing can see the true cost of the campaign and the customer sees the balance they were promised.
The decision rule is simple: if points change the order total or create an obligation to the customer, design them with the discipline of a payment operation: unique identifiers, explicit states, an event ledger, reconciliation and monitoring.
If you want to test this flow before a mass campaign, Qtim can trace one order from campaign rules to return and identify where the interface, integrations or architecture need to change. Learn more about our e-commerce platform development work.




Top comments (0)