# Coupon and Discount System Low-Level Design

Source: https://www.techinterview.org/post/3233467282/lld-coupon-system/
Updated: 2026-04-17 · techinterview.org

## Requirements

  - Create and manage discount coupons (percentage, fixed amount, free shipping)

  - Apply coupon to a cart: validate, compute discount, prevent reuse

  - Support: single-use codes, multi-use codes with a global limit, user-specific codes

  - Prevent race conditions: same coupon applied concurrently by many users

  - 100M users, 10K coupon redemptions/second during flash sales

## Data Model


```
Coupon(coupon_id, code VARCHAR UNIQUE, type ENUM(PERCENT,FIXED,FREESHIP),
       value DECIMAL, min_order_amount, max_uses INT, uses_count INT,
       max_uses_per_user INT, valid_from, valid_until, status ENUM(ACTIVE,EXPIRED,DISABLED),
       applicable_product_ids[], applicable_category_ids[])

CouponRedemption(redemption_id, coupon_id, user_id, order_id,
                 discount_amount, redeemed_at)
```


## Coupon Validation

On apply coupon (before order placement):

  - Look up coupon by code (Redis cache: key=coupon:{code}, TTL=1min)

  - Check status=ACTIVE and valid_from <= NOW() <= valid_until

  - Check cart total >= min_order_amount

  - Check uses_count < max_uses (global limit not exhausted)

  - Check user redemption count < max_uses_per_user (query CouponRedemption)

  - Check applicable products/categories match cart items

Return: discount amount (if PERCENT: order_total * value/100, if FIXED: min(value, order_total)).

## Preventing Race Conditions on Global Limit

Problem: 10K users try to redeem the last spot of a coupon simultaneously. Without locking, uses_count could exceed max_uses.

Solution: Atomic Redis decrement. Before DB insert:


```
# Initialize Redis counter on coupon creation:
SET coupon_remaining:{coupon_id} {max_uses - current_uses}

# On redemption attempt:
remaining = DECR coupon_remaining:{coupon_id}
if remaining < 0:
    INCR coupon_remaining:{coupon_id}  # undo
    return CouponExhausted
# Proceed with DB insert
```

Redis DECR is atomic — no two requests can simultaneously see remaining >= 1 and both decrement to 0. After the Redis check, insert CouponRedemption and increment uses_count in DB. If the DB insert fails (duplicate key on user+coupon), INCR to undo the Redis decrement.

## Per-User Rate Limiting

Check max_uses_per_user: SELECT COUNT(*) FROM CouponRedemption WHERE coupon_id=X AND user_id=Y. Cache result (key=user_coupon_uses:{user_id}:{coupon_id}, TTL=60s). For max_uses_per_user=1 (single-use per user): use a UNIQUE constraint on (coupon_id, user_id) in CouponRedemption. Concurrent redemptions from the same user: the second INSERT fails with a duplicate key error, safely returning AlreadyUsed.

## Coupon Redemption Flow

  - Validate coupon (all checks above)

  - Decrement Redis remaining counter

  - Place order with discount applied

  - INSERT CouponRedemption record

  - UPDATE Coupon SET uses_count = uses_count + 1 (async, for reporting)

Step 3 and 4 are in a database transaction. If the transaction fails, undo step 2 (INCR Redis counter). For steps 2-4, use a saga pattern with compensation.

## Bulk Coupon Generation

For marketing campaigns: generate 1M unique single-use codes. Use a CSPRNG (cryptographically secure random) to generate 8-12 character alphanumeric codes. Check for collisions in bulk: INSERT ... ON CONFLICT DO NOTHING, retry for conflicts. Store in DB with status=ACTIVE; import to Redis in batch for fast lookup. Coupon codes are case-insensitive: normalize to uppercase on input.

## Key Design Decisions

  - Redis atomic DECR prevents over-redemption without DB-level locking

  - UNIQUE constraint on (coupon_id, user_id) handles concurrent per-user limit checks

  - Cache coupon details in Redis (TTL=1min) to handle high lookup volume during flash sales

  - Soft delete coupon codes (status=DISABLED) — never hard delete for audit trail

Shopify system design interviews cover coupon and discount systems. See common questions for [Shopify interview: coupon and discount system design](https://www.techinterview.org/post/3233459924/shopify-interview/).

Amazon system design covers coupon and promotions at scale. Review design patterns for [Amazon interview: coupon and promotions system design](https://www.techinterview.org/post/3233460275/scale-ai-interview-guide-2026-data-infrastructure-rlhf-pipelines-and-ml-engineering/).

Stripe system design covers discount codes and payment flows. See design patterns for [Stripe interview: discount and payment system design](https://www.techinterview.org/post/3233460268/stripe-interview-guide-2026-process-bug-bash-round-and-payment-systems/).
