Splitwise tracks shared expenses among friends, roommates, and travel groups — helping millions of users settle debts fairly. Designing an expense-sharing platform tests your understanding of financial calculations (debt simplification), group data models, transaction consistency, and the algorithms that minimize the number of payments needed to settle all debts. This is an increasingly popular system design question that combines financial logic with social features.
Data Model
Core entities: (1) User — user_id, name, email, phone, default_currency, payment_methods. (2) Group — group_id, name, members (list of user_ids), created_at, type (apartment, trip, couple, other). (3) Expense — expense_id, group_id, paid_by (user_id who paid), amount, currency, description, category (food, rent, transport, entertainment), date, split_type, participants (list of user_ids with their share amounts), created_by, created_at. (4) Split types: equal (amount / N per person), exact (custom amounts per person), percentage (custom percentages), shares (weighted — Alice gets 2 shares, Bob gets 1), and by_item (itemized — Alice had the steak, Bob had the salad). (5) Settlement — settlement_id, from_user, to_user, amount, currency, payment_method, settled_at. A settlement records an actual payment that reduces a debt. Balance computation: for each pair of users (A, B) in a group: scan all expenses involving both. For each expense: if A paid and B is a participant, B owes A their share. If B paid and A is a participant, A owes B their share. The net balance between A and B is the sum of all these amounts. Positive: A is owed money by B. Negative: A owes B. Settle-up subtracts from the balance. Store balances as a derived view (computed from expenses and settlements) or maintain a running balance updated on each new expense/settlement.
Debt Simplification Algorithm
In a group of 5 people with many expenses, the naive approach produces many small debts (A owes B $5, B owes C $10, C owes A $3, …). Debt simplification minimizes the number of transactions needed to settle all debts. Algorithm: (1) Compute the net balance for each person: positive = they are owed money, negative = they owe money. The sum of all net balances is 0 (money is conserved). (2) Match debtors (negative balance) with creditors (positive balance). Greedy approach: find the max creditor and max debtor. Transfer min(|credit|, |debt|). This settles one person. Repeat until all balances are 0. (3) Optimal approach (minimum transactions): this is NP-hard in general but solvable for small groups (up to 20 people) with subset-sum DP. Find subsets of participants whose balances sum to 0 — each subset can settle internally without involving others. Maximize the number of such independent subsets to minimize total transactions. For small groups (Splitwise typical: 2-10 people): the greedy approach works well and produces near-optimal results. For a 5-person group: the naive approach might require 10 transactions; debt simplification reduces it to 4. Simplification is optional: some users prefer to see exactly who they owe (even if it means more transactions). Splitwise shows both: simplified debts (fewer payments) and detailed debts (per-expense breakdown).
Real-Time Balance Updates
When a new expense is added: all group members balances update in real-time. Architecture: (1) The expense is validated and stored in the database. (2) Balances are updated: for each participant, adjust their balance with the payer. This is a set of ledger entries: for a $100 dinner paid by Alice split equally among 4 people, create: Bob owes Alice $25, Carol owes Alice $25, Dave owes Alice $25. (3) Push notifications: all participants receive a notification (“Alice added dinner $100 — you owe $25”). (4) The group summary (total balances per member) is recomputed and pushed to all connected clients via WebSocket. Consistency: balance updates must be atomic. If the system crashes after updating some balances but not others, the group is inconsistent. Use a database transaction: BEGIN; INSERT expense; INSERT balance entries for each participant; COMMIT. Optimistic locking on the expense (prevent duplicate additions) with an idempotency key generated by the client. Concurrent edits: two users adding expenses simultaneously to the same group. No conflict (each expense is independent). But if both edit the SAME expense simultaneously: last-write-wins with conflict notification, or operational-transform-style merge for itemized edits.
Multi-Currency Support
International trips involve expenses in multiple currencies. A group trip to Europe: hotel in EUR, restaurant in GBP, taxi in USD. Each expense stores its original currency and amount. Balance computation: convert all amounts to a common currency (the group default or user preferred) using exchange rates at the time of the expense. Exchange rate service: fetch daily rates from a provider (Open Exchange Rates, Fixer.io). Cache rates per (date, currency_pair). For a historical expense: use the rate on that date (not today rate). Display: show the original currency and the converted amount. “Alice paid EUR 50 (~ $54.23).” The converted amount may change if rates are retroactively corrected (rare — use the rate at entry time and do not re-convert). Settlement in different currencies: Bob owes Alice $25 but wants to pay in EUR. The settlement records: amount_from = EUR 23.15, amount_to = $25.00, exchange_rate = 1.08. Both users see the correct amount in their preferred currency. Rounding: currency conversions introduce rounding (cents). For small groups: round to 2 decimal places and accept the tiny discrepancy (< $0.01 per expense). For very precise splitting: track amounts in the smallest currency unit (cents) and distribute remainders fairly (if $10 split 3 ways: two people pay $3.33, one pays $3.34).
Payment Integration and Settlement
Splitwise is a ledger (tracks who owes whom) but also enables direct payment. Payment options: (1) Record a cash payment — the debtor marks the debt as settled. No actual money movement through the app. The app updates the balance. (2) Integrated payment — connect to PayPal, Venmo, or bank transfer. The debtor initiates payment through the app. On successful payment: the app records a settlement and updates balances. The payment is processed by the third-party provider; Splitwise is the interface. (3) In-app wallet — some expense apps maintain an internal balance (like Venmo). Users can deposit funds and pay directly. Adds complexity (regulatory compliance, PCI) but improves UX. Settlement flow: (1) Debtor clicks “Settle up” -> sees the amount owed and payment options. (2) Selects payment method (Venmo, PayPal, bank). (3) The app initiates the payment via the provider API (with an idempotency key). (4) On success: record the settlement, update balances, notify the creditor (“Bob paid you $25”). (5) On failure: show error, do not update balance. Retry if transient. Partial settlement: the debtor can pay less than the full amount. The remaining balance persists. The settlement is recorded for the partial amount. Group-level settle-up: “Settle all debts in this group” generates the simplified set of payments and initiates each one. One-click settlement for the simplified debt graph.
{“@context”:”https://schema.org”,”@type”:”FAQPage”,”mainEntity”:[{“@type”:”Question”,”name”:”How does debt simplification minimize the number of payments?”,”acceptedAnswer”:{“@type”:”Answer”,”text”:”Without simplification: a 5-person group might need 10 individual payments. With simplification: typically 4. Algorithm: (1) Compute net balance per person (positive = owed money, negative = owes). Sum is always 0. (2) Greedy matching: find the max creditor and max debtor. Transfer min(|credit|, |debt|). This settles one person completely. Repeat until all balanced. (3) Optimal (NP-hard but practical for small groups): find subsets whose balances sum to 0 — each settles internally. Maximize independent subsets to minimize total transactions. For typical Splitwise groups (2-10 people): greedy is near-optimal. Simplification is optional — some users prefer detailed per-expense debts. Show both: simplified (fewer payments) and detailed (who owes what for each expense).”}}]}