Papers
Ledger: Stripe's System for Tracking and Validating Money Movement
Ilya Ganelin · Stripe Dot Dev Blog (engineering post, not peer reviewed), 2024
The problem: proving that independent systems add up together
Stripe's payments and treasury network accepts payments, holds money, and moves it across many currencies and payment methods, through banking partners and local financial networks. To make the problem tractable, the platform is divided into distinct services, databases, and interfaces (APIs/gRPC). The cost of this division is that nothing forces these systems to represent or deliver data the same way: some operate in real time and others on a monthly cadence; some generate billions of events per day and others only a few hundred; and each has its own definition of correctness. Even so, Stripe must guarantee, to internal customers and external auditors, that what should happen in payment processing actually happens. The post sums up the need as a mechanism able to handle these variations and prove that the individual systems, together, correctly model the company's finances. The text also emphasizes that the real world is imperfect: malformed reports, errors propagated by banking or network partners, and even macroeconomic changes. Although it aspires to an orderly ideal, Stripe says that at its scale this is impossible; instead, it built a system that keeps these imperfections manageable and bounded. Ledger and a Data Quality platform built on top of it are the answer.
The core idea: systems modeled as flows of funds between accounts
The Ledger represents each producer system as a state machine and describes its behavior as a logical flow of funds: balances (events) that move between accounts (states). From this, the Ledger computes all account balances, grouped by various subdivisions, to assess the health of the system and generate statistics. Accounts are buckets of money distinguished by type (for example, charge_unsubmitted) and by properties (for example, id and business); events move money between accounts. A charge, for example, appears as a creation event, for the pending charge, and a release event, when it completes. The Ledger works as a semantic repository: instead of computing a dataset derived from input pipelines, it models the actual work of the producer systems, recording each operation as a transaction. Since this model can diverge from the source data, the post says the divergence is explicitly watched by completeness checks. Because the Ledger is a system of record at the transaction level, it also models consistency across disconnected systems and follows each transaction through its entire lifecycle, which the post calls tracing. An end-to-end flow, such as a company adding funds to its balance, crosses several teams, and modeling it as a flow unifies that data.
Double entry: the error becomes a balance that did not zero out
The Ledger is based on double-entry bookkeeping, a standard method for ensuring that all the money in a system is accounted for, by balancing credits and debits. The post uses an analogy: water flowing through a network of pipes (processes) that ends in reservoirs (balances). In steady state, the terminal reservoirs are full and the intermediate pipes (clearing accounts) are empty; water trapped in the pipes, that is, an unresolved balance, indicates a problem. Stripe applies the idea beyond physical money, to model system behaviors such as currency conversion, report reading, estimates and billing analysis. In the post's example, the charge.creation event creates a balance in an account for funds not yet disbursed and, later, charge.release moves the funds to the company's balance. The two events are independent: even if they arrive out of order or from different sources, the Ledger joins them by the business and id identifiers. If the release is never published or arrives with the wrong id, the intermediate account's balance does not go to zero. Likewise, a wrong business value (B instead of A) leaves two accounts with a nonzero balance instead of one. Thus, a missing, late or incorrect event is detected with a simple query, such as finding the clearing accounts with a nonzero balance.
Immutability, data correction, and what the post does not say about idempotence
At its core, the Ledger is an immutable log of events. Transactions that have been published cannot be deleted or modified, and past state can always be reconstructed by processing the events up to that point. Balances, fund flows, and data quality checks are all transformations of this static structure, which makes it possible to audit and reproduce any data at any time and to analyze exactly the problematic data. The flip side is that you do not fix state with a query that alters records: you have to revert and reprocess earlier operations. For this, Stripe built a utility that creates and runs migrations safely, protected by a data quality tool that generates out-of-band reports (outside the execution flow) on the production impact of proposed changes. Together, these tools approximate a CI pipeline for one-off repairs, and every operation goes through review and two-phase commit, both of the data and of the DQ impact. A scope caveat: the post does not discuss idempotency or how duplicate writes are handled, so this summary does not attribute any such mechanism to Stripe. What the text establishes are neighboring ingredients, the immutable log, the derivation of balances from it, and the reprocessing of events.
Data Quality platform: clearing, timeliness, and completeness
On top of the Ledger, Stripe built a Data Quality (DQ) platform that evaluates each flow of funds with three questions. Clearing: did the flow complete correctly? This is checked through the clearing accounts that should be zeroed out. Timeliness: did the data arrive on time? It measures the interval between the data entering the Stripe platform and reaching the Ledger, against a hard delivery-window limit. Completeness: do we have a complete representation of the source system? This uses cross-system checks (for example, every ID in the producer's database must have a corresponding event in the Ledger), automatic anomaly detection and statistical models per account type that estimate, from history, when the data should arrive; an event that doesn't show up is treated as possibly missing data. The metrics are combined into a unified DQ score, and the post claims that a system with a 99.99% score is unlikely to hide serious problems. The post reports about five billion events per day in the Ledger, 99.99% of dollar volume fully ingested and verified within four days, and more than 99.9999% explainability of money movement, even with data volume having grown 10 times. Dashboards show the score per team, with automatically generated tickets, and let you investigate a point on the chart down to the root cause.
See the ideas at work
Practice the designs that use this paper in the System Design school.