cswork / libraryOpen practice workspace

Interview guides · Cardless

Cardless Software Engineer Interview Guide

Cardless Software Engineer interview guide: three reported rounds, ledger and webhook design, rate limiter coding, behavioral prompts, 7-day plan.

The 60-second brief

Candidates describe Cardless as a company that builds the software behind credit card programs run for consumer brands, along with other financial products tied to those brands. The engineering work sits on APIs, microservices and ledgers that handle card onboarding, transaction processing and rewards, plus integrations with external banking partners. For a Software Engineer, candidates describe a backend role: build and maintain those services, review code, scope features with product managers, set up monitoring and alerts, take part in on-call, and keep partner integrations in line with industry standards such as PCI-DSS.

This guide is for candidates applying for the Software Engineer role at Cardless, especially those with a backend background. It covers the three reported rounds, the coding, system design and behavioral questions candidates report, and the stack candidates describe for the role (Go, Java or Python, SQL databases, REST or gRPC APIs, message queues). It does not cover pay, and it does not assume prior fintech experience.

Candidates report three rounds over roughly 3-5 weeks: an HR Screening Call, a Technical Phone Screen built around a pragmatic coding challenge, and an Interview Loop that combines system design, a conversation with colleagues from other departments, and a culture discussion with senior leadership.

Focus areas

  • System Design
  • Scalability
  • Backend Engineering

Overview

The work candidates describe is backend engineering where money is involved: card onboarding, transaction processing, rewards and ledgers, with partner integrations alongside. Reported themes are data consistency, high-throughput transaction processing and regulatory compliance. For preparation, that means every answer, in code or in a design, should name its invariants (a balance never goes negative by accident, a payment is never applied twice), say what happens on a retry or a partial failure, and say where the data lives when something crashes halfway.

The reported questions are mostly credit card and payments scenarios, plus project and behavioral prompts. On the coding side: velocity rules over a stream of transaction logs, a reward-points history that tolerates concurrent updates, a reward tier for a billing cycle, and a thread-safe rate limiter for payment requests. On the design side: a double-entry ledger, a traffic spike during a promotional launch, at-least-once webhook delivery to merchant partners, and a partner integration layer that keeps cardholder data isolated. Build a small working version of each rather than only reading about them.

The stack candidates list is Go, Java or Python, relational databases with a clear grasp of transaction isolation levels, REST or gRPC APIs, and message queues such as Kafka or RabbitMQ. Sharding, consensus protocols and idempotency keys across services are described as less common topics, but idempotency is also the thread running through the ledger, rate limiter and webhook questions, so treat it as core. Cloud (AWS, GCP) and containers (Docker, Kubernetes) are listed as nice-to-have.

The final stage includes people outside engineering and a conversation with senior leadership, so you need two registers: precise engineering language for the coding and design sessions, and plain business language (what broke, who was affected, what it cost, what you decided) for the others. Prepare one set of stories and be ready to tell each at both levels of detail.

The Cardless interview process

Candidates describe three stages, with the last one bundling several sessions. The order of sessions can shift with team availability, and some candidates report rescheduled slots or changed interviewers, so keep in touch with your recruiter.

HR Screening Call

Candidates describe this first call as a conversation about your background, career goals and fit for the role. No technical exercise is reported for it. Treat it as the place to make your backend experience easy to follow, to explain why payments and card programs interest you, and to learn how the later sessions are organised. Since the role is reported as hybrid and San Francisco based, expect logistics to come up here too.

What to demonstrate

  • Your background and the path that led you to a backend role
  • Your career goals and how this role fits them
  • Fit for the role as candidates describe it: backend work where data consistency matters

How to prepare

  • Prepare a short walkthrough of two backend projects: what each did, what you owned, the language and database involved, and one correctness or reliability problem you solved.
  • Prepare your answer to the reported question about why you are interested in fintech and how you stay motivated around regulated systems, because it can come up in any conversation.
  • Ask the recruiter which sessions make up the final stage and who they involve, since candidates report that interviewers and scheduling can shift.

Technical Phone Screen

Candidates describe a phone screen built around a pragmatic coding challenge that resembles a real development task more than a contest puzzle. Reported example scenarios include an in-memory cache with eviction rules and parsing nested JSON from banking APIs where fields are missing or malformed. The reported coding questions for Cardless (velocity rules over transaction logs, reward tiers per billing cycle, a thread-safe rate limiter, a reward-points history) are the nearest practice material. Candidates are advised to explain their approach and data structures aloud before typing.

What to demonstrate

  • Working, readable code in the language you pick, with clear function boundaries and names
  • Choice of data structure for the access pattern: hash maps, queues and trees are the ones reported
  • Edge cases and tests: null input, missing fields, boundary values
  • Concurrency awareness, which is reported as a less common topic for this stage

How to prepare

  • Implement an in-memory cache with a least-recently-used eviction policy and an optional time-to-live, with tests for eviction order and expiry at the boundary.
  • Write a parser for a nested JSON payload with missing and malformed fields that returns valid records plus a list of rejected ones with reasons, rather than throwing on the first bad record.
  • Solve the velocity-rule and rate limiter questions timed, in one language, saying the approach and complexity out loud before you write code.
  • Store money as integer minor units (cents) in every exercise, and say why before the interviewer asks.

Interview Loop

Candidates describe the final stage as several sessions: a system design session, a behavioral interview with cross-functional colleagues who are not engineers, and a culture conversation with executive leadership, which candidates describe as informal and centered on your career story, your interest in fintech and your longer-term goals. For the design area, candidates report scenarios such as a payment gateway that must never process a transaction twice and a ledger synchronization pipeline with an external issuing bank, and topics such as relational versus NoSQL storage, REST or gRPC, message queues and idempotency keys.

What to demonstrate

  • System design with data integrity first: transactions, consistency model, idempotency
  • API design for outside partners and asynchronous processing with queues
  • Communication with non-engineers, including explaining constraints in business terms
  • Career story, motivation for fintech and working style, as covered in the leadership conversation

How to prepare

  • Practise the ledger, webhook delivery and partner integration questions aloud: requirements, API, data model, failure handling, then scaling, stating one trade-off at each step.
  • Write down the invariants of a payment flow (no double charge, entries balance, every event is recoverable) and use them as the checklist for every design answer.
  • Prepare two or three project stories you can tell in business terms: the user or operations impact, the decision, the result.
  • For the leadership conversation, prepare a plain account of why fintech, what you have built that relates to it, and where you want your career to go.

Where candidates lose points

Designing the ledger as a balance column that gets updated in place

Model append-only entries per account, in minor units, where the entries of each transaction sum to zero. Write them in one database transaction, derive or cache balances from entries, and explain how you would reconcile against an external issuing bank.

Treating retries as an afterthought in the payment, rate limiter and webhook designs

Give every payment request an idempotency key stored under a unique constraint. For webhooks, say that delivery is at-least-once and consumers dedupe on an event id, then show the retry schedule and what happens after the final attempt fails.

Writing a rate limiter or reward-points structure that is only correct single-threaded

Name the check-then-act race out loud, protect each key with a lock or an atomic update, and say how you would test it with many threads. Then explain how the design changes across multiple server instances.

Starting to type before pinning down inputs and edge cases in the phone screen

Spend the opening minutes stating assumptions: timestamp ordering, duplicate lines, malformed or missing fields, window boundaries, refunds as negative amounts. Write one test per edge case as you go.

Telling project and behavioral stories that are all team outcomes with no decision of your own, or that stay in engineering jargon for non-engineering colleagues

Use I for your own decisions, name the alternatives you rejected, and rehearse each story with a version stated in terms of customer, operations or business impact.

Questions & practice

Write a program to parse and validate a stream of credit card transaction logs, identifying anomalies based on

Medium · Pragmatic Coding & Data Structures

Write a program to parse and validate a stream of credit card transaction logs, identifying anomalies based on specific velocity rules.

Approach

  1. Parse each log line into a typed record (transaction id, card id, amount in integer minor units, currency, merchant, timestamp). Send malformed or incomplete lines to a rejects list with a reason so one bad line cannot stop the stream, and never hold money in floats.
  2. Keep the velocity rules as data, not branches: each rule has a scope key (card, merchant), a window W, a max count and a max amount. Adding a rule then needs no parser change, and each anomaly can name the rule it broke and the transactions involved.
  3. Per scope key, keep a deque of (timestamp, amount) and a running sum. On each event, pop entries older than now minus W, append the new one, then check count and sum. That is O(1) amortized per event and memory bounded by the events inside the window.
  4. Dedupe on transaction id so a replayed line is not counted twice. Evict keys whose deque is empty so idle cards do not use memory.
  5. Edge cases to state: whether the window boundary is inclusive, refunds and negative amounts, mixed currencies, and events that arrive out of timestamp order. The deque assumes per-key timestamps never go backwards.

Follow-up

  • Events can arrive a few seconds out of order. How do you keep the window counts correct?
  • How do you add a rule like 'more than three distinct merchants inside the window' without rescanning the deque?
  • How would you split this across machines once one process cannot keep up with the stream?

Given a set of merchant categories and user transaction data, write an algorithm to calculate the optimal rewa

Medium · Pragmatic Coding & Data Structures

Given a set of merchant categories and user transaction data, write an algorithm to calculate the optimal reward tier for a billing cycle.

Approach

  1. Pin down 'tier' first. A useful model: each tier has a base rate, per-category multipliers, optional caps, a qualifying spend threshold and possibly a fee. The answer is the tier with the highest net reward for this cycle, with a fixed tie-break.
  2. Make one pass over the cycle's transactions to build a hash map from category to net spend in integer cents. Then score each tier against that map. That is O(T + K x C) for T transactions, K tiers and C categories, with no tier rescanning the raw transactions.
  3. Apply a capped category as min(spend, cap) x bonus rate + max(0, spend - cap) x base rate. If the user chooses k bonus categories, rank categories by spend x (bonus - base) and take the top k. Greedy is optimal here because each category's gain is independent. That is O(C log C), or O(C log k) with a heap.
  4. Edge cases: refunds that net a category below zero (clamp it, or carry it forward), merchants with an unknown category falling back to the base rate, transactions on the cycle boundary (fix the time zone), and points rounding (round once at the end, not per transaction).
  5. Test with a hand-computed example per tier plus property checks: adding spend never lowers a tier's reward, and the chosen tier's score is at least every other tier's.

Follow-up

  • What changes if a single bonus cap is shared across all of the bonus categories?
  • How would you recommend next cycle's tier from past cycles instead of scoring the one just finished?
  • Transactions arrive late and change a closed cycle. How do you recompute and correct the result?

Diff a projection against the primary without per-row point reads

Hard · reconciliation · range hashing · throttling

The listing projection has drifted and some rows show a stale version. The primary holds 40,000,000 resource rows across 12,000 tenants while serving 1,200 writes and 14,000 reads per second. The obvious repair, reading each resource row and comparing its version against the projection, is correct and would eventually finish. Explain precisely why it is unacceptable here, then give a diff that finds the differing rows, state its complexity, and make it safe to run against a live primary. Replication lag is usually under 100 ms and is not bounded.

Approach

  1. Quantify the naive cost rather than calling it slow: 40,000,000 point reads at even 0.5 ms each is over five hours serialised, and the only lever is concurrency, which is exactly what you cannot spend. The primary's pool is sized for the write path, and 40,000,000 random reads evict the buffer cache that sustains the 85 percent cache hit rate, so the audit degrades the system it is auditing.
  2. Replace random access with one ordered pass per side. Both sides can be read in (tenant_id, resource_id) order, which is a sequential scan on each and a merge join in O(n) time and O(1) memory. For a dense diff that is the whole answer, and it reads the primary once instead of 40,000,000 times.
  3. For the expected sparse case, compare range hashes instead of rows: partition the key space, compute per range an order-independent aggregate over hash(resource_id, version), compare aggregates, and descend only into ranges that differ. With d differing rows and branching factor B, at most d ranges mismatch per level, so the drill-down examines O(d log_B(n/d)) ranges and reads full rows only in mismatching leaves.
  4. Aggregate with a sum modulo 2^64 or a multiset hash, never XOR. XOR is order-independent but self-cancelling, so two rows wrong in the same way, or a row duplicated on one side, leave the range aggregate matching and the range is declared clean.

Follow-up

  • The diff reports 900 stale rows. How do you decide between patching those rows and rebuilding the projection from resource_revision?
  • Same job, but the projection lives in a search index that cannot be scanned in key order. What changes?

Hold a per-tenant active cap against concurrent creates

Hard · write skew · isolation levels · constraints

A tenant on the standard plan may hold at most 50 resources with status='active'. The create handler runs SELECT count(*) FROM resource WHERE tenant_id = $1 AND status = 'active', compares to 50, then inserts. Two creates arrive 3 ms apart on different instances and the tenant lands at 51. Name the anomaly, say whether PostgreSQL 16 READ COMMITTED or REPEATABLE READ prevents it and why, then give an implementation that holds the cap at READ COMMITTED with the exact statements. Finally, say what changes when the cap is 'at most one running export per tenant' on job_run.

Approach

  1. Name it: write skew. The two transactions read an overlapping set and write disjoint rows, so there is no row-level conflict for the engine to detect and each commit is individually legal.
  2. Rule out the levels precisely. READ COMMITTED takes a fresh snapshot per statement and takes no lock on the counted rows, so both see 49. PostgreSQL's REPEATABLE READ is snapshot isolation: it removes non-repeatable reads and phantoms within the snapshot but still admits write skew, because the anomaly is not a re-read of a changed row, it is a read of a set that a concurrent transaction invalidates. Only SERIALIZABLE closes it, by tracking the read dependency and aborting one transaction with SQLSTATE 40001 — a guarantee that exists only if the application re-runs the whole transaction from the read.
  3. Convert the set predicate into a single-row conflict: keep tenant.active_resource_count and run UPDATE tenant SET active_resource_count = active_resource_count + 1 WHERE tenant_id = $1 AND active_resource_count < 50 in the same transaction as the INSERT. Zero affected rows is the cap, returned as 409. The row lock serialises the decision at any isolation level, and contention is bounded to one tenant's row — which is also the fair-scheduling unit, unlike a global counter that would convoy every tenant behind one row.
  4. State the cost you just took on: a counter is a second source of truth that can drift, so every path that changes status must adjust it inside the same transaction, and a periodic reconciliation has to exist, with resource_revision as the authority for what the count should have been.

Follow-up

  • A resource moves from archived back to active. Which statements change, and what breaks if the counter update and the status change land in different transactions?
  • The cap becomes plan-dependent and a plan can change mid-month. Where does the number 50 live, and who reads it?

Replace offset paging on the resource feed with keyset

Easy · keyset pagination · composite index · sort order

resource holds resource_id, tenant_id, owner_user_id, title, body_ref, version, status ('draft','active','archived','deleted'), created_at, updated_at, deleted_at, with an index on (tenant_id, status, updated_at DESC, resource_id DESC). The listing endpoint returns active resources for one tenant, newest update first, 50 per page, today with LIMIT 50 OFFSET n. Tenants reach page 400 and rows are created while they read. Write the keyset query, define what the cursor carries and how it is encoded, and say which part of the index each predicate uses. Assume PostgreSQL 16.

Approach

  1. Name the two failures separately. OFFSET 20000 makes the server produce and discard 20,000 rows, so page cost grows with depth rather than with page size. Independently, any write that changes how many rows sort above the offset moves the window between two fetches, and the direction decides which anomaly you get: an insert lands at the head of updated_at DESC and pushes already-returned rows down past the boundary, so they are returned a second time; a delete above the offset, or a row whose updated_at is bumped above the cursor, pulls rows up and one is never returned at all. Nothing in the response reveals either.
  2. Write the seek: WHERE tenant_id = $1 AND status = 'active' AND (updated_at, resource_id) < ($2, $3) ORDER BY updated_at DESC, resource_id DESC LIMIT 50. The row-value comparison is one index range rather than a disjunction, and both columns are NOT NULL, which is what makes that comparison well defined.
  3. Map each predicate onto the index: tenant_id and status are equality on the leading columns, (updated_at, resource_id) is the range, and the ORDER BY matches the index order so no Sort node appears and the scan stops after 50 rows. The DESC in the definition only matters for mixed directions — a plain ascending btree on the same columns is read backwards for this query.
  4. Put both sort columns in the cursor and nothing the client can tamper with into another tenant: base64 of (updated_at, resource_id), validated server-side, with tenant_id taken from the principal.

Follow-up

  • The client asks for 'jump to page 400'. What do you offer instead, and what does the honest version cost?
  • Sort order becomes user-selectable across four columns. How many indexes is that, and which would you refuse to add?

Design a data structure that efficiently tracks and retrieves the history of user reward points while handling

Medium · Pragmatic Coding & Data Structures

Design a data structure that efficiently tracks and retrieves the history of user reward points while handling concurrent updates.

Approach

  1. Model the history as an append-only event list per user: (user, sequence, delta, reason, idempotency key, timestamp). The current balance is the sum of the deltas, kept as a cached snapshot so reads do not rescan the history.
  2. Store the running balance on every event. Then a 'balance as of time T' query is a binary search over that user's events, O(log n), and a history page is a range scan on (user_id, created_at) with keyset pagination.
  3. Serialize writes per user, not globally. In memory, use lock striping or a per-user lock, or a compare-and-swap on a version number. In a relational store, insert the event and update the balance row in one transaction, either with SELECT ... FOR UPDATE or with an optimistic version column and a retry.
  4. Make awards idempotent with a unique constraint on (user, idempotency key), so a retried award is a no-op. Check redemptions against the locked balance so two concurrent redemptions cannot take it below zero.
  5. Trade-off to say out loud: per-user serialization makes one very active user a hot spot, while cross-user throughput scales with the number of users.

Follow-up

  • Points expire some time after they are earned. How do you decide which points a redemption uses up?
  • A redemption and an award for the same user land at the same moment. Walk through both orderings.
  • One user's history reaches millions of rows. How do reads and balance checks stay fast?

Implement a thread-safe rate limiter for an external API endpoint that handles incoming payment requests.

Medium · Pragmatic Coding & Data Structures

Approach

  1. Clarify the key (API key, merchant, client), the sustained rate, the allowed burst, and what a rejected request gets: HTTP 429 with Retry-After, returned before any payment side effect runs.
  2. Use a token bucket per key with capacity B and refill rate r. Store (tokens, last_refill) and refill lazily on each call: tokens = min(B, tokens + elapsed x r). Admit if tokens >= 1, then subtract one. That is O(1) time and memory per key. Read a monotonic clock so wall-clock jumps cannot mint tokens.
  3. The refill, check and consume steps have to be one atomic step, or two threads can both spend the last token. Get the bucket with computeIfAbsent on a concurrent map and lock only that bucket, or run a compare-and-swap loop on an immutable state object. Either way there is no global lock.
  4. Know the alternatives. A fixed window is cheap but can admit up to 2x the limit across a boundary. A sliding log is exact but stores up to the limit's worth of timestamps per key. A sliding-window counter approximates the log with two counters.
  5. An in-process lock only covers one instance. With several API servers, move the state to a shared store and update it atomically, for example a Redis Lua script. Evict idle buckets so memory does not grow with the number of keys ever seen.

Follow-up

  • The endpoint runs on several instances behind a load balancer. What changes, and what happens when the shared store is unreachable?
  • How would you test thread safety? What exact assertion would you make on the number of admitted requests?
  • Should a client retrying a payment with the same idempotency key use up another token?

Design a core ledger system for a credit card platform that guarantees atomic transaction processing and stric

Medium · System Design & Architecture

Design a core ledger system for a credit card platform that guarantees atomic transaction processing and strict double-entry bookkeeping.

Approach

  1. Data model: accounts (id, type, currency), transactions (id, unique idempotency key, created_at, description) and postings (transaction id, account id, signed amount in minor units, currency). The invariant is that each transaction's postings sum to zero per currency. Rows are never updated or deleted, and a correction is a new reversing transaction.
  2. Atomicity: write the transaction and all of its postings in one database transaction in a relational store such as PostgreSQL. Check the zero-sum rule in code and again at commit, for example with a deferred constraint trigger. A retry with the same idempotency key returns the original result.
  3. Balances: the source of truth is the sum of postings. For fast reads and credit-limit checks, update a balance row in the same transaction. Lock the affected account rows in a fixed order (sorted by account id) so that two transfers cannot deadlock.
  4. Isolation: under READ COMMITTED, a limit check without a row lock allows write skew. Either take the lock or run SERIALIZABLE and retry on serialization failures. Say which one you chose and why.
  5. Card specifics: model authorization holds as pending entries that later post or expire. Split hot accounts, such as one platform settlement account, into sub-accounts to reduce lock contention. Run a reconciliation job against the external bank or processor files.

Follow-up

  • How do you handle a chargeback on a transaction that has already settled?
  • One account is written on every transaction and is now the bottleneck. What do you do?
  • An auditor asks for an account's balance as of a date last year. How do you produce it, and how do you prove it is right?

How would you design and scale an app-based credit card management system to handle a sudden spike in traffic

Medium · System Design & Architecture

How would you design and scale an app-based credit card management system to handle a sudden spike in traffic during a major promotional launch?

Approach

  1. Split the traffic by path before scaling anything. App opens and card views are reads. Applications and sign-ups are writes, and they often call outside parties such as identity checks or the partner bank. Estimate peak versus normal traffic for each path. Because the launch time is known, you can scale up in advance.
  2. Read path: stateless API servers behind a load balancer, scaled before the launch because autoscaling reacts late. Put static and promotional content on a CDN, cache offer and card-art data with a TTL, and use read replicas. Never read a balance from a lagging replica right after a payment.
  3. Write path: accept an application, put it on a queue (Kafka or RabbitMQ) and return a status the client can poll. Workers drain the queue at the rate the outside partner allows. Give every outbound call a timeout and a circuit breaker, and require idempotency keys so client retries cannot create duplicate applications.
  4. Shed load gracefully. Use per-user and global rate limits that return 429 or 503 with Retry-After, feature flags to switch off non-essential screens, and a waiting room if needed. Pool database connections, because the connection count often runs out before CPU does.
  5. Prove it beforehand: load test to the projected peak, watch p99 latency, error rate, queue depth and partner error rates on dashboards, and have a written runbook listing who flips which flag.

Follow-up

  • Caching is in place and the primary database is still saturated. What is next?
  • The partner bank caps your call rate below launch demand. What does the applicant see?
  • How do you stop a burst of retries from every client at the exact launch moment?

Design an end-to-end webhook delivery system that reliably notifies merchant partners of transaction events, e

Medium · System Design & Architecture

Design an end-to-end webhook delivery system that reliably notifies merchant partners of transaction events, ensuring at-least-once delivery.

Approach

  1. Never lose an event. Use a transactional outbox: write the event row in the same database transaction as the business change, and have a relay publish it to a queue partitioned by merchant. This avoids the dual-write gap between the database and the broker.
  2. Delivery workers POST with a timeout and count only a 2xx response as delivered. Failures retry with exponential backoff and jitter. Cap concurrency per endpoint so one slow merchant cannot starve the rest. After the maximum number of attempts, move the event to a dead-letter store merchants can replay from, and disable an endpoint that keeps failing.
  3. At-least-once delivery produces duplicates. Give every event a stable unique id and document that receivers must dedupe on it. Retries also break ordering, so include a sequence number or resource version, or tell merchants to fetch current state when the order matters.
  4. Signing: compute an HMAC-SHA256 over the timestamp and body with a per-merchant secret, and send the timestamp so receivers can reject stale replays. Allow two active secrets during rotation, and keep sensitive card data out of the payload.
  5. Keep a delivery-attempts table (event id, endpoint, attempt number, status code, latency, next_attempt_at) indexed on next_attempt_at. It drives the retry scheduler, feeds the merchant-facing delivery log and supports manual replays.

Follow-up

  • A merchant needs strict ordering of events for each transaction. How do you provide it, and what does it cost in throughput?
  • A merchant's endpoint is down for a full day. What happens to the backlog when it comes back?
  • How does a merchant verify that a webhook came from you and is not a replay?

How would you architect a secure partner integration layer that isolates sensitive cardholder data while allow

Medium · System Design & Architecture

How would you architect a secure partner integration layer that isolates sensitive cardholder data while allowing third-party applications to query transaction statuses?

Approach

  1. Isolate card data with tokenization. Full card numbers live only in a separate vault service with its own network segment, its own database and envelope encryption under managed keys, which keeps the PCI-DSS scope small. Every other service, including the partner layer, sees only tokens and the last four digits.
  2. Put an API gateway in front of partners. Authenticate them with OAuth 2.0 client credentials or mutual TLS, and issue scopes so a partner can read transaction status and nothing more.
  3. Authorize every object. Scope each query by the caller's partner or program id, not by the transaction id alone. Otherwise a partner can guess another program's ids (broken object-level authorization, also called IDOR).
  4. Serve partners from a separate read model of transaction status (id, status, amount, merchant, timestamps, token), built from ledger events. Partner traffic then never reaches the core ledger or the vault. Add per-partner rate limits, keyset pagination and webhooks so partners do not need to poll.
  5. Controls and trade-offs: an allowlist serializer per response field, log scrubbing so no card number reaches the logs, an audit trail of every access, and credential rotation. The read model is eventually consistent, so return an updated_at with each status.

Follow-up

  • One partner flow legitimately needs the full card number. How do you support it without widening PCI scope?
  • A partner's credentials leak. How do you detect misuse and contain it?
  • How would you show an auditor that no full card number ever reaches a partner-facing service?

Walk me through a complex technical project you owned from start to finish. What were the most critical archit

Medium · Behavioral & Project Deep Dives

Walk me through a complex technical project you owned from start to finish. What were the most critical architecture decisions you made, and what would you do differently today?

Approach

  1. Choose a project you designed and shipped yourself. Open with the problem, the constraints (scale, correctness, deadline) and your exact role, then move on quickly to the decisions.
  2. Walk through two or three architecture decisions as options considered, choice, reason and the cost you accepted. For example: 'I picked a relational store over a document store because the writes had to be transactional, and I accepted harder horizontal scaling.'
  3. Bring numbers: request volume, latency or error rate before and after, incidents, and adoption. Be ready to sketch the system and go two levels deeper into any component, including how it fails.
  4. For 'what would you do differently', name a concrete technical change and the reason, such as adding idempotency keys or an outbox from the start. 'More tests' or 'better communication' does not count.
  5. What sinks this answer: describing a team effort where your own decisions cannot be separated out, or blaming others for the parts that went wrong.

Follow-up

  • What broke in production after launch, and how did you find it?
  • If traffic grew tenfold, which component would fail first?
  • Who disagreed with your main design decision, and what did you do about it?

Describe a situation where you had to debug a critical production issue under tight time constraints. How did

Medium · Behavioral & Project Deep Dives

Describe a situation where you had to debug a critical production issue under tight time constraints. How did you isolate the problem and prevent it from recurring?

Approach

  1. Open with the impact: who was affected, what broke (for example, failed or double-processed payments) and how you knew. Then say what you did to stop the damage before you found the root cause, such as a rollback, a feature flag or a failover.
  2. Describe the isolation steps in order. First establish what changed and when (deploys, config, traffic, dependencies). Then narrow by one dimension (a host, region, partner, client version), reproduce the failure, and confirm the hypothesis with a log line or metric rather than a guess.
  3. Separate the trigger from the root cause. A deploy or traffic spike often only exposes an existing bug, such as a missing timeout, a race or a non-idempotent retry.
  4. Prevention you owned: a test that reproduces the bug, an alert that would have fired earlier, a guardrail such as a canary or limit, and the action items from a blameless postmortem. If money or records were affected, explain how you found and repaired the bad rows with an idempotent script and how you reconciled them.
  5. What sinks this answer: no concrete technical detail, a fix that came from luck, or a story in which you only watched someone else debug.

Follow-up

  • How did you keep stakeholders informed while the incident was still open?
  • Which alert or dashboard would have caught it sooner, and did you add it?
  • How did you verify that the fix worked and that no data was left corrupted?

Suggested practice checklist

The plan follows the three reported rounds: foundations and the coding screen first, then ledger and integration design, then project, incident and behavioral stories. Each day ends with something you can reuse in the live session.

Day 1 — Map the loop and refresh the database foundations

  • Write out the three reported rounds and, for each, the questions you are least ready for. Pick the one language (Go, Java or Python) you will use for every coding exercise.
  • Write a one-page sheet on transaction isolation levels: read committed, repeatable read and serializable, the anomalies each allows, and a payments example such as two concurrent withdrawals from one balance.
  • Write a half-page on idempotency keys: what is stored, under what unique constraint, and what a retry returns.

Deliverable: A round map with weak spots marked, an isolation-level sheet and an idempotency note, all in your own words.

Day 2 — Phone-screen coding: log validation and reward tiers

  • Write a parser for transaction log lines that counts and skips malformed lines, then add a velocity rule (more than N transactions per card inside a sliding window) with a queue per card. Test boundary timestamps, out-of-order lines and duplicates.
  • Write the reward-tier calculation for a billing cycle: group transactions by merchant category, apply the tier rules, use integer cents, and handle refunds and an empty cycle.
  • Say the approach and complexity aloud before typing, then repeat both exercises under a timer.

Deliverable: Two working solutions in your chosen language with a test file each, and a one-line complexity statement for each.

Day 3 — Concurrency: rate limiter and reward-points history

  • Implement a thread-safe rate limiter (token bucket or sliding window) keyed per caller. Write a test with many threads hitting one key and assert the limit is never exceeded.
  • Design the reward-points history as an append-only list of changes (amount, reason, time) with a running balance, and compare a lock, an optimistic version check and a database row lock for concurrent updates.

Deliverable: A limiter with a concurrency test, a written comparison of three locking options for the points history, and your notes from the practice question.

Day 4 — Ledger design and transaction safety

  • Sketch the ledger schema: accounts, transactions and entries in minor units, entries per transaction summing to zero, a unique key for idempotency, and the SQL that posts a transfer in a single transaction.
  • Decide how you would stop two concurrent postings from overdrawing an account (row lock versus serializable retry) and write the trade-off in two sentences.

Deliverable: A ledger schema with the posting statement, a locking trade-off note, and a short list of what a reconciliation job would compare.

Day 5 — Scale, webhooks and the partner integration layer

  • Design the promotional-launch traffic spike answer: read caching, queued writes, autoscaling limits, load shedding and which features degrade first, with the datastore bottleneck named.
  • Design webhook delivery: an outbox table written in the same transaction as the event, a worker, exponential backoff with jitter, signed payloads, a dead-letter path and consumer dedupe by event id.
  • Design the partner layer: cardholder data kept in a separate vault behind tokens, status queries that return tokens and statuses only, scoped credentials per partner and audit logging.

Deliverable: Three one-page design outlines, each with API, data model, failure handling and its main trade-off.

Day 6 — Project deep dive and production incident stories

  • Write the outline of a project you owned end to end: goals, two or three architecture decisions with the alternatives you rejected, and what you would change today.
  • Write an incident story as a timeline: detection, mitigation, how you isolated the cause, the fix, and the prevention that followed (alert, test, runbook).
  • Rehearse both aloud, then rehearse again in business terms for non-engineering listeners.

Deliverable: Two outlined stories, each with an engineering version and a business-terms version.

Day 7 — Behavioral and leadership conversation rehearsal

  • Write outlines for the trade-off, mentoring, fintech motivation, explaining-to-a-non-engineer and challenged-design prompts, using I and naming your own decision in each.
  • Rehearse the leadership conversation: your career story, why fintech, and what you want next, without technical jargon.
  • Run one full mock: a design question followed by two behavioral prompts, with trade-offs said aloud.

Deliverable: Five behavioral outlines, a career-story script and notes from one full mock run.

Stories for engineers, colleagues and executives

The behavioral parts of this loop are reported to include colleagues from outside engineering and a conversational session with executive leadership, alongside project deep dives. They cover trade-offs, ownership, mentoring, explaining constraints to non-engineers and your interest in fintech. Prepare stories in which you made a decision and can state the alternatives and the result, and be able to tell each one in business terms as well as technical terms.

  1. How do you handle constructive feedback from peers or leadership when your system design is challenged?
  2. Walk me through a complex technical project you owned from start to finish. What were the most critical architecture decisions you made, and what would you do differently today?

Tell me about a time you had to make a trade-off between speed of delivery and architectural purity. How did y

Medium · Behavioral & Project Deep Dives

Tell me about a time you had to make a trade-off between speed of delivery and architectural purity. How did you align the team on this decision?

Approach

  1. Choose a decision you owned where a shortcut and a cleaner design were both real options. Name the two options concretely (for example, a synchronous call now versus a queue and retry worker later) and the deadline or business event that forced the choice.
  2. Show how you decided: how reversible the shortcut was, how much of the system it touched, and whether the code path moved money or only produced reports. A strong answer holds the line on correctness for money movement and accepts impurity elsewhere, and says so.
  3. Cover alignment: you wrote the options down with costs, got the team and product owner to agree to the shortcut explicitly, and recorded the debt with an owner, a ticket and a trigger for paying it back.
  4. Close with the outcome from your own experience: what shipped, whether the shortcut caused trouble, whether it was repaid. A story where you picked speed and never revisited it, or insisted on purity and missed the date with no fallback, is the version that sinks.

Follow-up

  • Was the shortcut ever repaid, and who decided when?
  • What would have made you choose the cleaner design instead?
  • Would your decision change if the code path were a ledger write rather than a reporting job?

How do you approach mentoring junior engineers and ensuring high code quality across your team?

Medium · Behavioral & Project Deep Dives

Approach

  1. Answer with mechanisms rather than a philosophy: pairing on a junior's first changes, starter tasks scoped to teach one new idea, and review comments that explain the reason behind the change instead of rewriting the code.
  2. Describe how quality is held at team level: small pull requests, tests required in CI, a short written review checklist (edge cases covered, errors handled, migrations safe to roll back), and incident follow-ups that feed new checklist items.
  3. Give one real mentee example with a before and after you can observe, such as their first independent feature, fewer review rounds, or taking on-call, and say what you did that made the difference.
  4. Show calibration: when you let someone try and fail in a safe place, and when you tighten review because the code touches payments or data migrations. Avoid the answer where quality means you approve every change, which makes you the bottleneck.

Follow-up

  • A junior's pull requests keep coming back with the same problems. What do you do?
  • How do you keep review quality up without becoming the bottleneck?
  • How would you review a change that alters how ledger entries are written?

Why are you interested in working in the fintech space, and how do you stay motivated when dealing with highly

Medium · Culture & Cross-Functional Collaboration

Why are you interested in working in the fintech space, and how do you stay motivated when dealing with highly regulated systems?

Approach

  1. Answer both halves of the question: why this field, and how you stay motivated when the systems are heavily regulated. Do not spend the whole time on the first half.
  2. For why, point to engineering problems you enjoy that fintech makes unavoidable: correctness under failure, idempotent retries, auditability, reconciliation between systems. Tie each to something you built or studied, and mention facts the role lists, such as ledgers, transaction processing and partner integrations.
  3. For regulation, treat constraints as design inputs. PCI-DSS is named for this role, which means isolating cardholder data, keeping audit trails and controlling change. Describe a time you worked within a security, compliance or process constraint and kept delivery moving, for example by automating a check or involving reviewers early.
  4. If you lack fintech experience, bridge from adjacent work with money-like invariants (billing, inventory, bookings) and say what you have read or built since. Avoid generic statements about the industry's size and avoid calling compliance red tape.

Follow-up

  • Describe a rule or review step that slowed you down and what you did about it.
  • Which failure in a card payment flow worries you most, and why?
  • What would you want to learn first about how card transactions are processed?

Tell me about a time you had to explain a highly technical concept or system limitation to a non-engineering c

Medium · Culture & Cross-Functional Collaboration

Tell me about a time you had to explain a highly technical concept or system limitation to a non-engineering colleague. How did you ensure they understood?

Approach

  1. Pick a situation with a real stake and a specific colleague in product, operations or compliance: for example why a transaction shows as pending, why a feature needs more time, or why an event can arrive twice. State the limitation and the decision they needed to make.
  2. Describe the translation: you led with the business impact and the decision, used a concrete example from their world (one customer's transaction followed step by step) instead of terms like idempotency or eventual consistency, and used one diagram or timeline rather than many.
  3. Explain how you checked understanding: you asked them to restate it in their own words, or you saw them act correctly afterwards, such as changing a support script, adjusting a launch date or choosing between two options.
  4. End with what lasted: a short written note or FAQ others reused. The story fails if you only simplified and moved on, if the listener ended up deciding differently only by deferring to you, or if it sounds condescending.

Follow-up

  • What did they misunderstand at first, and how did you notice?
  • What would you do if they still needed a date you could not meet?
  • How did you write this up so the next person would not need the same conversation?

How do you handle constructive feedback from peers or leadership when your proposed system design is challenge

Medium · Culture & Cross-Functional Collaboration

How do you handle constructive feedback from peers or leadership when your proposed system design is challenged?

Approach

  1. Choose a specific design review where your design was challenged and state the technical objection precisely (for example a single-writer bottleneck, a missing failure case, or an operational cost).
  2. Show your process: restate the objection to confirm you understood it, ask for the scenario that breaks the design, then test it with numbers, a failure walk-through or a small prototype rather than arguing from position.
  3. Say what changed. Either you revised the design and can show it was better, or you held your ground and can show the evidence that convinced the reviewer. Both are acceptable, but you should name which one happened and why.
  4. Add how you handle it when the challenger is senior or from outside engineering, and how you record the outcome (a design note with alternatives considered) so the decision is not reopened. Avoid a story where you were right all along or one where you gave in without understanding the point.

Follow-up

  • Tell me about a time you held your position and were later shown to be wrong.
  • How do you handle feedback when there is no time to test the alternative?
  • How do you record a design decision so it does not get relitigated?