CASE STUDY

Virtual Credit Card Service (Capital One)

4 min read·770 words·Intermediate

Asked at

2 candidate reports between Dec 2025 and Feb 2026

How to use this case study

SDE-2 / Mid

Explain what a virtual card is, how it links to the real account, and the rules checked when a transaction arrives (status, limit, merchant lock, expiry).

SDE-3 / Senior

Go deeper on the real-time authorization path and its latency budget, tokenization, decoding card IDs, and geography-aware rules.

Staff / Principal

Discuss PCI scope, fraud signals, high availability of authorization, and the product trade-offs for users vs the bank.


0) Problem Restatement

A virtual card is a separate card number (with its own expiry and CVV) linked to a customer's real credit card account. Customers create them for online shopping: e.g., single-use cards, cards locked to one merchant (only Netflix can charge it), or cards with a spending limit. If a merchant is hacked, only the virtual number leaks, and the customer can close it without replacing their real card.

Capital One asked two parts: (1) product reasoning, meaning benefits and drawbacks for users and the bank, and (2) transaction validation: when a charge arrives with an encoded virtual card ID, decide approve or decline in real time. A related question added geography-aware rules.


1) Product Reasoning (say this briefly)

  • For users: safer online shopping, easy cancellation, spending control, and fewer real-card reissues.
  • Drawbacks for users: extra steps, and problems with merchants that need the physical card at pickup (hotels, rentals) or recurring charges tied to a single-use card.
  • For the bank: lower fraud losses and reissue costs, more engagement, and data on merchant subscriptions.
  • Costs for the bank: more complex authorization, more card numbers to manage, and support calls when a locked card is declined.


2) Requirements

  • Create virtual cards with rules: single-use / multi-use, merchant lock (set on first use or chosen up front), spending limit (per transaction or monthly), expiry, and allowed countries.
  • Pause, resume or close a card.
  • Authorize each transaction in real time (under ~100 ms of our budget inside the card network's time limit).
  • Every decision is logged and explainable.


3) Architecture

Architecture Diagram

flowchart LR
    NET["Card network - auth request"] --> AUTH["Authorization Service"]
    AUTH --> VAULT["Token vault - decode virtual PAN"]
    AUTH --> VC[("Virtual cards + rules - cached")]
    AUTH --> ACC["Core account - available credit"]
    AUTH --> FR["Fraud scoring"]
    AUTH -->|"approve / decline + reason"| NET
    AUTH --> LOG[("Decision log")]
    APP["Customer app"] --> MGMT["Card Management API"]
    MGMT --> VC
    MGMT --> VAULT
  • Token vault: maps the virtual card number (PAN) to virtual_card_id and the real account. Card numbers live only here (a small PCI scope). The encoded ID in the request is decoded or looked up here.
  • Virtual card rules are cached in memory in the authorization service for speed, and invalidated on change.
  • Core account service: the real available credit, with holds placed on approval.


4) Validation Rules (in order, fail fast)

  1. Decode and look up the card. Unknown → decline "invalid card".
  2. Status: closed or paused → decline.
  3. Expiry and CVV match.
  4. Single-use: already used → decline.
  5. Merchant lock: if locked, the merchant ID must match. If "lock on first use" and not yet locked, lock it to this merchant atomically (so two first charges can't both lock).
  6. Limits: amount ≤ per-transaction limit, and monthly spent + amount ≤ monthly limit.
  7. Geography: the merchant's country is in the allowed list (and optionally matches the customer's recent location or travel notice).
  8. Real account: available credit ≥ amount → place a hold.
  9. Fraud score below a threshold, or step-up (send the customer a confirmation).
  10. Approve: record the decision, update counters (spent, used flag), and return the approval code.

Each decline returns a specific reason code for the network and the customer's app ("Declined: card locked to another merchant").


5) Concurrency and Reliability

  • Two charges at the same time on a single-use card: use a conditional update (SET used = true WHERE id = ? AND used = false). Only one succeeds.
  • Monthly spend counters are updated atomically alongside the hold.
  • Idempotency: networks retry authorization messages, so decisions are keyed by the network's transaction ID, and a retry returns the same answer.
  • High availability: multi-region active-active authorization with replicated card rules. If the core account system is slow, card networks allow stand-in decisions with conservative limits.


6) Trade-offs & Alternatives

DecisionChoiceWhyAlternative
Card dataSeparate vault (tokenization)Small PCI scope, saferStore PANs everywhere: huge compliance risk
Rule checksIn-memory cached rules, fail fastMeets network latencyDB queries per check: slow
First-use lockAtomic conditional updateNo double locksRead-then-write: race
RetriesIdempotent by network transaction IDSame answer on retryNew decision each time: double holds

7) Wrap-Up

Virtual cards give customers safer, controllable card numbers linked to one real account, with lower fraud costs for the bank. Authorize each transaction by decoding the card through a token vault, then checking cached rules in a fail-fast order: status, expiry, single-use, merchant lock, limits, geography, available credit and fraud. Use atomic conditional updates for single-use and first-use locks, idempotency by network transaction ID, and explainable decline reasons.

More Case Studies

Practice with a Mock Interview

Apply what you learned in a live system design mock interview with our AI interviewer.

Start System Design Interview →