# System Design Interview: Design a Loyalty and Rewards Points System

Source: https://www.techinterview.org/post/3233462761/system-design-loyalty-rewards-system/
Updated: 2026-04-17 · techinterview.org

## What Is a Loyalty and Rewards System?

A loyalty program tracks user activity and awards points redeemable for discounts or products. Amazon Prime, Starbucks Rewards, and airline miles programs are examples. Core challenges: points accrual without race conditions, expiry, transaction consistency, and scaling to tens of millions of members.

- [Coinbase Interview Guide](https://techinterview.org/coinbase-software-engineer-interview/)

- [LinkedIn Interview Guide](https://techinterview.org/linkedin-software-engineer-interview/)

- [Airbnb Interview Guide](https://techinterview.org/airbnb-software-engineer-interview/)

- [DoorDash Interview Guide](https://techinterview.org/doordash-software-engineer-interview/)

- [Stripe Interview Guide](https://techinterview.org/stripe-software-engineer-interview/)

- [Shopify Interview Guide](https://techinterview.org/shopify-software-engineer-interview/)

## System Requirements

### Functional

  - Award points for purchases, referrals, reviews, login streaks

  - Redeem points against purchases

  - Points expiry after 12 months

  - Tier system: Bronze/Silver/Gold based on spend

  - Promotional multipliers: 2x/3x points during campaigns

### Non-Functional

  - Exact consistency — no lost or duplicated points (billing depends on it)

  - Idempotency — retries must not double-award

  - 100M members, 10K transactions/second peak

## Core Data Model


```
members: id, user_id, tier, total_earned, total_redeemed
point_transactions: id, member_id, type(earn/redeem/expire), amount,
                    reference_id, reference_type, created_at, expires_at
point_balances: member_id, available_points, tier_points_ytd
```


## Points Accrual — Idempotency

Risk: loyalty service crashes after processing but before committing Kafka offset — event redelivered, double points. Solution: unique constraint on (reference_id, reference_type):


```
INSERT INTO point_transactions
    (member_id, type, amount, reference_id, reference_type)
VALUES (?, 'earn', ?, 'order_123', 'purchase')
ON CONFLICT (reference_id, reference_type) DO NOTHING;
```

Even if processed twice, only one row is inserted. Safe to replay Kafka events.

## Balance — Ledger + Cached Sum

Update cached balance atomically with each transaction:


```
BEGIN TRANSACTION;
INSERT INTO point_transactions (...) VALUES (...);
UPDATE point_balances
  SET available_points = available_points + ?
  WHERE member_id = ?;
COMMIT;
```


## Redemption — Preventing Overdraft

User tries to redeem 500 points but only has 300. Pessimistic locking:


```
BEGIN TRANSACTION;
SELECT available_points FROM point_balances
WHERE member_id = ? FOR UPDATE;  -- row lock
IF available_points < 500: ROLLBACK;
INSERT INTO point_transactions (type='redeem', amount=-500, ...);
UPDATE point_balances SET available_points = available_points - 500;
COMMIT;
```

FOR UPDATE prevents two concurrent redemptions from both succeeding with insufficient balance. Low contention (one user's balance) justifies pessimistic over optimistic locking here.

## Points Expiry

  - Store expires_at on each earn transaction

  - Nightly batch job: compute unredeemed amount of expiring transactions, insert expiry transaction

  - FIFO redemption: consume oldest non-expired points first

  - Notify members 30/7/1 days before expiry

## Tier System and Promotions

Tiers computed by nightly job on rolling-12-month spend. Store tier_points_ytd in point_balances. Promotions: at accrual time, check active promotions and apply highest multiplier. Store multiplier in point_transactions for auditing.

## Caching

  - Member balance/tier: Redis 30-second TTL, invalidated on each transaction

  - Active promotions: Redis 5-minute TTL

  - Transaction history: paginated, 60-second TTL

## Interview Tips

  - Idempotency via unique constraint on reference_id is the core reliability pattern.

  - Ledger + cached balance = double-entry accounting — shows financial systems knowledge.

  - FOR UPDATE for redemption: low contention but high cost of overdraft justifies pessimistic locking.

  - FIFO expiry and tier computation are product details that differentiate senior candidates.
