Chapter 9 · Reconciliation as a practice
The Platform Refund Ledger · 5 min read
This chapter answers one question: how does a Connect platform close a month — from payouts to balance transactions to the books — so that refund leakage cannot hide between systems?
Reconciliation is not a report you generate; it is a set of identities that must hold. When they hold, a leak of the kind this book describes is structurally impossible to miss for long. When nobody defined them, every number is negotiable.
The three artifacts
- Balance transactions — the ground truth (chapter 7). Pulled continuously or nightly; grouped by
typeand joined bysource. - Payouts — the bank-facing record. Each
Payoutobject has anamount,status, andarrival_date, and corresponds to balance transactions whose funds became available into it. Failed or canceled payouts return viapayout_failure/payout_cancelledger lines rather than vanishing (docs.stripe.com/reports/balance-transaction-types). - The books — where your accounting system believes everything happened.
The month-close is proving artifact 3 equals artifacts 1 and 2, line by line, with the type-to-account mapping made explicit.
Template T1 — the payout register
One row per payout in the month:
| payout_id | arrival_date | status | amount | Ledger sum match | Book ref |
|---|---|---|---|---|---|
| po_8141 | 2026-08-04 | paid | 12,481.90 | ✓ | JE-2211 |
| po_8157 | 2026-08-11 | paid | 9,930.44 | ✓ | JE-2287 |
| po_8172 | 2026-08-18 | failed | 0.00 | ✓ (funds returned) | JE-2305 |
"Ledger sum match" means: the balance transactions that fed this payout sum exactly to its amount. That check is the whole game — a payout your bank received that no set of transactions explains is the definition of unexplained money, in either direction.
Template T2 — the type-to-account map
Decide once, in writing, which book account each ledger type posts to. Ambiguity here is where refund losses hide — a refund posted against revenue nets to invisibility; posted to its own account it becomes a trend someone owns.
Balance transaction type | Posts to |
|---|---|
charge | Clearing — Stripe |
stripe_fee | Payment processing expense |
application_fee | Platform fee revenue |
application_fee_refund | Platform fee revenue (contra) |
refund | Refunds (contra-revenue, own account) |
transfer | Seller payable — clearing |
transfer_refund | Seller payable — clearing (contra) |
adjustment (dispute source) | Chargeback expense |
reserve_transaction / connect_collection_transfer | Connected-account reserve |
topup | Bank transfer in |
payout / payout_cancel / payout_failure | Bank: Stripe clearing |
Template T3 — the month-close checklist
| Step | Evidence when done |
|---|---|
Pull full-month balance transactions; group by type; total each | Type totals sheet |
Sum charge − refund − stripe_fee ± adjustments per currency; agree to payout totals plus change in available balance | Identity holds to zero |
| Match every payout row to its transaction set (T1) | Register complete |
| Post per T2; verify refund and fee-refund contra accounts carry real balances | Journal entries |
| Split closing Stripe balance into platform cash versus pending seller share | Balance decomposition memo |
Scan for orphan adjustment, reserve_transaction, connect_collection_transfer lines; each mapped to a cause | Anomaly list empty or explained |
The identity in step two deserves its own sentence: charges minus refunds minus Stripe fees, plus or minus dispute adjustments, must equal payouts out plus the change in what Stripe still holds. If it does not, the difference is either a missing object class in your pull or money nobody can name — both worth stopping the close over.
Cutoff discipline: pending is not available
At close, your Stripe balance exists in two states (docs.stripe.com/api/balance/balance_retrieve): available — spendable now — and pending — settling on future dates carried by each transaction's available_on. Only available funds can pay out, so the books' "cash at Stripe" figure is the available balance, while pending is a receivable still inside Stripe.
Worked decomposition, continuing chapter 7's day: available closed at $156.84, entirely platform money — the day's seller shares had already transferred out line by line. Suppose instead the export also showed $240.00 pending: under the book's running 10% pricing, $216.00 of that belongs to sellers (90% of unsettled volume) and $24.00 is the fee portion — a split worth writing down monthly, because next month's payout promises are sitting in it.
Foreign exchange lines are their own lines
Multi-currency platforms will see currency_conversion and stripe_fx_fee entries in their ledger (docs.stripe.com/reports/balance-transaction-types). Book them explicitly. Folding conversion effects silently into revenue or refund accounts guarantees a month-end variance nobody can attribute — and when a cross-currency reversal executes months after its original transfer, the conversion delta is real economics to record, not noise.
What to check on your own platform
- Run Template T1 for last month; if any payout lacks a full transaction-set match, stop and resolve before anything else.
- Write down your T2 mapping if it exists only in someone's head; date and version it.
- Compute the step-two identity for the last three months and record the residuals — a persistent small residual is a mapping bug, a large one is a leak.
- Check that refund and application-fee-refund postings land in named contra accounts, not netted inside revenue.
- Decompose your closing Stripe balance into available-versus-pending and platform-versus-seller shares; confirm the seller-share figure agrees with what you would owe if you suspended all transfers tomorrow.
Sources: docs.stripe.com/reports/balance-transaction-types · docs.stripe.com/api/balance/balance_retrieve · docs.stripe.com/api/payouts/object