First ask whether the two numbers mean the same thing
An analytics dashboard says $840. Stripe shows a different total. That difference is not yet evidence that either system is broken. One might count successful customer payments while the other displays a balance, payout, recurring revenue estimate or a different reporting period. Reconciliation starts with a definition, not with editing the smaller number.
Write down the metric, account, live or test mode, currency, product scope, timezone, date boundaries and refund rule for each report. Also record when each report was refreshed. Until those fields match, a side-by-side screenshot is a comparison of labels, not a reconciliation.
Separate four financial views
For an acquisition report, a useful starting definition is gross receipts: the amount of successful payments in a stated scope. Net receipts can then subtract successful refunds according to an explicit reporting rule. Neither measure is automatically profit or recognized accounting revenue.
A Stripe balance report includes balance activity in settlement currency. A payout represents money transferred out under its own timing and grouping. Monthly recurring revenue describes a subscription run rate, not simply the cash collected this month. Use the report that answers your question rather than forcing all of them to agree.
Stripe documents the Balance summary as a balance reconciliation report and points automatic-payout reconciliation to a separate report. That distinction matters when a marketing dashboard is organized around payment dates rather than settlement dates.
A synthetic reconciliation you can audit
The following fictional USD example uses a payment-period view, with successful refunds assigned back to their original payment cohort. It excludes fees, tax adjustments, disputes, currency conversion and payouts; those need separate fields if they belong in your question. The choice is explicit so the result can be reproduced.
Payment A contributes $100, not $200, even if its notification is delivered twice. Payment B contributes $40 after its successful partial refund. The requested refund on C is still pending, so this example does not subtract it from successful-refund totals. Show that pending amount separately rather than hiding it.
SYNTHETIC USD PAYMENT COHORT
Payment Successful receipt Successful refund Pending refund
A 100.00 0.00 0.00
B 60.00 20.00 0.00
C 40.00 0.00 10.00
Gross receipts = 100 + 60 + 40 = 200 USD
Successful refunds = 20 USD
Net receipts under this rule = 200 - 20 = 180 USD
Pending refunds, reported separately = 10 USDCompare canonical objects, not notification counts
Stripe can deliver duplicate webhook events, and delivery order is not guaranteed. A robust integration verifies signatures, records processed event IDs, and updates canonical payment or refund records rather than adding revenue for every notification. Distinct event objects can also refer to the same underlying object, so event-level deduplication alone is not a complete money model.
For investigation, export the smallest mismatch set: provider account, mode, payment ID, currency, amount and relevant timestamps. Compare those rows with the provider. An unmatched payment, wrong scope or duplicated canonical record is more actionable than a percentage difference in a chart.
Treat the browser’s thank-you page as a user-interface event, not the accounting authority. It may be refreshed, blocked or never reached. The server-side payment state should establish whether money was received.
Give refunds and dates explicit rules
A refund request is not always a completed refund. Stripe documents pending and failed possibilities, and partial refunds can occur against one payment. Track refund IDs and current states rather than assuming every request immediately reduces completed receipts.
Choose between two different questions. “What happened today?” subtracts refunds processed today from payments processed today. “How much did this acquisition cohort retain?” associates refunds with the original cohort. Both can be useful. They will produce different daily totals, especially when an older purchase is refunded.
Use a half-open time interval—start included, next boundary excluded—to avoid counting a midnight payment twice in adjacent reports. Keep provider event time separate from ingestion time. A delayed delivery belongs to the stated business-time rule, not automatically to the moment your worker received it.
Keep currencies and product scope intact
Stripe API amounts use currency-specific units, including zero-decimal and special cases. Do not universally divide amounts by 100. Keep the currency beside every amount and only format it using the applicable convention.
Do not add USD and EUR into an unlabeled total. If you need one reporting currency, state the conversion source, date and rounding rule, and preserve the original amounts. Also check whether the connected account contains other products. Account-wide revenue is not automatically revenue for your particular SaaS.
Finish with an exception list, not a forced match
Classify remaining differences: delayed delivery, unresolved refund, excluded test transaction, wrong product, timezone boundary or incomplete imported history. Give each exception an identifier and an owner. Re-run the same comparison after repairs and retain the original evidence.
A reconciliation is complete when the matched population agrees under the same definitions and the remaining exceptions are explained. Marketing attribution can still be missing for a genuine payment. Keep that separate: a trustworthy money total does not require inventing a visitor source.