TL;DR
Stripe pays you the net of charges minus fees minus refunds. Your FreshBooks invoice is gross. Don’t match payout total to invoice total — match the underlying charge to the invoice, then verify the payout sum reconciles to the bank deposit. Pull the Stripe Balance Transactions export, not just Payouts.
What breaks when reconciling Stripe with FreshBooks
Four landmines, in order of how much pain they’ve caused us:
The gross-vs-net trap. You raise a $1,000 invoice. The client pays via Stripe. Stripe deducts $29.30 (2.9% + $0.30) and pays out $970.70 a few days later. Your bank shows $970.70 on April 18. Your FreshBooks invoice says $1,000.00. If you match bank-deposit-to-invoice-amount, the math will never reconcile.
Payouts batch many charges. A typical Stripe payout doesn’t represent one charge — it represents every charge that cleared the rolling-payout window. A single $4,732.18 bank deposit can correspond to 47 different invoices. You can’t reconcile this on the payout view alone; you need the per-charge Balance Transactions export and the join logic.
Refunds and disputes net out of future payouts. If you refund a customer on April 22, the refund doesn’t reduce the April 22 payout — it reduces whichever payout is currently rolling (often the next one). Your April 25 payout will be $X minus the refund. If you don’t track this offset, you’ll mis-attribute the missing amount.
FreshBooks Stripe integration auto-marks paid. If you have FreshBooks Payments (or the Stripe integration) enabled, FreshBooks auto-marks invoices Status = Auto-Paid the moment Stripe confirms the charge — before the payout hits your bank. Our CSV-side reconciliation might still flag these as “to verify” because the bank-side cash event hasn’t happened yet.
Export the Stripe data
You need two exports, not one:
1. Balance Transactions (the per-charge detail):
- Stripe Dashboard → Reports → Balance → All transactions → date range → Export.
- File saves as
Itemized_balance_change_from_activity_<range>.csv.
Columns (the useful subset): Balance Transaction ID, Type, Source, Amount, Fee, Net, Currency, Created (UTC), Available On (UTC), Description, Customer Email, Customer Description, Card Brand, Card Country, Invoice ID, Invoice Number, Payout ID. The Invoice Number field is the Stripe-side invoice number, which only equals your FreshBooks invoice number if you set it explicitly during charge creation.
2. Payouts (the per-bank-deposit summary):
- Stripe Dashboard → Payouts → Export.
- Columns:
Payout ID,Date,Amount,Currency,Status,Description,Statement Descriptor.
Reconcile in two passes: payouts ↔ bank deposits (1:1), then balance-transactions ↔ FreshBooks invoices (N:1 grouped by Payout ID).
Export the FreshBooks invoice list
- FreshBooks → Reports → Invoice Details.
- Date range, all statuses, Export to CSV.
Columns relevant here: Date, Invoice Number, Client, Amount, Currency, Status, Outstanding, Date Paid, Payment Type. Payment Type will show Stripe for FreshBooks-via-Stripe charges, Other for manually-recorded payments.
For invoices paid via Stripe directly (not through the FreshBooks integration), Payment Type may be Other or blank — those need the per-charge match.
Match algorithm cheats for this combo
- Payout ↔ bank deposit. Match Stripe
Payouts.Amount↔ bank deposit amount, with date offset of 1–2 business days for theAvailable Ondate. Stripe sends one deposit per payout per currency. - Group balance transactions by Payout ID. For each Stripe payout, find all
Balance TransactionswherePayout IDmatches andType = charge. Sum theirNetamounts — it should equalPayouts.Amount(within rounding). - Match each charge to a FreshBooks invoice. Primary:
Balance Transactions.Invoice Number↔ FreshBooksInvoice Number(exact). Fallback:Customer Email↔ FreshBooksClient(via a lookup table, since FreshBooksClientis name not email). Fallback again:Amount(gross, before fees) ↔ FreshBooksAmountwithin ±$0.05. - Subtract fees explicitly. When reporting per-invoice cash received, use
Netfrom Stripe, notAmount. TheFeeis a real expense — it should hit your P&L as Stripe processing fees, separate from the AR clearing. - Handle refunds as offsets. For each
Type = refundrow in Balance Transactions, find the original charge bySource, locate the original invoice, and reduce the cash-received-to-date by the refund amount.
Real example
A real April 2026 Stripe payout for $4,732.18 corresponded to 7 charges. The Balance Transactions export showed:
txn_abc1, charge, ch_xyz1, 1000.00, 29.30, 970.70, USD, 2026-04-15 09:23, 2026-04-18, "INV-2026-411", , in_xyz1, INV-2026-411, po_april18
txn_abc2, charge, ch_xyz2, 500.00, 14.80, 485.20, USD, 2026-04-15 14:11, 2026-04-18, "INV-2026-412", , in_xyz2, INV-2026-412, po_april18
... (5 more charges) ...
FreshBooks for the same window:
2026-04-01,INV-2026-411,Acme LLC,1000.00,USD,Paid,0.00,2026-04-15,Stripe
2026-04-01,INV-2026-412,Beta Corp,500.00,USD,Paid,0.00,2026-04-15,Stripe
Match: each Stripe charge → matching FreshBooks invoice by Invoice Number. Sum of Net (970.70 + 485.20 + …) = $4,732.18 = the bank deposit on April 18. Reconciles end-to-end. Confidence: Exact.
Edge cases this combo hits
Currency conversion. Stripe accepts payment in any currency, settles to your account in your payout currency. The Balance Transactions export has Currency (the customer’s currency) and a separate Settled Currency for the converted amount. FX conversion fees are bundled into the Fee field but the customer-side amount is the original currency.
Application fees (Stripe Connect). If you’re a platform charging connected sellers, your application fee appears as a separate Type = application_fee balance transaction. These are revenue to your platform, not cost — different P&L treatment. Filter them out of the AR reconciliation.
Failed payouts. If a payout fails (wrong bank info, account closed), Stripe marks Status = failed and credits the funds back to your Stripe balance. The next successful payout absorbs them. Reconcile only Status = paid payouts against the bank.
Manual top-ups. If you ever add funds to your Stripe balance manually (rare, but used for funding refunds when your balance is empty), there will be a Type = adjustment row. Excluded from charge-to-invoice matching.
FreshBooks Auto-Paid timing. FreshBooks marks Status = Auto-Paid on the charge date, not the payout date. So an April 15 charge appears paid in FreshBooks on April 15 even though the cash hits the bank on April 18. Our reconciler will note the mismatch but mark it correctly as Paid based on the bank-side event.
When this combo breaks our tool
We auto-pair Payouts with Balance Transactions when both are uploaded together. If you only upload the Payouts file, we can verify deposit amounts but not match per-invoice — you’ll see all invoices as “Unverified”. Upload both.
If your Stripe account uses multiple Settlement currencies (USD + EUR payouts both going to a single multi-currency bank account), our matcher needs each currency uploaded as a separate file pair. Single-file multi-currency Stripe handling is on the roadmap, not shipped.
When FreshBooks Payment Type = Stripe is set but the invoice has been manually edited (e.g., a $50 discount added after the charge), the FreshBooks Amount won’t match the Stripe charge Amount. We flag these as “Likely paid, amount mismatch” — manual review required.
Faster way
Drop both Stripe exports (Payouts + Balance Transactions) and the FreshBooks invoice CSV into the reconciler on the homepage. The gross-vs-net unpacking, the payout-aggregation reconciliation, and the per-charge invoice matching all run in one pass.
For a deeper view of the Stripe payout flow specifically (without the FreshBooks side), the dedicated Stripe payout reconciliation tool handles charge-level audit cases.
If you’re still on the fence about whether to switch invoice tools, the free bank reconciliation software audit compares the integrated options.