Back to Stripe questions
CodingSoftware Engineer

Account Balance Manager

Role: Software Engineer


Problem Overview

You are building an account balance management system for a payment platform. The system processes financial transactions across multiple accounts and needs to handle various business rules around balance validation and fund coverage.

The problem is divided into three progressive parts:

  • Balance Aggregation: Process transactions and return final account balances

  • Transaction Validation: Reject transactions that would cause negative balances

  • Platform Account Coverage: Use a designated platform account to cover insufficient funds

Input Format

You will receive a list of transactions, where each transaction contains:

  • account_id: Unique identifier for the account

  • amount: Transaction amount (positive for deposits, negative for withdrawals)

python
transactions = [
    {"account_id": "account_A", "amount": 100},
    {"account_id": "account_B", "amount": 50},
    {"account_id": "account_A", "amount": -30},
    {"account_id": "account_B", "amount": -80}
]

Part 1: Balance Aggregation

Problem Statement

Implement a function get_account_balances(transactions) that processes all transactions and returns the final balance for each account that has a positive balance.

Example

Input:

python
transactions = [
    {"account_id": "account_A", "amount": 100},
    {"account_id": "account_B", "amount": 50},
    {"account_id": "account_A", "amount": -30},
    {"account_id": "account_C", "amount": 200},
    {"account_id": "account_B", "amount": -50}
]

Output:

python
get_account_balances(transactions)
# Returns: {"account_A": 70, "account_C": 200}
#
# Calculation:
# account_A: 100 - 30 = 70 (positive, included)
# account_B: 50 - 50 = 0 (zero, excluded)
# account_C: 200 (positive, included)

Requirements

  • Process transactions in order

  • Aggregate amounts by account ID

  • Return only accounts with balance > 0

  • Return as a dictionary mapping account_id to balance

Part 2: Transaction Validation

Problem Statement

Extend your solution to validate each transaction before processing. A transaction should be rejected if it would cause the account balance to become negative. Return both the final balances and the list of rejected transactions.

Implement process_transactions(transactions) that returns a tuple of (balances, rejected_transactions).

Example

Input:

python
transactions = [
    {"account_id": "account_A", "amount": 100},
    {"account_id": "account_A", "amount": -150},  # Would make balance -50
    {"account_id": "account_B", "amount": 50},
    {"account_id": "account_A", "amount": -80},   # Valid: 100 - 80 = 20
    {"account_id": "account_B", "amount": -100}   # Would make balance -50
]

Output:

python
process_transactions(transactions)
# Returns: (
#     {"account_A": 20, "account_B": 50},
#     [
#         {"account_id": "account_A", "amount": -150},
#         {"account_id": "account_B", "amount": -100}
#     ]
# )
#
# Processing:
# 1. account_A +100 → balance: 100 ✓
# 2. account_A -150 → would be -50 ✗ REJECTED
# 3. account_B +50 → balance: 50 ✓
# 4. account_A -80 → balance: 20 ✓
# 5. account_B -100 → would be -50 ✗ REJECTED

Requirements

  • Process transactions in order

  • Reject any transaction that would make the account balance negative

  • Deposits (positive amounts) are always accepted

  • Return rejected transactions in the order they were encountered

  • Include accounts with zero balance in the result

Part 3: Platform Account Coverage

Problem Statement

The platform can now provide financial assistance. When a transaction would cause a negative balance, instead of rejecting it, the system should transfer funds from a designated platform account to cover the shortfall.

Implement process_with_coverage(transactions, platform_account_id) that returns the total amount of funds transferred from the platform account to cover all shortfalls.

Example

Input:

python
transactions = [
    {"account_id": "platform", "amount": 1000},
    {"account_id": "account_A", "amount": 100},
    {"account_id": "account_A", "amount": -150},  # Needs 50 coverage
    {"account_id": "account_B", "amount": 50},
    {"account_id": "account_B", "amount": -100},  # Needs 50 coverage
    {"account_id": "account_A", "amount": -30}    # Needs 30 coverage
]

platform_account_id = "platform"

Output:

python
process_with_coverage(transactions, "platform")
# Returns: 130
#
# Processing:
# 1. platform +1000 → platform balance: 1000
# 2. account_A +100 → account_A balance: 100
# 3. account_A -150 → would be -50, cover 50 from platform
#    account_A balance: 0, platform balance: 950, total_coverage: 50
# 4. account_B +50 → account_B balance: 50
# 5. account_B -100 → would be -50, cover 50 from platform
#    account_B balance: 0, platform balance: 900, total_coverage: 100
# 6. account_A -30 → would be -30, cover 30 from platform
#    account_A balance: 0, platform balance: 870, total_coverage: 130

Requirements

  • Platform account is specified by an additional parameter

  • When a transaction would cause negative balance, transfer exactly enough from the platform account to bring balance to zero

  • The transaction should still be processed (balance ends at 0)

  • Return the total amount of coverage provided

  • Assume platform account always has sufficient funds

Solution Approach

Part 1: Balance Aggregation Solution

Strategy:

  • Use a dictionary to track balance for each account

  • Iterate through transactions, updating balances

  • Filter and return accounts with positive balances

Time Complexity: O(n) where n is the number of transactions

Space Complexity: O(k) where k is the number of unique accounts

Example Implementation:

python
def get_account_balances(transactions):
    balances = {}

    for txn in transactions:
        account_id = txn["account_id"]
        amount = txn["amount"]
        balances[account_id] = balances.get(account_id, 0) + amount

    # Filter for positive balances only
    return {acc: bal for acc, bal in balances.items() if bal > 0}

Edge Cases to Consider:

  • Empty transaction list

  • All accounts end with zero or negative balance

  • Single account with multiple transactions

  • Large number of accounts

Part 2: Transaction Validation Solution

Strategy:

  • Track current balance for each account

  • Before processing withdrawal, check if it would cause negative balance

  • If valid, apply transaction; otherwise add to rejected list

  • Return both final balances and rejected transactions

Time Complexity: O(n)

Space Complexity: O(k + r) where r is the number of rejected transactions

Example Implementation:

python
def process_transactions(transactions):
    balances = {}
    rejected = []

    for txn in transactions:
        account_id = txn["account_id"]
        amount = txn["amount"]
        current_balance = balances.get(account_id, 0)

        new_balance = current_balance + amount

        if new_balance < 0:
            # Reject transaction
            rejected.append(txn)
        else:
            # Accept transaction
            balances[account_id] = new_balance

    return (balances, rejected)

Key Considerations:

  • Deposits (positive amounts) can never cause negative balance

  • Check happens before applying the transaction

  • Rejected transactions don't affect account state

  • Order of rejected transactions matches input order

Part 3: Platform Account Coverage Solution

Strategy:

  • Process transactions with coverage logic

  • When a withdrawal would cause negative balance:

  • Calculate the shortfall (amount needed to bring balance to 0)

  • Deduct from platform account

  • Add coverage to running total

  • Set account balance to 0

  • Return total coverage amount

Time Complexity: O(n)

Space Complexity: O(k)

Example Implementation:

python
def process_with_coverage(transactions, platform_account_id):
    balances = {}
    total_coverage = 0

    for txn in transactions:
        account_id = txn["account_id"]
        amount = txn["amount"]
        current_balance = balances.get(account_id, 0)

        new_balance = current_balance + amount

        if new_balance < 0 and account_id != platform_account_id:
            # Calculate coverage needed
            coverage_needed = -new_balance  # Convert negative to positive

            # Deduct from platform account
            balances[platform_account_id] = balances.get(platform_account_id, 0) - coverage_needed

            # Add to total coverage
            total_coverage += coverage_needed

            # Set account balance to 0
            balances[account_id] = 0
        else:
            balances[account_id] = new_balance

    return total_coverage

Important Considerations:

  • Platform account transactions are processed normally

  • Coverage is only for non-platform accounts

  • Shortfall calculation: if balance would be -50, coverage is 50

  • Final balance after coverage is always 0, not the full withdrawal amount

  • Clarify with interviewer: should platform account balance be tracked/validated?