SYSTEM_DESIGN
System Design: Neobank Architecture
Design a neobank architecture powering a fully digital bank with mobile-first experiences, real-time transaction notifications, virtual and physical card issuance, and partner banking infrastructure (BaaS).
Requirements
Functional Requirements:
- Mobile-first checking and savings accounts with FDIC insurance via partner bank
- Virtual and physical debit card issuance with real-time transaction notifications
- Direct deposit with early paycheck access (up to 2 days early)
- Peer-to-peer payments, bill pay, and ACH transfers
- Spending insights with automatic categorization, budgeting tools, and savings goals
- Card controls: freeze/unfreeze, merchant category blocking, spending limits, location-based controls
Non-Functional Requirements:
- Support 10M active accounts with 50M daily card transactions
- Real-time push notifications for every transaction within 2 seconds of authorization
- 99.99% availability for card authorization (network-level SLA with Visa/Mastercard)
- Sub-100ms response for card authorization decisions
- PCI DSS Level 1 compliance for card data handling
Scale Estimation
50M daily card transactions = 580 TPS average, peaking at 3,000 TPS during holiday shopping (Black Friday sees 5x normal volume). Each card transaction triggers: authorization decision (100ms budget), real-time notification push, balance update, transaction categorization, and spending limit check. Direct deposit processing: 5M users receiving bi-weekly paychecks = 2.5M ACH credits on the 1st and 15th of each month, processed in a 4-hour batch window = 174 ACH credits/sec. Savings goal calculations: 10M accounts × 3 goals average = 30M daily progress updates. Card issuance: 50K new virtual cards/day + 10K physical card orders/day.
High-Level Architecture
The neobank operates as a technology layer on top of a sponsor bank (the chartered bank that holds deposits, provides FDIC insurance, and interfaces with payment networks). The architecture has three pillars: the Banking Core (ledger, accounts, payments), the Card Platform (issuance, authorization, settlement), and the Customer Experience Layer (mobile app, notifications, insights).
The Banking Core maintains a double-entry ledger tracking every financial movement. Customer accounts are liability accounts on the sponsor bank's balance sheet, but the neobank's ledger maintains the sub-ledger with real-time balances. The Card Platform interfaces with payment networks (Visa/Mastercard) through a card processor (Marqeta, Galileo, or in-house). When a cardholder swipes their card, the merchant's acquiring bank routes the authorization request to Visa, which routes it to the neobank's authorization endpoint. The neobank has 100ms to respond with approve/decline based on available balance, card controls, and fraud checks.
The Customer Experience Layer is event-driven: every authorization, settlement, ACH credit, and P2P transfer emits an event to Kafka, consumed by the Notification Service (pushes real-time alerts), the Insights Service (categorizes and aggregates spending), and the Savings Service (tracks progress toward goals and executes round-up savings).
Core Components
Card Authorization Service
The Card Authorization Service is the most latency-critical component. When a cardholder taps their card, the authorization request arrives from the card network (Visa/Mastercard) via the card processor's API. The service must respond within 100ms with an authorization decision. The decision pipeline: parse ISO 8583 message → check card status (active, not frozen) in Redis → check available balance in Redis → evaluate card controls (merchant category allowed, within spending limit, within geo-fence) → run fraud score (simplified model, <20ms) → respond APPROVED or DECLINED with response code. The entire pipeline runs in memory using Redis for all lookups. Balance holds are created atomically using Redis DECRBY — if the decrement would make balance negative, the operation fails and the authorization is declined. Hold amounts are persisted to PostgreSQL asynchronously after responding to the network.
Early Direct Deposit Engine
Early paycheck access is a key neobank differentiator. The Early DD Engine works by recognizing incoming ACH payroll credits up to 2 days before the scheduled settlement date. When an ACH file is received from the Federal Reserve (via the sponsor bank), the engine identifies payroll transactions by: originator name matching against known payroll processors (ADP, Gusto, Paychex), transaction codes indicating payroll (PPD with specific addenda records), and recurring pattern matching (same originator, similar amount, bi-weekly/monthly frequency). Recognized payroll deposits are credited to the user's available balance immediately, funded by the neobank's credit facility with the sponsor bank. When the ACH settles on the original date, the credit facility is repaid. Risk management: the engine limits early access to the lesser of the incoming amount or the user's average payroll deposit to mitigate risk of ACH returns.
Spending Insights & Savings Service
The Insights Service processes every transaction through a categorization pipeline: merchant category code (MCC) provides a base category, enhanced by merchant name matching (Plaid-style enrichment) for granular sub-categories. Spending aggregations are pre-computed by category and time period (daily, weekly, monthly) and stored in Redis for instant dashboard rendering. The Savings Service implements automated savings features: round-ups (round each purchase to the next dollar and sweep the difference to savings), percentage-of-deposit (automatically move 10% of each direct deposit to savings), and goal tracking (user sets a target amount and deadline, the system calculates required weekly savings). Sweep transactions are batched and executed as a single daily ledger entry to avoid per-transaction overhead.
Database Design
The neobank ledger uses PostgreSQL with double-entry bookkeeping. Tables: accounts (account_id, user_id, account_type CHECKING/SAVINGS, balance NUMERIC(18,4), available_balance, hold_amount, status, opened_at), ledger_entries (entry_id, transaction_id, account_id, direction DEBIT/CREDIT, amount, balance_after, created_at), card_authorizations (auth_id, card_id, account_id, merchant_name, mcc, amount, currency, status APPROVED/DECLINED/SETTLED/REVERSED, auth_code, network_reference_id, authorized_at, settled_at).
Real-time balances are cached in Redis as simple key-value pairs: balance:{account_id} storing available_balance as an integer (cents). Card status and controls are stored in Redis hashes: card:{card_id} with fields status, spending_limit_daily, spending_limit_monthly, blocked_mccs, geo_fence. This ensures all authorization checks read from Redis exclusively. PostgreSQL serves as the durable ledger with reconciliation between Redis balances and PostgreSQL balances running every 5 minutes.
API Design
POST /v1/cards/authorize— Card network authorization endpoint (called by card processor); body contains ISO 8583 fields (card_number, amount, merchant, MCC); must respond within 100ms with approval/declinePOST /v1/transfers— Initiate an internal transfer, P2P payment, or ACH transfer; body contains from_account, to_account_or_routing_number, amount, type (INTERNAL/P2P/ACH), idempotency_keyGET /v1/accounts/{account_id}/insights?period=monthly— Spending breakdown by category, comparison to prior period, budget progressPATCH /v1/cards/{card_id}/controls— Update card controls; body contains changes (frozen, spending_limits, blocked_categories, geo_fence)
Scaling & Bottlenecks
Card authorization at 3,000 TPS during Black Friday with a 100ms SLA is the defining scaling challenge. The authorization service runs on dedicated bare-metal servers (not containers — to avoid scheduler jitter) with direct Redis connections (no connection pooling — pool checkout latency is too high). Multiple authorization servers sit behind an L4 load balancer with health checks every 1 second. If Redis fails, a fallback mode reads the last-known balance from a local in-memory cache (refreshed every 30 seconds), accepting slightly stale data over declining all transactions.
Direct deposit processing on the 1st and 15th creates massive batch spikes. The 2.5M ACH credits must be processed, early-deposit-eligible ones identified, and balances credited — all within the 4-hour batch window. The ACH Processing Service parallelizes across 50 workers partitioned by account_id range. Each worker processes 50K credits in 45 minutes. The ledger database experiences 10x normal write load during this window — handled by pre-provisioned IOPS and write-ahead-log optimization.
Key Trade-offs
- Redis for authorization over database reads: Sub-millisecond Redis reads ensure the 100ms authorization SLA, but Redis is volatile — the 5-minute reconciliation against PostgreSQL detects and corrects any Redis-PostgreSQL drift
- Early direct deposit with credit facility over waiting for settlement: Offering paychecks 2 days early is a killer feature for customer acquisition, but the neobank assumes settlement risk — mitigated by limiting early access to recognized payroll patterns and historical amounts
- Sponsor bank model over bank charter: Using a sponsor bank avoids the 2-3 year charter application process and $50M+ capital requirements, but limits product flexibility and adds regulatory dependency — some neobanks eventually pursue their own charter as they scale
- Event-driven insights over request-time computation: Pre-computing spending aggregations on every transaction ensures instant dashboard loading, but creates a processing pipeline that must keep up with 580 TPS of transaction events — Kafka consumer lag monitoring triggers auto-scaling
GO DEEPER
Master this topic in our 12-week cohort
Our Advanced System Design cohort covers this and 11 other deep-dive topics with live sessions, assignments, and expert feedback.