Skip to main content

Merge Bank, Stripe, and PayPal CSV Exports for Monthly Reconciliation

10 min readPipeSheets Team

To reconcile bank, Stripe, and PayPal CSV exports for a month, do not stack the three files on top of each other. A Stripe payout and a PayPal transfer each appear twice across your sources: once as the processor's settlement row and again as the matching deposit on your bank statement. If you sum all three exports as-is, you count that money twice. The fix is to treat one source as the ledger of gross sales and fees (Stripe and PayPal), treat the bank statement as the record of cash actually landing, and then match each processor payout to its bank deposit so it is reconciled, not re-added.

This is a three-source reconciliation, which is different from building a single combined cash-flow sheet from two files. The goal here is not one merged spreadsheet of every line. The goal is to confirm that every dollar Stripe and PayPal say they paid you actually arrived in the bank, flag anything that did not, and account for refunds and disputes that reduce a payout. Everything below assumes you have downloaded a month of activity from all three and are staring at three CSVs with completely different column names.

Why does merging the three exports double-count revenue?

Each payment processor works as a holding account. When a customer pays, the money sits in your Stripe or PayPal balance. On a schedule (daily, weekly, or on demand), the processor sweeps that balance to your bank as a single payout or transfer. So one $980 Stripe payout on the 14th is the net result of dozens of individual charges minus fees minus refunds. That same $980 shows up on your bank statement two business days later as one deposit line.

If your merged file contains the Stripe charges (which sum to the gross sales), the Stripe payout row, and the bank deposit, you now have the same economic event represented three ways. Add a naive SUM across the amount column and your revenue balloons. The rule that keeps you honest: gross sales and fees come from the processor exports; cash arrival comes from the bank; the payout line is the bridge between them, not additional income.

The single most common reconciliation mistake is importing both the Stripe payout export and the bank statement into accounting software as separate income. The bank deposit is the Stripe payout. Match them; never book both as revenue.

Step 1: Normalize each export to a common schema

You cannot match rows across files whose columns do not line up. Stripe, PayPal, and your bank each name the same concepts differently, format dates differently, and put fees in different places (PayPal splits fee into its own column; a bank statement has no fee column at all). Map every export onto one target schema first, then match.

Here are the raw column names you will actually see. Stripe's itemized Payout reconciliation report uses machine-style identifiers; PayPal's Activity Download uses title-case labels; a typical bank CSV uses whatever the bank felt like that day.

# Stripe - Payout reconciliation report (itemized), typical columns
balance_transaction_id, created_utc, reporting_category, currency,
gross, fee, net, automatic_payout_id, automatic_payout_effective_at_utc,
charge_id, customer_facing_amount

# PayPal - Activity Download (CSV), typical columns
Date, Time, TimeZone, Name, Type, Status, Currency,
Gross, Fee, Net, Balance, Transaction ID, Reference Txn ID

# Bank statement export (varies wildly by bank)
Date, Description, Amount, Running Bal.
# or: Posting Date, Details, Debit, Credit, Balance

Now collapse all three onto one target schema. Every row, regardless of source, ends up with the same fields:

# Target schema (one row per line item, tagged by source)
date, description, gross, fee, net, reference_id, source, row_type

# Stripe charge row ->
2026-06-14, "Charge ch_3Ab...", 42.00, 1.52, 40.48, po_1Kx..., stripe, charge

# Stripe payout row ->
2026-06-16, "Payout to bank",  0.00, 0.00, 980.15, po_1Kx..., stripe, payout

# PayPal sale row ->
2026-06-14, "Jane Doe",        30.00, 1.28, 28.72, 8XJ9..., paypal, charge

# PayPal transfer to bank ->
2026-06-17, "Bank Deposit",     0.00, 0.00, 412.40, 8XJ9..., paypal, payout

# Bank deposit rows ->
2026-06-18, "STRIPE TRANSFER",  0.00, 0.00, 980.15, ,        bank,   deposit
2026-06-19, "PAYPAL TRANSFER",  0.00, 0.00, 412.40, ,        bank,   deposit

The source and row_type tags are what make the reconciliation possible. You will match stripe/payout rows to bank/deposit rows, and paypal/payout rows to their bank/deposit rows, while leaving the charge rows out of the cash total entirely.

Mapping Stripe columns

For the Stripe payout reconciliation report, map fields like this:

  • created_utc or automatic_payout_effective_at_utc becomes date (the effective date is what to match against the bank).
  • gross, fee, and net map straight across; Stripe already gives you all three.
  • automatic_payout_id becomes reference_id, and it is the same ID on every line item swept into one payout, which is how you group charges to a payout.
  • reporting_category (charge, refund, payout, dispute, etc.) helps you set row_type and handle deductions.

Mapping PayPal columns

For the PayPal Activity Download, map fields like this:

  • Date maps to date; note PayPal reports in the account time zone shown in the TimeZone column, so a late-night sale can land on a different calendar day than Stripe.
  • Gross, Fee, and Net map across; PayPal fees are already negative or shown in the Fee column.
  • Transaction ID becomes reference_id for a sale; the withdrawal/transfer row has its own Transaction ID.
  • The Type column tells you what a row is (Website Payment, General Withdrawal, Transfer, Refund, Chargeback), and Reference Txn ID links a refund back to the original sale.

Mapping bank columns

The bank is the messiest. Some banks give one Amount column with negatives for debits; others split Debit and Credit. Collapse split columns into a single signed net, parse the date to ISO (YYYY-MM-DD), and keep the raw Description because the processor name in it (STRIPE, PAYPAL, PAYPAL TRANSFER) is your only clue to which deposit belongs to which processor. Bank rows have no fee and no reference ID, so those fields stay blank.

Step 2: Match payouts to bank deposits

With everything on one schema, matching is a three-signal join between processor payout rows and bank deposit rows. Rely on any single signal alone and you will mis-match; use all three and confidence is high.

Match a stripe/payout or paypal/payout row to a bank/deposit row when all of the following line up:

  • Amount: the payout net equals the bank deposit amount to the cent. This is the strongest signal.
  • Date window: the bank deposit posts within a plausible lag of the payout, usually 1 to 3 business days after the effective date. Do not require the same day.
  • Reference or description: the bank description contains the processor name (STRIPE, PAYPAL), and where the bank surfaces it, the last four of the payout ID or a statement descriptor confirms the exact payout.

Amount plus date window catches the vast majority. The description check breaks ties when two payouts happen to be the same amount in the same window, which is common for subscription businesses with steady daily payouts. When two candidate deposits both match on amount and window, the descriptor or payout ID is the decider.

A practical tactic: build a match key of source plus rounded amount plus effective date, then look for the bank deposit whose amount equals the payout net and whose date is greater than or equal to the effective date but within three business days. Mark each matched pair with a shared reconciliation ID so you can prove the link later.

Step 3: Flag unmatched rows for review

Reconciliation is really about the exceptions. After matching, three buckets remain, and each means something specific.

Investigate every row that did not match:

  • Processor payout with no bank deposit: the money is in transit (payout near month-end that lands next month), a payout failed, or the deposit posted under a description you did not search for. Month-boundary timing is the usual culprit.
  • Bank deposit with no processor payout: a deposit from a source you did not export (a second Stripe account, a manual transfer, a customer ACH), or a payout export that did not cover the full date range.
  • Amount mismatch on an otherwise obvious pair: a refund or dispute reduced the payout after the fact, or a currency conversion changed the landed amount. Reconcile the difference, do not ignore it.

Set a small tolerance only for known rounding or FX, and even then flag it rather than auto-clearing. An unexplained few cents today is a systematic error next quarter.

How do refunds and disputes affect the match?

Refunds and disputes are why a payout net rarely equals the gross sales for the same period. In Stripe, a refund appears with reporting_category of refund and a negative gross, and it is deducted from whatever payout it settles in, not necessarily the payout that carried the original charge. In PayPal, a refund is its own row with a Type of Refund and a Reference Txn ID pointing at the original sale; a chargeback shows as a separate reversal row.

Because a refund can hit a later payout than the sale, do not try to net a refund against its original charge across periods. Instead, treat each payout as a settled batch: the payout net already reflects every charge, fee, refund, and dispute that settled in it. Reconcile the payout net to the bank deposit, and let the itemized rows explain how the processor arrived at that net. This is exactly why the payout ID grouping matters: it tells you which deductions belong to which deposit.

A monthly reconciliation checklist

Run this sequence every month for a clean three-way reconciliation:

  • Export the full month from all three sources using the effective/settlement date, not the created date, so payouts near the boundary are captured.
  • Normalize each file to the target schema (date, description, gross, fee, net, reference_id, source, row_type).
  • Confirm dates are ISO YYYY-MM-DD and amounts are real numbers, not text with currency symbols or thousands separators.
  • Tag every row's source and row_type; separate charge/sale rows from payout/transfer rows from bank deposit rows.
  • Match each processor payout to its bank deposit on amount, date window, and description.
  • List unmatched payouts, unmatched deposits, and amount mismatches on a review tab.
  • Explain each exception (in transit, refund, dispute, FX, missing export) before you close the month.
  • Book gross and fees from the processors and cash from the bank, never both, so revenue is not double-counted.

Clean the exports before you merge them

The matching logic only works if the underlying data is clean, and raw exports rarely are. Bank descriptions carry trailing whitespace that breaks a text match on STRIPE. PayPal amounts sometimes import as text because of a currency symbol or a thousands separator. Empty rows and repeated header blocks from a multi-page bank statement quietly throw off a SUM. Column names differ across every file, so even lining them up is manual work.

This is the prep stage where PipeSheets helps. You can trim whitespace across every column, standardize the null values that banks scatter through empty cells, drop fully empty rows and columns, and normalize headers to a consistent snake_case in one Quick Clean pass, then preview the before and after before you download. For the per-source mapping, a saved pipeline can rename each export's columns to your target schema, reorder them to match, and find-and-replace inconsistent labels, so the Stripe, PayPal, and bank files all come out with identical headers ready to stack and match.

PipeSheets also exports CSV or XLSX without the damage Excel does to this kind of data, so payout IDs and reference IDs keep their leading zeros and long numeric IDs are not silently converted to scientific notation. Clean each of the three exports to the same schema first, and the reconciliation itself, matching payouts to deposits and flagging the exceptions, becomes a short, dependable routine instead of a monthly scramble.

Try the automated solution

PipeSheets can fix these issues automatically. Clean your first file free.

Clean Your CSV