Parafin’s capital products move millions of dollars every day. In the company’s earliest phase, we made the classic tradeoff: optimize for speed. Funding and repayments lived in product tables; a user’s “balance” was recomputed on the fly:
balance = principal + fees – Σ(repayments)
The worked, until reality crept in:
if to “the formula.”balance = principal + fees – Σ(repayments) – Σ(manual_repayments) – fee_discount – Σ(generic_activity) …
Early‑stage velocity gave us a product, customers, and signal. But it also left us with two sources of “truth” (backend vs. reporting) and rising engineering costs with each new feature. Eventually we hit a wall: the model wasn’t extensible.
We put a product‑agnostic ledger at the center of money movement. The rule is simple: if an event changes a balance, it must be represented as a ledger transaction first; product state is derived from ledger state, not vice versa.
To make that tractable across teams and vendors, we created layered, vendor‑agnostic services:
This separation lets us add vendors or rails without touching product logic and ensures every balance‑impacting event flows through the same contract.

A ledger is an append‑only, double‑entry log of monetary events. Each ledger transaction contains at least two ledger entries — one debit, one credit — that net to zero, producing auditable, replayable balances per account.
(If you’re new to double‑entry, Modern Treasury’s docs and journal series are a great grounding in accounts, entries, transactions, and immutability.)
When we decided to build a ledger-first system, we first asked whether to build our own ledger or use a vendor. As a startup, our team is small and we’re deliberate about where we invest engineering effort. We want to focus on Parafin’s core value, not re-solve problems that infrastructure providers already handle well.
Building a ledger in-house would have meant significant work to achieve durability, consistency, and reconciliation guarantees. Instead, we chose to evaluate external ledger vendors that could give us those primitives out of the box. After comparing a few options, we decided on Modern Treasury as the best fit for our needs.
Using MT lets our team focus on product semantics rather than building core ledger infrastructure from scratch.
The CapitalCashierService converts business events into balanced entries. For example, funding user1 with $1,000 principal and a $10 fee becomes one transaction with four entries:
DEBIT merchant_outstanding_balance $1,000 (type=principal)
DEBIT merchant_outstanding_balance $10 (type=fee)
CREDIT parafin_disbursement_account $1,000 (type=principal)
CREDIT parafin_fee_revenue_account $10 (type=fee)The resulting MT transaction status (e.g., pending → posted) is now the source of truth for product state. Entry metadata (e.g., type=principal|fee) gives Accounting the dimensions they need without re‑deriving context later.
Network blips and 5xxs are normal at scale. We designed the write path so they can’t corrupt state:
allowRetry=false and are retried by Temporal with the same idempotency key; non‑retryables (4xx) set state Failed with allowRetry=true for a corrected new attempt.Tradeoff: This adds schema and workflow surface area, but it converts transient failures from scary to routine and prevents duplicate or missing money movement. It’s a tradeoff worth making for correctness.
Calling a third‑party API for every balance read or status check is slow and fragile under rate limits, so we built two mechanisms:
ledger_account_lock_version. Writers update the cache on ledger transaction creation/updates; readers hit the cache and refresh asynchronously if stale. We also reconcile cache lock‑versions against MT’s data warehouse on a regular cadence; if versions diverge, we refresh affected accounts asynchronously.This kept correctness while cutting external calls by ~80% and improving p95 latency for balance reads.
Tradeoff: Caching introduces eventual consistency risk. The lock‑version discipline and periodic reconciliation are the guardrails that make it safe.
We launched in shadow mode first. Every money movement produced a ledger transaction in MT, but product UIs and APIs still served balances from the legacy path. We double‑read and logged any discrepancies between the two. Once drift hit ~zero, we gradually flipped traffic — first a slice of businesses, then 100% — and finally removed double‑writes.
Shadow mode immediately paid for itself: we found subtle bugs in the old calculation logic (e.g., rare refund edge cases) that were hard to detect in the legacy system.
Tradeoff: We carried redundant processing and duplicate plumbing briefly, but it bought trust with stakeholders and a clean roll‑out.
By unifying around a single ledger-backed balance, we’ve improved accuracy, reliability, and speed across products and systems, making it easier to launch, reconcile, and operate at scale.
CashierService balance, backed by MT ledger data. No more re‑implementing SQL in dashboards or pipelines; the ledger is the source of truth.The ledger is no longer “back office”. It’s a first-class part of our product surface. There’s compelling work ahead.
Beyond correctness and auditability, we’re also pushing toward full financial reconciliation.
With our product ledger solidified, the next frontier is extending ledger coverage to the bank and reporting layers, bringing true end-to-end reconciliation.
CashierService. However, these accounts are not linked to our corporate cash accounts, which means we can’t yet use Modern Treasury’s integrated payments + ledger for automatic reconciliation. Next, we’re expanding our ledger coverage to each of our 25+ corporate accounts to enable real-time, intraday reconciliation against bank balances. This will shorten time-to-detect for anomalies and let us retire much of the accounting team’s reconciliation work.If you’re wrestling with drifting balances or exploding schema complexity, our strongest advice is simple: force every balance‑impacting event through a double‑entry ledger and derive product state from that record of truth. The rest — retries, migrations, caching — becomes an engineering discipline rather than a guessing game. For a quick primer (and battle‑tested patterns), Modern Treasury’s “What is a Ledger” and scaling series are excellent resources.
We’re growing the team building this platform. If designing reliable, auditable money movement at scale sounds fun, come work with us.