Caching And Cache Invalidation For Payment APIs
Asked of: Software Engineer
Last updated

What's being tested
This topic tests whether you can design a cache for read-heavy payment APIs without returning incorrect authorization, payment, or balance state. The interviewer is probing your understanding of cache invalidation, consistency guarantees, idempotency, failure handling, and distributed coordination—not merely whether you know Redis commands. Stripe cares because stale payment data can cause duplicate actions, incorrect merchant decisions, or customer-visible contradictions, so a strong Software Engineer makes correctness boundaries explicit before optimizing latency.
Core knowledge
-
Cache-aside is usually the safest default: read from
Redis, fetch from the source of truth on a miss, then populate the cache. Writes update the database first and invalidate afterward; never treat cache population as the durable write. -
Cache invalidation must be tied to every state transition, not only the primary update path. Payment objects may change through synchronous requests, webhook processing, retries, asynchronous workers, administrative tools, or reconciliation jobs.
-
Choose a consistency model explicitly: strong consistency for authorization or capture decisions, bounded staleness for dashboards, and eventual consistency for search-like views. A cache hit is acceptable only if its freshness matches the endpoint’s correctness requirement.
-
Use versioned values or monotonic timestamps to prevent an older asynchronous writer from overwriting newer data. A cached record can contain
version; accept an update only whenincoming_version >= cached_version. -
Delete-on-write is simpler than write-through for mutable payment state: commit the database transaction, then remove the key. If invalidation fails, a TTL limits damage, while a durable invalidation stream or retry queue improves recovery.
-
TTL is a safety net, not a correctness proof. If stale data is unacceptable for an operation, bypass the cache or re-read the authoritative store; randomize TTLs with jitter to avoid synchronized expiration and load spikes.
-
Prevent a cache stampede when a hot key expires: use request coalescing, a short distributed lock, probabilistic early refresh, or stale-while-revalidate. Locks require bounded leases and ownership checks so a delayed client cannot delete another client’s lock.
-
Negative caching can reduce repeated misses for nonexistent objects, but it must use short TTLs and careful invalidation. Otherwise, a newly created payment or customer can remain invisible until expiration.
-
Scope keys by tenant and authorization context, such as
account:{id}:payment:{payment_id}:v:{schema}. Never cache a response containing fields that differ by caller unless the key includes the relevant permission or the response is safely filtered. -
Idempotency keys protect repeated mutations; caches do not. A cached
POSTresponse must not be confused with durable idempotency storage, which needs atomic persistence, request-parameter validation, and a defined replay policy. -
Treat
Redisas an optimization, not the source of truth. During outages, decide whether to fail closed, serve stale reads, or bypass the cache based on endpoint semantics; monitor hit rate, origin load, stale-read indicators, eviction rate, andp99latency. -
In a multi-region deployment, distinguish replication lag from cache staleness. Region-local caches can show older state after a write elsewhere, so route read-after-write traffic to the writer, use version checks, or expose an explicit consistency token.
Worked example
Representative question: “Design a cache for retrieving PaymentIntent objects through a payment API.” In the first 30 seconds, I would clarify whether reads influence payment mutations, the required read-after-write behavior, the object size and traffic skew, tenant isolation, and whether updates arrive through webhooks or background workers. I would state an assumption: cache-aside reads are acceptable for dashboards, but mutation preconditions must read authoritative state. I would organize the answer around key design and authorization, read/write and invalidation flows, failure and stampede protection, and observability. I would use Redis for cache-aside reads, commit changes to the primary database first, then invalidate account:{id}:payment_intent:{id} with retries backed by a durable event or outbox. The explicit tradeoff is whether to delete immediately or write the new value: deletion avoids publishing a partially transformed object, while write-through can reduce misses but creates more ordering and failure cases. I would address concurrent updates with object versions and reject stale cache writes. If I had more time, I would specify multi-region behavior, load-test hot merchants, and define alerts for stale-read evidence and invalidation backlog.
A second angle
Representative question: “How would you cache a payment status endpoint while preventing stale authorization decisions?” The framing changes because the endpoint’s response may directly influence whether a capture, refund, or fulfillment action is allowed. I would permit cached data for display but require a conditional authoritative read for the mutation, using an object version or If-Match-style precondition to detect changes. The main challenge becomes separating presentation latency from correctness-critical state transitions, rather than maximizing the general cache hit rate. I would also discuss whether a short-lived “processing” state can be served stale while terminal states require stronger guarantees.
Common pitfalls
Pitfall: “Set a five-minute TTL and the problem is solved” is analytically insufficient; TTL bounds staleness but does not prevent an incorrect decision during those five minutes. Tie freshness to endpoint semantics and invalidate on every mutation path.
Pitfall: A candidate may describe only the happy path—database write followed by cache delete—without explaining invalidation failure, concurrent writers, worker retries, or regional lag. Strong communication names the failure modes and gives each one a concrete recovery or safety policy.
Pitfall: Saying “use a distributed lock” without lease expiry, ownership tokens, or a fallback path shows shallow depth. Explain how the lock prevents stampedes, how a crashed holder releases safely, and why the system remains correct if the lock service is unavailable.
Connections
An interviewer may pivot to idempotency, outbox patterns, optimistic concurrency control, webhook ordering, rate limiting, or multi-region replication. Be ready to distinguish caching from durable deduplication and to explain how database transactions and event delivery determine whether invalidation is reliable.
Further reading
-
Designing Data-Intensive Applications — chapters on replication, consistency, and derived data provide the foundation for reasoning about stale cached state.
-
Caching at Netflix: EVCache — a practical example of distributed caching, failure isolation, and operational tradeoffs.
-
Stripe: Idempotent Requests — useful for separating mutation safety from read caching and understanding replay semantics.