Skip to content

Senior Engineering Interview Handbook / Chapter 145

Fintech and Regulated Systems

A specialty-track chapter that follows one unresolved payment through idempotent submission, ledgering, reconciliation, controlled correction, operational access, and interview practice.

The request timed out. Did the money move?

Consider a checkout service that sends a charge request to a payment provider. The provider accepts the TCP connection, the client waits, and then the request times out. The local service has no response. The customer still sees a spinner.

What should happen next?

“Return an error and retry” is an ordinary product instinct with an extraordinary consequence here: the provider may already have accepted the charge. Retrying with a new identity can move the money twice. Declaring success is no better. The system does not yet have evidence for either answer.

The honest state is unknown. That one word changes the design. It requires a stable command identity, a durable local record, a way to learn what the provider did, a customer status that does not claim false certainty, and an operational path for cases automation cannot settle.

An interview in this domain is rarely a quiz on regulatory acronyms. It asks whether the organization could trust, explain, and repair the system you designed. The timeout gives that question a concrete shape. Follow it far enough and it reaches ledger design, retries, access control, privacy, fraud, incident response, compliance collaboration, and customer remediation.

Name what is being governed

Before drawing services, state the sensitive transition. In this case, an authorized customer intends to move a specified amount in a specified currency to a merchant. The harm is not merely an untidy row: the customer may be charged twice, the merchant may be underpaid, financial reports may be wrong, or the firm may be unable to reconstruct a dispute.

Six questions give the rest of the answer its boundaries:

  1. Authority: who may initiate, approve, submit, reverse, or inspect the movement? A user action, service principal, risk rule, operator, or scheduled job needs a bounded permission model.
  2. Invariant: what must remain true? Amounts have a declared currency and scale; one logical command must not create two intended charges; posted financial history is corrected rather than overwritten.
  3. Evidence: which durable records will later identify the actor, command, request, provider reference, state change, reason, and time?
  4. Reconciliation: which independent account of reality can confirm or contradict the online path?
  5. Correction: which reversal, void, refund, adjustment, or case workflow repairs a mistake while preserving the original event?
  6. Policy: which retention, residency, approval, reporting, or privacy choices require an accountable legal, compliance, risk, finance, or privacy owner?

These questions transfer beyond payments. Replace the charge with an identity decision, entitlement, consent record, insurance claim, payroll instruction, regulated report, data-deletion state, or privileged access grant. The rules change by product and jurisdiction; the engineering obligation to make the transition explicit does not.

Give the retry something stable to mean

A practical coding round may reduce the problem to this:

Implement an endpoint that submits a transfer between two wallet accounts.
The client may retry after a timeout. The system must not transfer funds twice.

Start with the command contract, not the HTTP handler. Require a client transfer identifier scoped to the initiating customer. Validate that the amount is positive, the currency is supported, source and destination are legal, the caller is authorized, and product or risk limits permit the request. Reuse of the same identifier with different command data is a conflict, not a retry.

The database must enforce the identity. A plausible first transaction inserts the command under a unique (customer_id, client_transfer_id) constraint, records the validated intent, and creates the necessary hold or pending ledger entries. If work must leave the database, an outbox record can make publication part of that transaction. A duplicate submission reads the existing command and returns its stable transfer identifier and current known state.

This is stronger than a cache of recent keys. A cache can expire while the external effect remains. It is also stronger than “check, then insert,” which allows concurrent requests to pass the check together. The uniqueness constraint, transaction boundary, and guarded state transitions are part of the correctness argument.

If the transfer calls an external provider, use the same stable command identity where the provider contract supports idempotency, and persist its reference. That reduces duplicates; it does not abolish uncertainty. The system can still lose a response after the provider accepts the work.

Tests should force the boundaries rather than decorate the happy path:

  • repeat the same key before completion and after success;
  • reuse the key with a different amount, currency, or destination;
  • submit the same key concurrently;
  • time out before a provider receives the request, after it accepts the request, and after it responds but before local state advances;
  • deliver duplicate and out-of-order callbacks;
  • reject insufficient funds, closed accounts, currency mismatch, failed authorization, and forbidden transitions;
  • reverse or refund a completed movement without changing the original entries.

“Exactly once” is usually the wrong claim at a boundary shared by clients, databases, queues, and vendors. The defensible claim is narrower: commands have stable identities, duplicate effects are resisted, state changes are monotonic where possible, and reconciliation finds cases the online path cannot resolve.

Keep three truths separate

The payment now has three related but different representations.

The workflow records business progress: initiated, submitted, unknown, authorized, captured, settled, failed, canceled, reversed, or refunded. Its state machine says which transitions are legal and which actor may cause them. “Unknown” is neither failure nor permission to start again.

The ledger records financial facts: holds, releases, charges, fees, settlement, refunds, and adjustments. Posted entries are not edited because the customer-facing workflow changed. Corrections create linked entries so a later reader can see both what happened and how it was repaired. Double-entry structure can help preserve equal and opposite effects across accounts, but it does not by itself solve authorization, idempotency, wrong account mapping, chargebacks, delayed settlement, or fraud.

The customer and operator views translate internal truth without falsifying it. A customer may see “payment pending” while an operator sees the provider request, last observation, next reconciliation attempt, and permitted actions. Neither view is the system of financial record.

Money representation belongs in this design, not in a footnote. Use integer minor units or a decimal-safe representation rather than binary floating point. Carry currency and scale explicitly. Define rounding for fees, taxes, foreign exchange, and partial refunds. If the product deals in securities, credits, rewards, or usage units, say whether the quantity has money-like conservation rules or only resembles money in the interface.

A useful state trace for the original timeout is:

local command:  initiated -> submitted -> unknown -> captured -> settled
provider view:                         accepted -> captured -> settled
ledger facts:                          hold/charge          -> settlement
customer view: pending -----------------------> paid

The lines will not advance together. That is why collapsing them into one payment_status column produces lies during failure.

Reconciliation supplies the missing observation

The online path records what the application attempted and observed. It cannot be its own independent proof. To resolve the timeout, the service may combine a provider lookup, webhook, polling result, settlement file, bank movement, or other provider report. Each source has its own delay and failure modes.

A reconciliation job needs stable matching keys where possible, explicit timing windows, rules for partial and aggregate settlement, and known provider quirks. It should distinguish at least these breaks:

  • the provider captured a charge that the local workflow still calls unknown;
  • the local workflow claims success but no provider or settlement record appears;
  • amounts or currencies disagree;
  • one side contains a refund, reversal, fee, or dispute missing from the other;
  • multiple external records match one logical command;
  • a record is too old to remain a routine timing difference.

Every exception needs severity, customer or financial exposure, an owner, and an allowed correction path. Preserve the detected mismatch and the resolution. Measure unmatched counts, aged breaks, exposure amounts, time to resolution, and recurrence. A backfill after an outage or schema migration should use the same controls instead of becoming an unreviewed bulk rewrite.

Reconciliation is not a background chore added after launch. It is part of the product’s truth model. In an interview prompt involving payments, payouts, payroll, billing, settlement, reports, or external identity vendors, mentioning it early shows that you do not confuse a successful API call with agreement between systems of record.

Let operators repair harm without acquiring invisible power

Some unknown payments will require human judgment. Operations may need to view provider evidence, refund a fee, release a risk hold, correct an account state, or escalate a dispute. The internal tool that permits those actions is a high-risk production system, not incidental back-office UI.

Split capabilities by consequence. Viewing masked payment details, revealing identity documents, changing account state, issuing a refund, and overriding a risk decision are different permissions. High-impact actions may require a second approver. Sensitive writes should show their effect before execution, require a reason and case reference, emit an immutable audit event, and produce a monitoring signal. Bulk work needs rate limits, dry runs, bounded batches, and an exception report.

Break-glass access deserves a separate path: time-limited privilege, incident or case linkage, immediate visibility, mandatory review, and cleanup. “Senior engineers can edit production” is not a control design.

An audit event should answer who acted, what changed, when, under which authority, why, and through which correlated request or case. Before-and-after values may help an investigation, but copying secrets, payment data, or identity documents into a broadly accessible log creates a new liability. References, hashes, redaction, tokenization, or separately protected evidence may be safer.

The same restraint applies across environments. Ask whether test, analytics, support, debugging, and exported reports need the sensitive data at all. When they do, enforce purpose, tenant and regional boundaries, retention class, masking, access review, and deletion or legal-hold workflows. Do not invent a universal retention period or promise that every record can be deleted on demand. Those decisions depend on the record, jurisdiction, contract, and policy owner.

Risk controls must include the customer who was wronged

Fraud and risk systems introduce another governed transition: allow, step up, hold, review, or block. A model score or rule is evidence for a decision, not the decision’s entire explanation. The design also needs false-positive handling, reviewer tools, appeal or remediation paths, abuse controls, and monitoring for drift in both loss and customer friction.

Suppose the timed-out payment is held because the retried request looks like a duplicate. That may prevent a second charge, but it can also leave a legitimate order unpaid. The system should tell support what is known, let reconciliation resolve the provider state, and give an authorized operator a bounded response. “Block suspicious activity” is incomplete until the answer includes how an innocent customer recovers.

During an incident, stop the unsafe retry path before perfect diagnosis. Count affected attempts and exposure, preserve provider and local evidence, identify which operations remain safe, and give support a truthful customer status. Correction may mean voids, refunds, reversals, or adjustments according to provider capability and finance policy. Regression coverage should replay the timeout, duplicate callback, delayed webhook, provider mismatch, and repeated checkout submission that produced the harm.

Policy becomes real only through system behavior

Legal, compliance, privacy, risk, security, finance, support, and operations are not a final approval queue. Their decisions can change the state machine, approval path, data model, retention scheme, launch gate, monitoring, and incident response. Bring the accountable partners in before those choices are expensive to reverse.

The engineer should not improvise legal interpretation. “Regulation requires us to retain every log for seven years” is too broad to design against. A stronger answer identifies the record class and jurisdiction, asks the accountable owner to confirm the rule, and builds a retention mechanism that can enforce the answer. Legal owns interpretation; engineering owns whether the chosen policy can be operated, evidenced, and changed safely.

This posture avoids two failures. Treating compliance as paperwork yields controls that cannot survive production. Hiding behind compliance abdicates the engineering judgment needed to implement the policy. In an interview, state your assumption, name its owner, and continue with the architecture the system would need under that assumption.

Migrations are reconciliation events

Moving from a mutable balance table to an entry-based ledger makes every old record part of the proof. A credible migration declares the source of truth for each phase, defines mappings for malformed and disputed records, and decides how new transactions behave while backfill runs. Dual writing is useful only when the team can compare and repair the results.

balance_before = balance_after is insufficient. Reconcile by account and currency; include pending holds, negative balances, closed accounts, historical adjustments, customer disputes, and finance exports. Use checkpoints and independent totals. Isolate unsafe edge cases for manual review. Preserve the migration decisions and exceptional adjustments, then monitor cutover in terms of customer impact and financial exposure.

Rollback may be impossible after new financial facts exist. In that case, name the forward-fix path rather than promising a database restore that would erase valid activity.

Carry one payment through the interview loop

The specialty signal can appear through several interview doors without becoming five unrelated performances.

In a coding round, implement the command identity, posting function, authorization guard, state-transition validator, reconciliation matcher, or audit-event builder. Make the invariant visible in constraints and tests rather than leaving it in comments.

In system design, keep workflow, ledger, external provider, reconciliation, customer view, and operator tools distinct. Let the interviewer add partial settlement, multiple currencies, chargebacks, regional data boundaries, manual review, or a provider outage and show which contract changes.

In debugging, begin with observations rather than a retry fix. Preserve evidence, bound the blast radius and exposure, stop unsafe paths, distinguish unknown from failed, and prove the remediation against independent records.

For a project deep dive, choose work involving money movement, identity, entitlements, billing, privacy, reporting, risk, or another sensitive workflow. Make the protected invariant and rejected alternative audible. Useful evidence includes reconciliation results, audit findings, launch gates, incident metrics, migration totals, decision records, and operational outcomes.

Behavioral questions often add delivery pressure: product wants to launch before reconciliation exists; an operator asks for direct database access; a policy interpretation changes late; a customer needs remediation before the root cause is complete. A strong answer explains the harm plainly, offers a bounded route forward, identifies who owns residual risk, and names the evidence required to reopen the broader path. Compliance is neither villain nor shield.

Prepare two stories. One should be about correctness: the state, harm, invariant, design, trade-off, evidence, correction, and lesson. The other should show cross-functional judgment: how a policy or risk concern became an engineering decision, what delivery cost it introduced, and how you communicated the remaining uncertainty.

Practice until the timeout changes your answer

Use the original payment attempt as a week of connected practice:

  1. Implement the idempotent transfer command. Add concurrent duplicate submissions and conflicting reuse of the same key.
  2. Sketch ledger entries for hold, charge, fee, settlement, refund, and adjustment. Derive available and pending balances.
  3. Add a timeout at every boundary. Decide which state is now known, which is unknown, and what evidence can advance it.
  4. Write the reconciliation matcher and exception queue. Include delayed, missing, duplicated, amount-mismatched, and aged records.
  5. Design the operator refund action with permission, approval threshold, reason, case link, preview, audit evidence, and compensation path.
  6. Remove unnecessary sensitive data from logs, lower environments, support views, and reports; then define the policy decisions you still need.
  7. Rehearse the incident and the launch disagreement aloud. Preserve evidence, quantify exposure, remediate customers, and explain the next decision without claiming legal authority you do not have.
  8. Migrate the balance representation while new transfers continue. State the source of truth at every phase and the independent totals that permit cutover.

Preparation is adequate when “the request timed out” no longer triggers an automatic retry. You can name what is unknown, what must remain true, what each record proves, how independent systems will agree, who may correct the result, and which policy owner must resolve the remaining assumption.

Keep this compact frame available during an interview:

Sensitive state: what can harm the customer or firm if wrong?
Authority: who may change it, under which approval or policy?
Invariant: what must remain true before and after the change?
Evidence: what durable record proves the action and its reason?
Uncertainty: which state must remain unknown rather than guessed?
Reconciliation: which independent record can resolve disagreement?
Correction: how can we repair harm without rewriting history?
Policy owner: who confirms retention, privacy, risk, or reporting assumptions?

The senior answer does not sound regulated because it contains more control vocabulary. It earns trust by refusing to make the system claim more than it knows—and by ensuring that uncertainty has somewhere disciplined to go.