PracHub
QuestionsLearningGuidesInterview Prep
|Home/System Design/Klaviyo

Design banking with scheduled transfers and merges

Last updated: Mar 29, 2026

Quick Overview

Design banking with scheduled transfers and merges evaluates requirements, scale assumptions, API/data design, architecture, trade-offs, failure modes, and rollout in a realistic interview setting. A strong answer states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.

  • hard
  • Klaviyo
  • System Design
  • Software Engineer

Design banking with scheduled transfers and merges

Company: Klaviyo

Role: Software Engineer

Category: System Design

Difficulty: hard

Interview Round: Take-home Project

Design and implement an in-memory banking system with scheduled payments and account merges. Provide these APIs and semantics: 1) transfer(timestamp, source_account_id, target_account_id, amount) -> str | None - At 'timestamp', deduct 'amount' from the source account’s available balance and freeze it until the target accepts or the transfer expires exactly 24 hours after initiation (upon expiry, funds automatically return to the source and the transfer can no longer be accepted). - If source == target, either account does not exist, or the source has insufficient available balance (excluding already frozen funds), return None. - On success, return a unique transfer id like 'transfer1', 'transfer2'. - Frozen funds contribute to both parties’ pending (unsettled) totals and do not enter either account’s transaction history until accepted. 2) accept_transfer(timestamp, account_id, transfer_id) -> bool - Return True iff the transfer exists, is not expired, not already accepted, and 'account_id' is exactly the transfer’s target; otherwise return False. 3) merge_accounts(timestamp, account_id_1, account_id_ 2) -> bool - At 'timestamp', merge 'account_id_2' into 'account_id_1'. If the IDs are equal or either account does not exist, return False. - Cancel all pending transfers originating from 'account_id_2'; also cancel all pending transfers from 'account_id_1' to 'account_id_2'. - Redirect all other pending inbound transfers whose target is 'account_id_2' so their target becomes 'account_id_1'. - Increase 'account_id_1' balance by 'account_id_2' balance; aggregate both accounts’ historical totals as combined; delete 'account_id_2'; return True. 4) get_balance(timestamp, account_id, time_at) -> int | None - Return the balance of 'account_id' immediately after processing all operations at 'time_at'. If the account did not yet exist by 'time_at' or had been deleted by then, return None; otherwise return the correct historical balance. Constraints and expectations: - Amounts and balances are integers; timestamps are integer units; 24 hours means exactly 24*60*60 units after initiation; acceptance at or after the expiry moment is invalid. - Operations may arrive in any order of 'timestamp'; you must answer historical queries correctly for arbitrary 'time_at'. - Describe the data structures/algorithms (e.g., hash maps, event log/ledger, min-heap or timer wheel for expirations, indices for per-account state, and any persistence/persistence-like strategy for time travel), their time/space complexity, and how you would generate unique IDs. - Provide a working single-threaded in-memory implementation and justify design choices; briefly discuss how you would extend to handle concurrency and scale.

Quick Answer: Design banking with scheduled transfers and merges evaluates requirements, scale assumptions, API/data design, architecture, trade-offs, failure modes, and rollout in a realistic interview setting. A strong answer states assumptions, handles edge cases, explains trade-offs, and shows how to validate the result clearly.

|Home/System Design/Klaviyo

Design banking with scheduled transfers and merges

Klaviyo logo
Klaviyo
Jul 15, 2025, 12:00 AM
hardSoftware EngineerTake-home ProjectSystem Design
15
0

Design banking with scheduled transfers and merges

In-Memory Banking System with Scheduled Payments and Account Merges

Design and implement a single-threaded, in-memory banking system that supports scheduled payments, account merges, and time-travel balance queries.

APIs and Semantics

  1. transfer(timestamp, source_account_id, target_account_id, amount) -> str | None
  • At timestamp, deduct amount from the source account’s available balance and freeze it until the target accepts or the transfer expires exactly 24 hours after initiation. On expiry, funds automatically return to the source and the transfer can no longer be accepted.
  • If source == target, either account does not exist at timestamp, or the source has insufficient available balance (excluding already frozen funds), return None.
  • On success, return a unique transfer id like "transfer1", "transfer2".
  • Frozen funds contribute to both parties’ pending (unsettled) totals and do not enter either account’s transaction history until accepted.
  1. accept_transfer(timestamp, account_id, transfer_id) -> bool
  • Return True iff the transfer exists, is not expired, not already accepted or cancelled, and account_id is exactly the transfer’s current target at timestamp; otherwise return False.
  1. merge_accounts(timestamp, account_id_1, account_id_2) -> bool
  • At timestamp, merge account_id_2 into account_id_1. If the IDs are equal or either account does not exist at timestamp, return False.
  • Cancel all pending transfers originating from account_id_2; also cancel all pending transfers from account_id_1 to account_id_2.
  • Redirect all other pending inbound transfers whose target is account_id_2 so their target becomes account_id_1.
  • Increase account_id_1 balance by account_id_2 balance; aggregate both accounts’ historical totals as combined; delete account_id_2; return True.
  1. get_balance(timestamp, account_id, time_at) -> int | None
  • Return the balance of account_id immediately after processing all operations at time_at. If the account did not yet exist by time_at or had been deleted by then, return None; otherwise return the correct historical balance.

Constraints

  • Amounts and balances are integers.
  • Timestamps are integer units; 24 hours is exactly 24 60 60 units after initiation.
  • Acceptance at or after the expiry moment is invalid.
  • Operations may arrive in any timestamp order; you must answer historical queries correctly for arbitrary time_at.

Expectations

  • Describe data structures/algorithms (e.g., hash maps, event log/ledger, min-heap or timer wheel for expirations, indices for per-account state, and any persistence-like strategy for time travel), their time/space complexity, and how to generate unique IDs.
  • Provide a working single-threaded in-memory implementation and justify design choices.
  • Briefly discuss how you would extend to handle concurrency and scale.

Minimal Assumptions to Make the Problem Self-Contained

  • Accounts are created outside the four required APIs (e.g., via a helper create_account(account_id, created_at, initial_balance)). The four required APIs must still enforce existence checks at their timestamps.
  • "Balance" means settled ledger balance (excludes frozen funds). "Available" means balance minus currently frozen outgoing amounts.
  • Event ordering at the same timestamp will be deterministic: Initiations first, then Merges, then Accepts, then Expirations.

Constraints & Assumptions

  • Preserve the scope, facts, inputs, and requested outputs from the prompt above.
  • If the prompt leaves a detail unspecified, state a reasonable assumption before relying on it.
  • Keep the answer interview-ready: concise enough to present, but concrete enough to implement or evaluate.

Clarifying Questions to Ask Guidance

  • Clarify users, core use cases, read/write patterns, scale, latency, availability, and data retention.
  • State explicit assumptions before making sizing or architecture decisions.
  • Prioritize the functional path first, then address reliability, security, observability, and rollout.

What a Strong Answer Covers Guidance

  • A scoped requirements summary with concrete non-goals and success metrics.
  • API, data model, architecture, consistency, capacity, and operations.
  • Reasoned trade-offs among simple and scalable designs, including bottlenecks and failure modes.
  • A validation, monitoring, migration, and launch plan appropriate for the risk level.

Follow-up Questions Guidance

  • What breaks first at 10x traffic or data volume?
  • How would you degrade gracefully during dependency failures?
  • What metrics and alerts would prove the design is healthy after launch?

Submit Your Answer to Earn 20XP

Sign in to leave a comment

Loading comments...

Browse More Questions

More System Design•More Klaviyo•More Software Engineer•Klaviyo Software Engineer•Klaviyo System Design•Software Engineer System Design

Your design canvas — auto-saved

PracHub

Master your tech interviews with 9,000+ real questions from top companies.

Product

  • Questions
  • Learning Tracks
  • Interview Guides
  • Resources
  • Premium
  • For Universities

Browse

  • By Company
  • By Role
  • By Category
  • Topic Hubs
  • SQL Questions
  • AI Coding Questions
  • Compare Platforms
  • Discord Community

Support

  • support@prachub.com
  • (916) 541-4762

Legal

  • Privacy Policy
  • Terms of Service
  • About Us

© 2026 PracHub. All rights reserved.