All Drafts

A loyalty program where no point is lost or made up

I built the loyalty program for a Chilean eCommerce with two stores: a ledger where nothing is deleted, clear rules for earning, redeeming and expiring, monitoring every ten minutes, and the liability accounting ready for the accountant.

Daniel Flores Osses
Daniel Flores Osses
Oct 20, 2026 · 6 min read

A customer writes: "I didn't get the points for my purchase". To answer in seconds, you have to be able to see which purchase added points, which redemption took them away, and why the balance is what it is. I rebuilt the loyalty program for a Chilean eCommerce with two stores, one retail and one wholesale, so that would be possible and so any failure would be caught in time.

The foundation is the same in both: 1 point is worth 1 peso and you earn 1% of what you pay, to use as a discount on later purchases.


A ledger that never gets erased

Every movement is recorded in a ledger, as in accounting. Nothing is edited or deleted: a correction is always a new movement. A customer's balance is the sum of their movements, and each row stores the amount, the resulting balance, the date, the origin and the author.

There are only a few possible movements: purchase, recovered credit, opening balance, redemption, redemption refund, reversal, manual adjustment and expiration.


The rules in the retail store

Cart$50.00010% coupon−$5.000Paid$45.000VAT and shipping included+450points1% of what was paid✓Buys with their account: earns✕Buys as a guest: doesn't earnCredited only once payment is confirmed
Points are calculated on what the customer actually paid, after coupons, and only if they bought while logged into their account.
  • Only those who buy while logged in earn points; guests see how much they would earn if they sign up.
  • It's calculated on what was paid, after coupons and after the redemption itself.
  • It's credited when payment is confirmed, not before.
  • Redemption happens at checkout and is reserved when the order is created, so the same balance can't be used twice.
  • If the order is canceled, the redeemed points come back on their own.

Reversals without negative balances

MovementAmountBalancePurchase #1+500500Redemption on purchase #2−5000Refund of #1−500 → 00Loss absorbed: 500, covered by the companyNothing is edited or deleted: things are only added
The balance is the sum of the ledger. If a reversal has nothing to deduct from, the balance stays at zero and the difference is recorded.

Canceling or refunding an order reverses what it earned. If the customer has already spent those points, the balance drops to zero and the difference is recorded as an absorbed loss: the customer isn't charged, and each case opens an alert to catch abuse.

Expiration: oldest first

January+500March+800Redemption−600used700 leftThe remaining 700 expire in March of the following yearEach credit expires after 12 monthsand redemptions use the oldest first
The oldest is spent first. That way only what has really gone a year unused expires.

Each credit expires after 12 months and redemptions use the oldest first (FIFO: first in, first out). The customer gets notices 30 and 7 days beforehand, and expiration is only switched on with approval.


Something watching all the time

The app checks the store every ten minutes with detection rules.

every10 min✓Plugin with heartbeat signals✓Paid orders that earned✓Redemptions that match✓Balance never negative✓Mirror equal to the ledger✕An order didn't earnCritical failureinstant emailAutomatic sweepcredits what was missed
The app checks the store every ten minutes. If something stops earning, it alerts immediately and the sweep fixes it on its own.
  • The plugin stopped sending signals or the store isn't responding.
  • Paid orders that didn't earn points, or a whole day with no earning.
  • Redemptions that don't match the order's discount.
  • Balances written outside the ledger or too many manual adjustments in an hour.

Critical failures arrive by email instantly and the rest in a daily summary. An automatic sweep fixes the orders that didn't earn, and whatever wasn't credited in the past is recovered in batches that an admin approves, never crediting twice.

A loyalty program that fails silently is worse than having no program. This one sends alerts.

Points are also accounting

For the company, issued points are a debt to the customer until they're used or expire. The IFRS 15 standard splits each sale between the product (today's revenue) and the points (a liability for later).

A purchase that earns pointsProducttoday's revenuePointsdeferred liabilityIf redeemedbecomes salesIf they expirebecomes incomeEach issued point equals ≈ 0.832 of liability
Points are a debt to the customer until they're used or expire. The app keeps that account month by month for the accountant.

The app tracks that liability month by month and exports it in a file ready for the accountant.


The app from the inside

  • Summary: what's owed today, the liability, the redemption rate and what share of orders did earn points.
  • Customers: search by name, email or RUT, and a record with their full history.
  • Movements and events: every point that comes in or goes out, and what doesn't move the balance but explains what happened.
  • Redemptions, accounting, failures and audit, where it's recorded who did what.
  • Manual adjustments with a mandatory reason and a cap above which an admin is needed.
  • Three roles: read-only, editor and admin.

The wholesale store: different rules

Here the customers are companies that pay by bank transfer and work with an account executive, so the program changes almost completely.

Payment by bank transferBy card: no1 · RUT on the invoicethe main source✕2 · RUT on the orderif the account isn't a staff account or a multi-RUT account✓+1% to that RUT's ledgertruncated to the peso, payment by paymentIf none works: Pendingdoesn't earn until the record is fixed in the ERP
In the wholesale store, the owner of the points is the RUT that gets invoiced. If it can't be determined which one, the payment waits in Pending.
  • The owner of the points is the RUT that gets invoiced, not the web account.
  • Only bank transfers earn points , reconciled against an invoice in the ERP.
  • The executive handles the redemption in the ERP, and the app flags those that exceed the balance.
  • Expires from inactivity: 12 months without buying or redeeming, with prior notices and the owner's approval.
  • Payments without a valid RUT wait in Pending until the record is corrected.
  • Links and transfers between RUTs of the same customer, always with double approval or an entry in the ledger.

Changing the engine without the customer noticing

In both stores the switch went through a shadow mode: the new ledger calculates everything in parallel without touching the visible balances, and is compared every day with what customers see.

Old mode, but monitoredcustomers see no changeShadow: the ledger runs in parallelcompared every night with the old one7 days in a row matchingone unexplained difference resets the streakThe ledger takes overonly with explicit approvalRecover what was missedin approved batches, never crediting twice
Nothing changed for customers until the ledger matched seven days in a row. Every irreversible step required approval.

Only with seven days in a row matching, and every difference explained, does the ledger take over. Every irreversible step requires approval.


What the business gains

Answers in seconds to "why do I have this balance?", no silent failures, a defensible accounting figure, and rules built for each store.

The balance isn't a number someone stored. It's the sum of everything that happened.

Want a system like this for your business? Let's talk.

Contact me