Stripe Software Engineer Interview Prep Guide
Everything Stripe actually asks Software Engineer candidates — concept walkthroughs, worked examples, and the real interview questions, drawn from candidate reports. Free to read.
Last updated

Technical Screen
Coding & Algorithms
-
Stateful Stream Processing And Time Scheduling — covered in depth under Onsite below.
-
Graph Algorithms For Relations And Routing — covered in depth under Onsite below.
-
Money-Safe Financial Computation — covered in depth under Onsite below.
-
Load Balancing And Resource Lifecycle Simulation — covered in depth under Take-home Project below.
Data Manipulation (SQL/Python)

What's being tested
These exercises test data-shaping code: parsing semi-structured inputs, validating records, joining datasets, aggregating nested values, and producing deterministic output. Stripe interviewers are probing whether you can turn messy business data into correct, maintainable Python/SQL-style transformations with clear edge-case handling.
Patterns & templates
-
Hash join for CSV-style joins — build
dict[key] -> list[rows], then emit left rows with all matches;O(n + m + output)time. -
Stable sorting for deterministic output — use
sorted(rows, key=lambda r: (...)); explicitly define tie-breakers instead of relying on incidental input order. -
Validation pipeline — parse, normalize, validate, compute, serialize; keep errors structured as
{field, message, path}and filterNone/ empty messages. -
Nested aggregation — flatten recursive lists/dicts with DFS or stack; preserve sequence order when serializing validation failures.
-
Timezone-aware schedule expansion — use
datetime,zoneinfo, and locale formatting; distinguish recurring-rule expansion from notification rendering. -
String/bitmap rendering — preallocate row buffers or collect chars in lists, then
''.join(...); avoid repeated string concatenation in loops. -
Numeric robustness — use
Decimalfor money-like costs, validate missing/negative/invalid quantities, and separate rounding policy from computation.
Common pitfalls
Pitfall: Treating joins as one-to-one when keys can have multiple matches; output cardinality may exceed either input size.
Pitfall: Mixing parsing, validation, and business logic in one loop; this makes edge cases hard to test and debug.
Pitfall: Producing nondeterministic output because
dictiteration, duplicate keys, or unsorted errors are not explicitly ordered.
Practice these
The practice cards below cover the canonical variants — solve all of them and time yourself.
Practice questions
System Design
-
Distributed System Design For Ledgers And Counters — covered in depth under Onsite below.
-
API Integration And External Service Design — covered in depth under Onsite below.
Onsite
Coding & Algorithms

What's being tested
These problems test stateful stream processing: applying events in deterministic time order while maintaining per-entity state such as balances, locks, fraud counters, schedules, or notification queues. Interviewers look for clean data structures, explicit ordering rules, and edge-case handling around time, retries, conflicts, and mutations.
Patterns & templates
-
Sort-then-scan event streams —
events.sort(key=(ts, tie_breaker)), then single pass; usuallyO(n log n)time,O(k)state. -
Per-key state maps — use
dict[(account_id, currency)] -> balanceordict[user_id] -> schedule; initialize defaults carefully. -
Priority queue scheduler —
heapqby(next_run_at, stable_id)for due jobs; push updated recurrence after processing. -
Interval / TTL rules — store active rules by
start <= ts < end; expire with min-heaps or ordered scans to avoid stale decisions. -
LRU eviction — combine
dictplus doubly linked list orOrderedDict;get,put, and eviction areO(1). -
Deterministic conflict resolution — define tie-breakers for same timestamp: cancellation before creation, rule update before auth, rejection before overdraft.
-
Timezone-safe scheduling — convert user-local wall time with
zoneinfo; store canonical UTC instants; handle DST gaps and duplicated hours explicitly.
Common pitfalls
Pitfall: Processing input order as truth instead of sorting by timestamp produces wrong balances, fraud decisions, and email order.
Pitfall: Treating recurring schedules as precomputed infinite lists can explode memory; generate the next occurrence lazily.
Pitfall: Ignoring idempotency or duplicate event IDs leads to double-charged balances, duplicate notifications, or repeated lock acquisition.
Practice these
The practice cards below cover the canonical variants — solve all of them and time yourself.
Practice questions

What's being tested
You’re being tested on graph modeling: turning relations like similarity, exchange rates, or roads into nodes, edges, weights, and traversal rules. Interviewers look for correct algorithm choice, clean data structures, edge-case handling, and clear complexity reasoning.
Patterns & templates
-
Adjacency list with
`dict[node] -> list[(neighbor, weight)]`— best default for sparse graphs; build inO(E)space. -
DFS/BFS traversal for connected components or reachability —
O(V+E)time; trackvisitedbefore enqueueing to avoid cycles. -
Weighted path accumulation for ratios/conversions — multiply edge weights along a path; add reciprocal edges for bidirectional rates.
-
Dijkstra’s algorithm for nonnegative route costs —
O((V+E) log V)withheapq; don’t use plain BFS on weighted edges. -
Topological sort for DAG dependency chains —
O(V+E)using indegree queue; detect cycles when processed count< V. -
Union-Find for grouping linked records — near-constant amortized
find()/union(); useful when edges imply equivalence components. -
Consistency checking in weighted graphs — compare implied versus supplied ratios with epsilon tolerance; floating-point equality is unsafe.
Common pitfalls
Pitfall: Treating every graph as unweighted; bicycle routes and conversion rates require preserving edge costs or multiplicative weights.
Pitfall: Forgetting disconnected components; queries may involve two nodes with no valid path.
Pitfall: Overengineering dynamic updates; first solve the static graph correctly, then discuss incremental rebuilds or cached components.
Practice these
The practice cards below cover the canonical variants — solve all of them and time yourself.
Practice questions

What's being tested
These problems test money-safe stateful computation: applying ordered events, pricing rules, validation, and aggregation without floating-point surprises. Interviewers look for clean data modeling, deterministic edge-case handling, and fixed-point arithmetic that preserves cents, currencies, and balances.
Patterns & templates
-
Fixed-point integer arithmetic — store money in minor units like cents; compute
fee = amount * bps // 10000with explicit rounding policy. -
Composite-key maps — use
(account_id, currency),(country, payment_method), or(item_type, tier)as dictionary keys; expectO(1)lookup. -
Sort-then-apply event processing — sort by
timestampplus stable tie-breaker; update balances sequentially inO(n log n)time. -
Configuration-driven calculators — encode tiers, discounts, tax, and fee rules as data; keep calculation logic generic and testable.
-
Boundary-safe tier loops — calculate
units_in_tier = min(remaining, tier_limit - prev_limit); watch inclusive vs exclusive thresholds. -
Validation-first pipelines — reject missing currency, negative quantity, unknown rate, malformed account, or unsupported tier before mutating state.
-
Deterministic output ordering — sort results by account, currency, item name, or timestamp as specified; never rely on dictionary iteration.
Common pitfalls
Pitfall: Using
floatfor prices, tax, or fees; binary rounding errors can produce incorrect cents and flaky tests.
Pitfall: Aggregating before validation; invalid transactions must not partially update balances, totals, or platform overdraft coverage.
Pitfall: Treating all currencies as interchangeable; balances, fees, and totals usually aggregate per currency unless conversion rates are explicitly provided.
Practice these
The practice cards below cover the canonical variants — solve all of them and time yourself.
Practice questions
Software Engineering Fundamentals

What's being tested
Interviewers are probing production-minded debugging: can you turn a vague failure into a bounded hypothesis, inspect the right layer, fix the root cause, and prevent recurrence? The recurring skills are input validation, error normalization, deterministic behavior, and framework-aware debugging across backend-style data transformations and frontend DOM behavior. Stripe cares because seemingly small validation bugs can create incorrect charges, confusing merchant integrations, broken compliance flows, or support-heavy edge cases. A strong Software Engineer answer shows not only “here is the bug,” but also “here is the invariant, the test that catches it, the observability I would add, and the failure mode I am intentionally handling.”
Core knowledge
-
Reproduction first beats speculative fixing. Start with the smallest failing input, expected output, actual output, environment details, and whether the issue is deterministic. For UI bugs, capture browser, framework version, server-rendered HTML, hydrated DOM, and user interaction path.
-
Validation invariants should be explicit and testable: required fields are present, types are correct, values are within domain bounds, and output shape is stable. For cost computation, examples include
quantity >= 0,unit_priceis finite, and totals avoidNaN/Infinity. -
Error normalization converts heterogeneous failures into a consistent schema, such as
{ path, code, message }. Nested validators often emit arrays, maps, exceptions, or nullable messages; normalize before aggregation so rendering, logging, and tests do not depend on library internals. -
Tree traversal is the common algorithm behind nested validation aggregation. Use DFS or BFS over objects/arrays, carry the current
path, and filter invalid leaves. Runtime should be over validation nodes, with stack space for depthdin recursive implementations. -
Deterministic serialization matters for tests, logs, and client-visible errors. Sort by stable keys such as
path,field_order, or insertion index; avoid depending on unspecified object iteration across runtimes. Determinism turns flaky failures into reproducible failures. -
Numeric robustness is part of error handling, not a polish detail. For money-like computations, avoid binary floating point where precision matters; use integer minor units or
Decimal. Check rounding policy, negative values, overflow, missing discounts, and stable sorting tie-breakers. -
Client-side validation improves UX but is not authoritative. A passport form can validate date format, required fields, pattern constraints, and accessibility state in the browser, but server-side validation must enforce the same security and business rules before persistence or payment.
-
DOM attributes vs properties are a common frontend debugging trap. In
React,classNamemaps to theclassattribute, boolean attributes may reflect differently, andvalueas a property can diverge fromgetAttribute("value"). Inspect both rendered HTML and live DOM state. -
SSR/hydration mismatches require layer-by-layer isolation. Compare server output, client bundle behavior, framework compile output, and post-hydration DOM. A bug may come from template compilation, prop casing, build transforms, browser normalization, or code that mutates DOM after render.
-
Observability should be proportional and privacy-aware. Log validation error codes, field paths, request IDs, version/build SHA, and counts, not raw passport numbers or sensitive user data. Use metrics like validation failure rate, top error code, and frontend exception count.
-
Testing strategy should include unit, property, integration, and regression tests. Unit tests cover edge cases; property tests generate malformed inputs; integration tests verify schema-to-UI behavior; regression tests lock the exact bug so the fix cannot silently revert.
Worked example
For Debug Validation Error Aggregation, a strong candidate would first clarify the expected output contract: should empty strings be included, how should nested paths be represented, and must ordering be stable across runs? They would ask for one failing input and actual output, then declare assumptions such as “I will treat null, undefined, and whitespace-only messages as non-errors unless the product contract says otherwise.” The answer should be organized around four pillars: reproduce with a minimal nested validation object, inspect the aggregator’s traversal logic, normalize/filter messages consistently, and add deterministic serialization plus regression tests.
The likely implementation shape is a recursive or stack-based traversal that carries path, recognizes arrays and objects, and emits only valid error leaves. The candidate should call out that filtering before flattening can be wrong if a parent object has no message but contains children with messages. A specific tradeoff is recursion simplicity versus stack safety: recursion is readable for typical form schemas, but an iterative stack is safer if untrusted or deeply nested schemas can exceed call-stack limits. They should also mention stable ordering: preserve schema order if user-facing, or sort by canonical path if test/log stability matters more. They would close with prevention: add unit cases for null, empty arrays, duplicate paths, mixed nested arrays/objects, and whitespace-only messages, then instrument aggregate error counts by code without logging sensitive field values. If more time remained, they could add property-based tests to generate arbitrary nested error shapes and assert no empty messages appear in output.
A second angle
For Debug wrong DOM attributes in unknown framework, the same debugging discipline applies, but the failure boundary shifts from data structure traversal to rendering layers. A strong candidate would not immediately blame the browser or framework; they would compare source component code, compiled output, server-rendered markup, hydrated DOM, and live properties inspected via element.getAttribute(...) and element.propertyName. The key invariant becomes “the semantic state represented by the component is reflected correctly in the accessible DOM,” not just “the string in HTML looks right.” The tradeoff is whether to use the framework’s idiomatic prop API or force raw attributes; idiomatic props are usually safer, but custom elements and accessibility attributes like aria-* may require exact attribute behavior. The prevention pattern is similar: create a minimal reproduction, add framework-specific regression tests, and verify behavior in the browser rather than relying only on snapshot strings.
Common pitfalls
Pitfall: Treating validation as a set of
ifstatements instead of a contract.
The tempting answer is “just skip null messages” or “just add another regex.” That misses the deeper issue: define the accepted input domain, normalized error schema, ordering guarantee, and ownership between client and server validation.
Pitfall: Debugging from the middle of the stack.
A weak communication pattern is jumping straight into code changes without saying how you would reproduce and isolate the failure. A better answer narrates the layers: input, transformation, framework/library behavior, output, logs/tests, then the smallest fix that restores the invariant.
Pitfall: Ignoring user-facing and operational consequences.
For Stripe-style systems, “the code passes the sample” is not enough. Mention how bad errors surface to users, whether sensitive data could leak in logs, how you would monitor the fix, and which regression tests would prevent recurrence.
Connections
Interviewers may pivot from this topic into API design, especially how to return stable error codes and field paths to clients. They may also ask about idempotency, observability, frontend accessibility, or distributed debugging using request IDs and structured logs. For coding-heavy variants, expect edge cases around sorting stability, precision, malformed input, and time/space complexity.
Further reading
-
Google SRE Book, “Monitoring Distributed Systems” — useful framing for symptoms, signals, and production debugging discipline.
-
MDN: HTML attribute reference — grounding for how browser attributes behave versus framework abstractions.
-
React DOM Elements — concrete examples of prop/attribute naming, boolean attributes, and hydration-related behavior.
Practice questions
System Design

What's being tested
Stripe-style system design for a Software Engineer probes whether you can build systems where money-like state and high-volume event-derived state have different correctness requirements. A ledger demands strong consistency, idempotency, auditability, and clear failure semantics; an activity counter often accepts bounded staleness but must handle scale, hot keys, deduplication, and time-windowed aggregation. The interviewer is looking for crisp separation of invariants: what must be linearizable, what can be eventually consistent, and how you recover after retries, crashes, and external dependency failures. Stripe cares because payments infrastructure frequently combines durable financial records with operational counters, limits, fraud signals, and integrations with third-party services.
Core knowledge
-
Ledger systems should be modeled as append-only immutable entries, not mutable balances. Store debits and credits as journal lines with a transaction id, account id, currency, amount, and timestamp; derive balance as , optionally materialized for speed.
-
Double-entry accounting is the core invariant for financial movement: every transaction must balance, typically in a single currency and ledger domain. Enforce this inside one database transaction or equivalent consensus-backed write path.
-
Linearizability matters for operations like “reserve funds,” “capture payment,” or “prevent overdraft.” If two concurrent writes can both observe the same prior balance, you need serializable isolation, conditional writes, row locks, or a consensus store such as
Spanner,FoundationDB, or carefully configuredPostgres. -
Idempotency keys turn client or worker retries into safe operations. Persist
(idempotency_key, operation_type, request_hash, response/result)with a unique constraint; if the same key appears with a different payload, return a conflict rather than silently creating a second ledger movement. -
Outbox pattern is safer than “write database, then publish event.” In the same transaction as the ledger write, insert an outbox row; a relay later publishes to
Kafka,SQS, orPub/Sub. Consumers deduplicate by event id, giving at-least-once delivery without losing ledger facts. -
Distributed transactions should be avoided across internal ledger state and external services. If integrating with a routing, bank, or card-network API, use a state machine:
PENDING → CONFIRMEDorPENDING → FAILED, plus retries, reconciliation jobs, and compensating entries instead of pretending two-phase commit exists across the internet. -
Activity counters are usually derived views over events, not source-of-truth records. A robust design ingests events, deduplicates by event id, partitions by entity and time bucket, and stores aggregates like
(counter_id, bucket_start, granularity, count)inRedis,DynamoDB,Cassandra, orBigtable. -
Tumbling windows use fixed buckets such as one row per minute: bucket = . Sliding windows are computed by summing recent smaller buckets, e.g. last 5 minutes = five 1-minute buckets, trading read amplification for simple writes.
-
Hot-key sharding is necessary when one merchant, location, or activity becomes extremely popular. Write to shards like
(counter_id, bucket, shard_id)whereshard_id = hash(event_id) % S; reads sum acrossSshards. IncreaseSwhen per-key QPS exceeds a partition’s safe write rate. -
Deduplication for counters is bounded by the time horizon. Use a durable event-id table for strict correctness, or a
RedisSET/Bloom filter with TTL for near-real-time counters. Bloom filters reduce memory but introduce false positives, undercounting by roughly the configured false-positive rate. -
Consistency tradeoffs should be explicit. A dashboard counter can tolerate seconds of lag and eventual convergence; an authorization limit or ledger balance usually cannot. Name the SLA: for example, “counter visible within 5 seconds, exact after backfill,” versus “ledger write committed once and visible immediately.”
-
Observability and reconciliation are part of the design, not afterthoughts. Track ingestion lag, dedup hit rate, dropped events, outbox backlog, ledger imbalance count, and reconciliation mismatches. For ledgers, a daily job should recompute balances from entries and alert on any non-zero imbalance.
Worked example
For Design ledger and bikemap integration, a strong candidate should first clarify the invariant: “Is the ledger the source of truth for billable activity, and is the external bikemap service authoritative only for route distance or pricing inputs?” Then declare assumptions: ledger writes must be strongly consistent and auditable; bikemap calls may fail, time out, or return changed routes; users may retry requests. Organize the answer around four pillars: data model, write path, external integration workflow, and reconciliation/observability.
The data model should separate immutable ledger entries from trip or route metadata: a trips table can hold route state, while a ledger_entries table records balanced debits and credits with an idempotency key. The write path should avoid a distributed transaction between the ledger database and bikemap; instead, create a PENDING_ROUTE or PENDING_CHARGE state, call the external service via an async worker, then commit a balanced ledger transaction when the required data is available. A specific tradeoff to flag is synchronous versus asynchronous integration: synchronous gives lower latency for the user if bikemap is healthy, but asynchronous state transitions are more reliable under timeouts and retries. If the external service returns different results on retry, store the request parameters and versioned response used for billing so the ledger remains explainable. Close by saying that, with more time, you would add reconciliation jobs, webhook replay handling if the service is event-driven, and security controls such as signed requests, scoped credentials, and audit logs.
A second angle
For Design a local activity counter service, the same discipline applies, but the correctness bar moves from financial invariants to bounded error and freshness. Instead of designing a serializable double-entry write path, frame the system as event ingestion, deduplication, bucketed aggregation, hot-key mitigation, and query serving. The interviewer may push on tumbling versus sliding windows, so explain that one-minute buckets can serve both hourly tumbling counts and “last 15 minutes” sliding counts by summing recent buckets. Idempotency still matters, but duplicate events affect counts rather than money movement, so you can choose between exact dedup storage and TTL-based approximate dedup depending on SLA. The key transfer is knowing which state is authoritative and which state is a derived, eventually consistent view.
Common pitfalls
Pitfall: Treating counters and ledgers as the same consistency problem.
A tempting answer is “put all events in Kafka and aggregate later,” but that is not sufficient for financial correctness. For a ledger, the committed database record is the source of truth; streams and counters are downstream projections, not the authority for whether money moved.
Pitfall: Hand-waving idempotency as “we’ll retry safely.”
Retries are only safe if the system can recognize the same logical operation after a client timeout, worker crash, or duplicate message. A stronger answer names the unique key, where it is stored, how payload mismatches are handled, and whether the prior response is replayed to the caller.
Pitfall: Over-indexing on technology before invariants.
Jumping straight to Kafka, Redis, and Cassandra can sound scalable but shallow. Start with invariants and access patterns: exact balance checks, append-only audit trails, write QPS, read freshness, window sizes, and hot keys; then choose storage and queues that support those constraints.
Connections
Interviewers often pivot from this area into event sourcing, CQRS, rate limiting, distributed locking, stream processing, and database isolation levels. Be ready to compare Postgres serializable transactions with consensus-backed stores, and to explain when approximate structures like Count-Min Sketch or Bloom filters are acceptable.
Further reading
-
Designing Data-Intensive Applications — especially chapters on transactions, replication, stream processing, and derived data systems.
-
Google Spanner paper — useful for understanding externally consistent distributed transactions and why global linearizability is expensive.
-
Stripe API idempotent requests — concrete example of production-grade idempotency semantics for retried API operations.
Practice questions
What's being tested
Stripe-style integration design tests whether you can build correct internal state while depending on unreliable external APIs. The interviewer is probing for choices around consistency, idempotency, failure isolation, schema boundaries, and API contracts, not just whether you can draw boxes. For a Software Engineer, the core skill is separating what must be strongly correct inside your system, such as a ledger mutation, from what can be retried, cached, degraded, or reconciled when an external service fails. Stripe cares because payment systems routinely integrate with banks, networks, risk providers, tax engines, maps, schedulers, and notification vendors where duplicate calls, partial failures, and stale data can directly affect money movement or user trust.
Core knowledge
-
Idempotency keys are mandatory for any operation that may be retried after timeout, connection reset, client crash, or
5xx. Store{idempotency_key, request_hash, response, status}with a uniqueness constraint; if the same key arrives with a different payload, return409 Conflict. -
Strong consistency should be scoped narrowly to the system of record. For financial flows, keep double-entry ledger writes in
`Postgres`or another transactional store usingSERIALIZABLEisolation, row-level locks, or append-only journal entries; do not couple correctness to an external routing or mapping API. -
Double-entry accounting models every movement as balanced debits and credits: . Per transaction, enforce this invariant at write time. Append-only entries plus derived balances are safer than mutable balance rows alone, because they support audit, replay, and reconciliation.
-
External service calls should usually sit outside database transactions. Holding a transaction open while calling
BikeMapor a notification provider risks lock contention, transaction timeouts, and ambiguous commits. Prefer reserve/commit state machines, outbox pattern, or asynchronous workers. -
Outbox pattern means writing the internal state change and an outbound task in the same local transaction, then having a worker deliver the external call. This avoids the “database committed but API call never happened” gap without requiring distributed transactions across systems.
-
Retry policy needs bounded exponential backoff with jitter; for example,
delay = min(base * 2^attempt, max_delay) + random_jitter. Retry429,500,502,503, and network timeouts; do not blindly retry semantic errors like400,401, or validation failures. -
Timeouts and circuit breakers protect your service from dependency collapse. Set client timeouts below your own
`p99`latency budget, cap concurrent calls with bulkheads, and open a circuit after sustained failures so requests degrade quickly instead of exhausting threads or connection pools. -
API contract design should distinguish canonical internal models from provider-specific DTOs. Keep a translation layer around
BikeMap,Twilio,SendGrid, or calendar APIs so provider fields, error codes, pagination, and version changes do not leak throughout your domain model. -
Consistency models must be explicit. A user-facing route estimate can be eventually consistent or cached with a TTL, while a ledger entry must be linearizable or at least serializable within an account. Stronger consistency increases latency and coordination cost, so apply it only where invariants demand it.
-
Calendar and schedule integration requires precise time semantics. Store instants in
UTC, preserve the user’s IANA timezone likeAmerica/Los_Angeles, and expand recurring rules usingRFC 5545semantics. Daylight saving transitions create nonexistent or duplicated local times that must be defined. -
Conflict resolution should be deterministic and explainable. For notifications, conflicts may be handled by priority, quiet hours, deduplication window, or “latest user preference wins.” For money movement, avoid “last write wins”; use optimistic concurrency with version checks or append-only commands.
-
Capacity planning should be back-of-the-envelope and tied to bottlenecks. If users each have schedules and generate reminders/day, notification volume is approximately QPS on average, with spikes around local morning hours requiring queue smoothing.
Worked example
For Design ledger and bikemap integration, a strong candidate first clarifies the domain boundary: “Is the ledger authoritative for payments or balances, and is BikeMap only used to compute route pricing, ETA, or validation?” They should also ask whether route data can be stale, whether prices are quoted before ledger commit, and what happens if the map provider is unavailable. A clean answer can be organized around four pillars: the ledger data model, the external integration boundary, the transaction/state machine, and failure handling.
The ledger design should be append-only, double-entry, and backed by a transactional store such as `Postgres`, with unique idempotency keys per client request. The BikeMap call should be wrapped behind an internal RouteService adapter that normalizes provider responses, applies timeouts, caches route estimates when allowed, and records provider request IDs for debugging. The key tradeoff to flag is whether to call BikeMap synchronously before ledger commit or asynchronously after: synchronous gives immediate pricing validation but adds latency and dependency risk, while asynchronous improves resilience but requires quote reservation or later adjustment. A robust design often computes or validates the route before creating a pending ledger transaction, then commits only the balanced ledger entries under a local transaction. If the provider times out after the client retries, idempotency ensures the same request does not create duplicate ledger movements. To close, say that with more time you would add reconciliation jobs, audit tooling, provider failover strategy, and integration tests with fault injection for timeout, duplicate response, and stale route scenarios.
A second angle
For Generate user notifications from schedules, the same integration principles apply, but the correctness boundary shifts from financial invariants to time, preference, and delivery semantics. The internal scheduler should decide what notification is due based on user profile, timezone, locale, recurrence rules, and quiet hours before calling an external push, email, or SMS provider. Unlike a ledger, duplicate delivery may be tolerable only within strict deduplication windows, so idempotency keys should be based on {user_id, schedule_occurrence_id, channel}. The external provider call belongs behind an adapter with retries, rate-limit handling, and delivery status mapping. The tricky design questions are around daylight saving time, recurring event expansion, user preference changes between scheduling and send time, and whether the system promises “exactly once” delivery or more realistically “at least once with deduplication.”
Common pitfalls
Pitfall: Treating external APIs as if they are reliable local function calls.
A tempting answer is “call BikeMap, then write the ledger, then return success,” without discussing timeouts, retries, or ambiguous outcomes. A stronger answer names the failure matrix: provider call succeeds but response is lost, database commit succeeds but worker crashes, client retries after timeout, and provider returns inconsistent errors.
Pitfall: Overusing distributed transactions.
Candidates sometimes propose two-phase commit across your database and the external service. That is usually impractical because most third-party APIs do not participate in 2PC, and even when possible it harms availability. Prefer local transactions plus idempotent APIs, outbox, sagas, reconciliation, and explicit pending/committed/failed states.
Pitfall: Ignoring domain-specific edge cases.
For notifications, saying “store the timestamp and send at that time” misses timezone, locale, recurrence, DST, and user preference updates. For ledgers, saying “update the balance” misses append-only auditability, balanced entries, concurrency control, and duplicate request protection. Interviewers reward candidates who surface these edge cases before being prompted.
Connections
Interviewers may pivot from this topic into distributed transactions, event-driven architecture, rate limiting, webhook design, or database isolation levels. For Stripe specifically, also be ready to discuss idempotent API design, ledger reconciliation, API versioning, and observability through structured logs, correlation IDs, metrics, and traces.
Further reading
-
Stripe API Idempotent Requests — practical reference for request replay safety and idempotency-key behavior.
-
Designing Data-Intensive Applications — strong foundation for consistency, transactions, replication, and fault tolerance tradeoffs.
-
RFC 5545: Internet Calendaring and Scheduling Core Object Specification — canonical reference for recurrence rules and calendar edge cases.
Practice questions
Take-home Project
Coding & Algorithms

What's being tested
These prompts test checksum implementation, string validation, and bounded combinatorial search around payment-card numbers. Interviewers look for clean isValidLuhn, brand/network rule handling, wildcard completion, and single-digit recovery without brute-forcing unnecessarily.
Patterns & templates
-
Luhn checksum — scan right-to-left, double every second digit, subtract
9if over9; valid whensum % 10 == 0. -
Check digit derivation — compute partial sum excluding final digit, then
check = (10 - partial % 10) % 10; avoid trialing0..9. -
Network validation — model card brands as
{name, lengths, prefixes}; validate digits, length, prefix, then checksum in a predictable order. -
Wildcard enumeration — for small
?counts, DFS over digits; for larger counts, use modulo-DP over positions with statesum_mod_10. -
Counting completions — dynamic program
dp[i][mod]inO(n * 10 * choices)time andO(10)space; apply brand constraints first. -
Single-error correction — try replacing each digit with
0..9except itself, then re-run format and checksum; complexityO(n * 10 * n)naïvely, reducible with precomputed contributions. -
Input hygiene — normalize spaces/dashes only if allowed; otherwise reject non-digits early and keep leading zeros meaningful.
Common pitfalls
Pitfall: Doubling parity is based on distance from the right, not absolute index; parity changes when length changes.
Pitfall: Passing Luhn alone is not enough; a number can satisfy the checksum but fail brand prefix or length rules.
Pitfall: Wildcard brute force explodes at
10^k; switch to modulo counting whenkis more than a few digits.
Practice these
The practice cards below cover the canonical variants — solve all of them and time yourself.
Practice questions

What's being tested
These problems test stateful simulation with deterministic load-balancing behavior: routing, locking, lifecycle transitions, eviction, and shutdown handling. Interviewers are probing whether you can turn ambiguous product rules into clean data structures, preserve invariants, and handle edge cases without overcomplicating the code.
Patterns & templates
-
Entity state maps — use
dict[id] -> statefor connections, accounts, or targets; most operations should beO(1)average time. -
Round-robin pointer — maintain
next_index; after choosing a target, advance modulon, skipping unavailable or full targets carefully. -
Capacity-aware routing — track
load[target]and reject or reroute whenload[target] == capacity[target]; define deterministic tie-breaking upfront. -
Sticky assignment — keep
connection_id -> target; duplicateconnectshould usually return existing assignment, not consume capacity again. -
Lifecycle transitions — model
connect,disconnect,shutdown,lock,unlock, andevictas explicit state changes with invariant checks. -
LRU cache template — combine
dictplus doubly linked list orOrderedDict;get/put/evict areO(1). -
Ordered rerouting on shutdown — collect affected connections in stable order, free old capacity, then reassign deterministically to avoid hidden ordering bugs.
Common pitfalls
Pitfall: Treating duplicate connects as new connections, which silently inflates load and breaks capacity invariants.
Pitfall: Updating the round-robin pointer on failed assignment; clarify whether failed attempts should advance before coding.
Pitfall: Handling shutdown by deleting a server first, then losing the list or order of connections that must be rerouted.
Practice these
The practice cards below cover the canonical variants — solve all of them and time yourself.
Practice questions