Low Level Design: Gift Card Service

What Is a Gift Card Service?

A gift card service handles the full lifecycle of stored-value cards: issuance, activation, balance tracking, redemption at checkout, partial use, expiry, and fraud controls. It is a common low level design interview topic because it touches financial ledgering, idempotency, concurrency, and security.

Functional Requirements

  • Issue a gift card with a specified value and optional expiry date.
  • Activate a card (physical cards require a separate activation step).
  • Check balance by card number and PIN.
  • Redeem an amount at checkout, supporting partial redemption.
  • Reload a card with additional funds.
  • Expire cards past their expiry date.
  • Block or void a card for fraud or customer service reasons.

Non-Functional Requirements

  • Idempotent redemption: duplicate checkout calls must not double-deduct.
  • Strong consistency for balance mutations.
  • Low latency balance reads (<50 ms p99).
  • Audit trail for every balance change.

Core Entities

GiftCard
  id            UUID PK
  card_number   VARCHAR(16) UNIQUE
  pin_hash      VARCHAR(64)
  status        ENUM('INACTIVE','ACTIVE','BLOCKED','EXPIRED','DEPLETED')
  currency      CHAR(3)
  issued_at     TIMESTAMP
  expires_at    TIMESTAMP NULL
  created_at    TIMESTAMP

LedgerEntry
  id            UUID PK
  card_id       UUID FK -> GiftCard
  txn_type      ENUM('ISSUE','RELOAD','REDEEM','REVERSE','EXPIRE')
  amount        DECIMAL(12,2)   -- positive = credit, negative = debit
  balance_after DECIMAL(12,2)
  idempotency_key VARCHAR(64) UNIQUE NULL
  order_id      VARCHAR(64) NULL
  created_at    TIMESTAMP

CardActivation
  card_id       UUID PK FK -> GiftCard
  activated_by  VARCHAR(64)
  activated_at  TIMESTAMP

Balance Ledger Design

Never store balance as a mutable column. Derive it by summing ledger entries, or maintain a cached balance updated inside a transaction alongside every ledger insert. The cached approach is preferred for read performance.

Every redemption call carries an idempotency_key (e.g., order ID + attempt number). The service inserts the ledger row with a UNIQUE constraint on that key. A duplicate call hits the constraint, returns the original result, and never debits twice.

Redemption Flow

  1. Validate card number + PIN; confirm status is ACTIVE.
  2. Check expiry: if expires_at < NOW(), transition status to EXPIRED, return error.
  3. Check idempotency key in LedgerEntry; if found, return cached result.
  4. Begin transaction: SELECT balance FOR UPDATE (or optimistic lock via version column).
  5. Verify balance >= requested_amount.
  6. Insert LedgerEntry (REDEEM, -amount, new_balance, idempotency_key).
  7. Update cached balance on GiftCard row.
  8. If new balance is 0, set status = DEPLETED.
  9. Commit; return authorized amount and remaining balance.

Partial Redemption

The checkout service passes requested_amount. If the card balance is less than requested, the service returns the available balance as the authorized amount. The caller is responsible for charging the remainder via another payment method. This split-tender pattern must be handled atomically on the caller side.

Expiry Enforcement

Two layers: (1) runtime check on every balance query or redemption call, (2) a nightly batch job that scans cards with expires_at < NOW() AND status = 'ACTIVE', inserts an EXPIRE ledger entry for the remaining balance, and sets status = EXPIRED. Regulations in some jurisdictions require dormancy fees or prohibit expiry — the service must expose a configurable policy hook.

Fraud Prevention

  • Rate-limit PIN check attempts per card (e.g., 5 failures in 10 minutes triggers a temporary lock).
  • Flag high-velocity redemptions from the same IP or device fingerprint.
  • Require re-authentication for reload operations above a threshold.
  • Immutable ledger: no UPDATE or DELETE on LedgerEntry rows; reversals create new REVERSE rows.
  • All card numbers and PINs transmitted and stored with encryption; card numbers tokenized in logs.

API Design

POST /gift-cards                        -- issue
POST /gift-cards/{id}/activate
GET  /gift-cards/{id}/balance           -- requires PIN header
POST /gift-cards/{id}/redeem            -- {amount, idempotency_key, order_id}
POST /gift-cards/{id}/reload            -- {amount}
POST /gift-cards/{id}/void              -- admin / CS only

Scalability Notes

  • Shard by card_id for horizontal scale; all ledger entries for a card live on the same shard, making balance reads cheap.
  • Cache hot card metadata (status, currency, expiry) in Redis with short TTL; balance must always be read from the DB inside a transaction.
  • For very high throughput (retail flash sale), use a Redis counter for optimistic pre-authorization, then reconcile with DB asynchronously — accept the complexity trade-off consciously.

Interview Tips

  • Lead with idempotency — interviewers want to see you handle duplicate payment calls first.
  • Discuss ledger vs. mutable balance and state your reasoning.
  • Mention the split-tender partial redemption contract between services.
  • Address expiry policy as a configurable concern, not a hardcoded rule.

Frequently Asked Questions

What is a gift card service architecture?

A gift card service is a stored-value system built around a ledger of issued and redeemed balances. Core components include a card issuance service (generates unique codes, stores initial value), a ledger service (records every credit and debit as immutable transactions), a redemption service (validates codes and applies debits), and a fraud detection layer. Cards are typically represented as accounts with a balance derived from summing all ledger entries rather than storing a mutable balance field directly, which ensures auditability and prevents silent corruption.

How do you prevent double-spending in gift card redemption?

Double-spending is prevented through optimistic locking combined with idempotency keys. When a redemption request arrives, the service reads the card’s current balance and records a pending debit with a unique transaction ID. The write is conditioned on the balance not having changed since it was read (compare-and-swap or a version column). If two concurrent requests race, only one succeeds; the other receives a conflict error and must retry or fail. Idempotency keys ensure that a client retrying a timed-out request doesn’t create a second debit for the same checkout. Distributed locks (Redis SETNX with TTL) can be layered on top for high-contention cards during flash sales.

How does partial redemption work in a ledger model?

In a ledger model, partial redemption is a standard debit entry for the purchase amount rather than the full card balance. The remaining balance is the sum of all credits minus all debits and is computed at read time. The redemption flow checks that the requested debit does not exceed the available balance, writes the debit entry atomically, and returns both the amount applied and the remaining balance to the caller. The merchant’s point-of-sale or checkout layer then charges any outstanding order total to a secondary payment method. Ledger entries are immutable; corrections are represented as compensating credit entries rather than mutations, which preserves the full audit trail.

How do you handle gift card fraud?

Gift card fraud takes several forms: bulk code scraping, account takeover followed by balance drain, and social-engineering scams. Defenses operate at multiple layers. Code generation uses cryptographically random identifiers long enough to make brute-force enumeration infeasible. Rate limiting on balance-check and redemption endpoints (per IP, per device fingerprint, per account) throttles scrapers. Velocity rules flag cards redeemed within seconds of issuance or from geographies inconsistent with the purchaser. High-value redemptions can be held for manual review or require re-authentication. Compromised cards are frozen by updating their status in the ledger service, and compensating credits can be issued to affected customers once fraud is confirmed.

See also: Shopify Interview Guide

See also: Stripe Interview Guide 2026: Process, Bug Bash Round, and Payment Systems

See also: Scale AI Interview Guide 2026: Data Infrastructure, RLHF Pipelines, and ML Engineering

Scroll to Top