Skip to main content

Earning points

How to use it

Decide how customers earn, then let it run automatically:

  1. Set your base earn rate — e.g. 10 points per $1 spent. (Loyalty → Setup → Earning)
  2. Set tier multipliers so bigger spenders earn faster. (Loyalty → Tiers)
  3. Add earning beyond purchases — sign-up, reviews, birthdays. (Loyalty → Settings → Actions)
  4. Run a campaign for a push, like a double-points weekend. (Loyalty → Campaigns)

Earning then happens automatically on every paid order — no manual work.

⏱ ~10 min · 💳 Starter+ · 🎯 Points awarded on the next paid order

Purchase earning

When an order is marked paid, the customer earns:

points = round( order_total × base_rate ) × tier_multiplier

With defaults (base rate 10 points per unit of currency), a $80 order earns:

TierMultiplierPoints on an $80 order
Bronze1.0×800
Silver1.5×1,200
Gold2.0×1,600
Platinum3.0×2,400

The tier used is the customer's tier at the time of the order, derived from their lifetime points. The award is written as an earned ledger row keyed to the order, and a uniqueness rule on (shop, order, type) means a duplicate webhook delivery can never award the same order twice.

One formula, everywhere

The earn math lives in a single pure module that both the award engine and the merchant-facing preview card import. So the "customers earn N points" number a shopper sees on the product page is computed by the exact same code that the ORDERS_PAID webhook later runs — they cannot disagree.

Stacking bonus earning

On top of the base purchase award, an order can trigger extra earning. Each is written as its own bonus ledger row so the reason reads honestly and each is independently idempotent.

Campaigns — time-boxed multipliers or flat bonuses

Run a "Double Points Weekend" or a "+200 points on this collection" push. A campaign has a type (multiplier or bonus), a scope (store or specific products), and a start/end window. The single best active campaign for the order applies.

FieldMeaning
Typemultiplier (e.g. 2× points) or bonus (flat extra points)
ScopeWhole store, or only orders containing specific products
WindowstartsAtendsAt; status auto-advances scheduled → active → ended

Milestones — one-time lifetime rewards

Gamify long-term loyalty: award a one-time bonus the first time a customer's lifetime points cross a threshold (e.g. "10,000 points → 500 bonus"). Each milestone grants once, ever — checked against the new lifetime total after the order's base + campaign points.

Purchase-threshold bonus — revenue-positive

A flat extra award when an order's qualifying value clears a floor (e.g. "orders over $150 earn a 500-point bonus"). Unlike a check-in reward, the bonus is tied to a real qualifying purchase, so it's genuinely revenue-driven. Off by default.

Action points — earning beyond purchases

So loyalty isn't only a repeat-purchase discount, customers earn for engagement and acquisition actions. Each action grants once (de-duped on the action's natural scope), respects the programme's active status, and is configurable (0 disables an action).

ActionDefaultTriggerOne-per
Sign-up200Account created (CUSTOMERS_CREATE)Account
Verified review50Review of a purchased productProduct
Birthday500Daily cron matches month/dayYear
Referral100Friend places first paid orderHandled by the referral engine

Reviews are gated to verified purchases — a customer can only earn the review bonus for a product they actually bought (recorded from order line items). Details on check-in, birthday, and reviews in Engagement & streaks.

What a customer's ledger looks like

+ earned 800 Purchase: order #1042 — bronze tier (1.0×) bal 800
+ bonus 800 Campaign: Double Points Weekend bal 1,600
+ bonus 500 Milestone reached: 1,000 points bal 2,100
- redeemed −500 Redemption — code LOY-7QK2 (5.00 off) bal 1,600
- expired −120 Points expired after 12 months bal 1,480

Every row carries the before/after balance and a human reason, so support can explain any balance and finance can audit the liability.

Points expiry

Earned and bonus points expire after the configured window (default 12 months; set to 0 to never expire). Expiry is stamped on each earn lot at award time, and a monthly sweep reclaims lots whose window has passed — oldest-first, clamped to the customer's live balance so a spent-down customer never goes negative. Customers with points expiring soon are a prime re-engagement audience.

Best practices

Set your earn rate against your redeem rate deliberately. With the defaults (10 pts per $1, 100 pts = $1) each dollar spent returns ~10% in points value at the base tier — generous. Tune the base rate to your target reward cost.

Use campaigns for pushes, not permanent lifts. A time-boxed double-points weekend drives urgency; a permanent 2× just inflates liability.

Turn on the purchase-threshold bonus to lift AOV, not the check-in reward — the threshold bonus only pays out on real, qualifying revenue.

Don't disable expiry unless you've modelled the liability. "Never expire" means points accumulate forever on your books.