Reconciliation · Data · DTC · E-Commerce

Your Shopify Shows $94k. Stripe Says $88k. QuickBooks Says $81k. Where's the Money?

Every month-end, the numbers don't match. Your accountant says "the apps don't talk to each other." Your bookkeeper says "I'll figure it out next month." Six months later you still don't know if money is missing or just mislabeled. Here's the 6-step reconciliation framework we install for DTC brands so the numbers finally line up.

Get a free reconciliation audit
No commitment. No bookkeeping access required. Clear report in 48 hours.

It was a Tuesday afternoon in May when the bookkeeper finally said it out loud. She had been running month-end for the apparel brand for almost two years, and the numbers had never matched. Shopify said the store had done $94,200. Stripe had paid out $87,940 to the bank. QuickBooks, by the time everything was categorized on Friday, had landed on $81,116. The owner kept asking the same question — "Is money actually missing, or are we just looking at three different definitions of the same number?" — and nobody could answer it. The truth, as in almost every DTC brand we audit, is that all three numbers were correct. Shopify shows gross sales. Stripe shows what hit your bank after fees and refunds. QuickBooks shows whatever the bookkeeper has had time to categorize. The gap between the three is where money quietly hides.

The fix isn't another app. It's a small set of automated reconciliation rules — running every night — that link every order, payment, fee, refund, and payout back to a single key. Once those rules are wired in (Shopify orders, QuickBooks invoices via the Intuit API, and Stripe charges), month-end stops being detective work. Below is the exact 6-step framework, including a stripped-down version of the SQL we actually run. The same data-quality discipline applied to your sales pipeline lives in our breakdown of how to clean a CRM full of duplicates and bad leads.

Worked example DTC apparel brand, 35 employees: Shopify reports $94,200 in May. Stripe paid out $87,940. QuickBooks shows $81,116 in revenue. The owner can't tell whether $13,000 is missing or just sitting in three different definitions of the same number.
1
List the Money Systems

Map every source: orders, payments, refunds, fees, taxes, payouts.

Most stores don't realize they have 5–7 different sources of money truth.

Example
"We pull shopify_orders, stripe_charges, stripe_balance_transactions (for fees), refunds, and quickbooks_invoices into one staging schema."
2
Create One Order Key

Tie records together with a stable ID.

Without one, you're chasing rounding errors for a week.

Example
"Reconcile on stripe_charge_id and shopify_order_id. Fall back to amount + date + customer email when an ID is missing."
3
Separate Sales From Cash

Split gross, fees, refunds, tax, and deposits into their own buckets.

"Revenue" isn't "cash received."

Example
"Stripe rows where balance_transaction.type = 'fee' get their own ledger. Refunds become negative entries on the original day."
4
Find the Missing Links

Surface every unmatched and duplicated row.

The unmatched rows are where money quietly walks out the door.

Example
"Flag Shopify orders with no Stripe charge within 3 days. Flag Stripe charges that don't appear in QuickBooks within 7 days."
5
Fix the Mapping Rules

Standardize SKUs, tax codes, refund logic, and bundles so the rules survive new products.

Example
"Map sku_bundle_parent to its child SKUs before counting revenue. Apply state-specific tax codes from one source of truth."
6
Build the Owner View

One daily dashboard: matched, unmatched, adjusted totals.

The owner stops asking "where's the money" because they can see it.

Example
"Daily Slack message at 8am: 'May 14: $4,812 unmatched payouts, 3 Shopify orders missing Stripe charges, 2 duplicate QB invoices.'"

What this looks like in practice

A simplified version of the daily reconciliation query we run for clients on Postgres.

SQL · daily three-way reconciliation-- Match every Shopify order to its Stripe charge and QuickBooks invoice
WITH shopify_orders AS (
  SELECT order_id, total_price, financial_status, created_at::date AS day
  FROM shopify.orders
  WHERE created_at >= CURRENT_DATE - 30
),
stripe_charges AS (
  SELECT charge_id,
         amount / 100.0 AS amount,
         metadata->>'shopify_order_id' AS shopify_order_id,
         created::date AS day
  FROM stripe.charges
  WHERE status = 'succeeded'
),
qb_invoices AS (
  SELECT invoice_id, doc_number AS shopify_order_id, total_amt
  FROM quickbooks.invoices
)
SELECT s.day,
       SUM(s.total_price)            AS shopify_gross,
       SUM(c.amount)                 AS stripe_received,
       SUM(q.total_amt)              AS qb_revenue,
       SUM(s.total_price - c.amount) AS unmatched_amount
FROM shopify_orders s
LEFT JOIN stripe_charges c USING (shopify_order_id)
LEFT JOIN qb_invoices   q USING (shopify_order_id)
GROUP BY s.day
ORDER BY s.day;
Why this approach beats the alternative   Each gate is mechanical. The system can't show you a single "revenue" number that hides $13,000 in unmatched rows — because every unmatched row is surfaced by name, every night, until it's resolved.
One KeyPer Order
DailyReconciled
Audit-SafeRecords

If any of these sound familiar

This is for you if any of these have happened in the last 90 days:

The framework above isn't theoretical — it's a checklist. Every step takes one or two days to install, and once installed it runs without you. The point is not to build a perfect ledger; the point is to make month-end boring — every row matched, every gap surfaced, every number explainable. This is also what the AICPA's audit and assurance guidance assumes you already have when an auditor comes knocking.

You don't need to switch accounting systems. You don't need to hire a full-time data person. You need the rules above, running quietly every night, surfacing the handful of rows that actually need a human's attention — and a clean audit trail that satisfies the IRS recordkeeping requirements for small businesses if you're ever asked to produce one. When those nightly rules surface a real anomaly at 3am, our overnight alert response pipeline is what turns it into a fix instead of a Monday surprise.

Get a free reconciliation review, written report in 48 hours

We'll review your Shopify, Stripe, and QuickBooks setup and send you a clear report within 48 hours showing exactly where the numbers diverge — and what each gap would take to close.

Show me where the money is
No bookkeeping access required. No commitment. Just a clear review.