WooCommerce stores the sale as an order. Stripe settles the money as a batch. That is why order #1842 seems to disappear the moment you open a payout log: the order reference lives on the storefront side, while the payout rows are organized around charges, refunds, fees, and payout IDs.

Matching WooCommerce order references to Stripe payout logs becomes reliable when you stop looking for one shared column and build the bridge in the right sequence: WooCommerce order reference -> Stripe payment identifier -> Stripe payout row. Once that bridge exists, the mismatch stops feeling random.

Why the order reference does not appear where you expect

The first mistake is assuming the WooCommerce order number should appear directly inside the payout summary. In most cases it does not. The payout log is not an order ledger. It is a settlement ledger.

What you see in WooCommerceWhat you see in StripeWhat each field actually representsWhy a raw match fails
Order #1842po_1Q8...One order versus one payout batchA single payout can contain many orders
Transaction ID ch_3Nk...Source ID ch_3Nk...The same card chargeThis is usually the real bridge key, not the order number
Refund on order #1842re_1AB...A later reversal of the original paymentRefund rows do not reuse the order number
Order paid date 2026-05-06Payout date 2026-05-08Sale date versus settlement dateThe cash event happened later
Order total 124.00Net impact 119.82Gross customer payment versus net cash after feesThe payout row is lower on purpose

That table explains most failed reconciliations.

The WooCommerce order reference tells you which sale you are dealing with. The Stripe payout log tells you how money moved through Stripe and into a payout. Those are connected, but they are not stored at the same level.

Do not match the order directly to the payout ID

The payout ID is too far downstream to be your first match key.

One payout can include:

  • dozens of WooCommerce orders
  • one or more refunds from earlier days
  • Stripe fee rows
  • dispute or adjustment rows
  • transactions that settled together even though the orders were created on different dates

That means the payout ID answers a bank-level question: which group of Stripe activity became one deposit? It does not answer the order-level question: which WooCommerce order created this charge?

To match WooCommerce references reliably, split the Stripe export by row type before you try to join anything:

Stripe row typeShould it map back to a WooCommerce order?How to use it
chargeYesMatch it to the WooCommerce payment record
refundYes, but indirectlyAttach it back to the original order as a later reversal
stripe_feeNoUse it to explain the gross-to-net difference
dispute or adjustmentSometimesTreat it as an exception or downstream reduction
payoutNoUse it only for the batch and bank-level match

This is the step most guides skip. They explain what a Stripe payout is, or where Stripe IDs live inside WooCommerce, but they do not tell you that some payout rows should never be forced to match an order at all.

Build the bridge table before you reconcile

If you try to solve this with one giant spreadsheet tab, the logic gets muddy fast. A bridge table is cleaner.

Pull these fields from WooCommerce first:

WooCommerce fieldWhy you need it
Order number or order nameThe business-facing reference you care about
Paid date and timeNarrows the Stripe search window
Order totalUseful supporting evidence, never the only key
Refund statusExplains later negative rows
Payment methodConfirms the order belongs in the Stripe set
Transaction ID if presentUsually the strongest bridge into Stripe
Customer emailLast-resort support evidence

Then pull these fields from Stripe transaction or payout detail:

Stripe fieldWhy you need it
Payout IDTells you which settlement batch the row belongs to
Balance transaction typeSeparates charges, refunds, fees, and adjustments
Source IDThe object-level reference such as ch_ or re_
Created dateShows when the underlying Stripe event happened
Available or payout dateShows when funds moved toward settlement
Gross, fee, and netExplains why cash differs from order total
CurrencyCatches false mismatches in multi-currency setups
Description or metadata fieldsUseful when the order reference was passed through

Your working bridge table should look more like this:

Woo order referenceWoo transaction IDStripe source IDStripe row typePayout IDStatus
#1842ch_3Nk...ch_3Nk...chargepo_1Q8...Matched
#1843ch_3Nl...ch_3Nl...chargepo_1Q8...Matched
#1842ch_3Nk...re_1AB...refundpo_1Q9...Refunded later
fee_... or fee linestripe_feepo_1Q8...Explanation only

That table does two important things. It proves which Stripe object belongs to which WooCommerce order. It also makes clear which Stripe rows are not supposed to point back to a WooCommerce order reference.

Where to find the Stripe identifier when WooCommerce does not export it cleanly

This is the part that usually decides whether the job takes twenty minutes or two hours.

If the WooCommerce export already includes the Stripe transaction ID, use it. That is the cleanest route. But many exports do not expose it in a convenient column, so you need fallback evidence.

Use the sources in this order:

Evidence sourceWhat you can recoverReliability
Order details screenTransaction or payment identifier linked to StripeHigh
Order notesCharge, refund, or payment lifecycle IDs written during processingHigh when present
WooCommerce Stripe logsOrder number beside ch_, pi_, cus_, or src_ valuesHigh
Customer email + exact amount + time windowLikely Stripe charge candidateMedium
Order total alonePossible candidate onlyLow

If the order notes are empty, do not assume the payment never existed. The order can still be real while the metadata written back from Stripe is incomplete. That is why the logs matter. In practice, the log often gives you the crucial pair you need: WooCommerce order number on one side, Stripe charge or payment intent on the other.

Once you recover that Stripe-side identifier, the rest of the match becomes much more stable. Search the Stripe export for the ch_ or pi_ value, confirm the amount and date, then capture the payout ID attached to that row.

The workflow that holds up when the payout includes real noise

This is the sequence that avoids most false mismatches.

  1. Match the payout batch to the bank first. The payout log belongs to a cash-settlement workflow, so confirm which payout actually landed before you start tracing individual orders. If that layer is still unclear, start with how to match a Stripe payout CSV to your bank statement.
  2. Open the Stripe rows inside that one payout. Separate charge, refund, stripe_fee, and any adjustment rows before you attempt to join them to WooCommerce.
  3. Match charge rows back to WooCommerce using the Stripe transaction ID or payment intent. This is the real order-to-Stripe bridge.
  4. Match refund rows back to the original WooCommerce order as a later reversal. Do not treat negative payout rows as missing sales.
  5. Keep fee rows out of the order match. They belong in the payout explanation, not in the order bridge.
  6. Write the result as a classification, not as one big unmatched list.

That last point matters. A working reconciliation should not end with forty red cells and a guess. It should end with categories that explain what each difference means.

The failure modes that make good matches look broken

Even with the right bridge key, a few patterns still create noise.

The same amount appears more than once.

Two WooCommerce orders can both be 89.00. If you match on amount alone, you can attach the wrong Stripe charge to the wrong order. Use amount only as support, never as the primary key.

The order date and payout date belong to different periods.

Late-night orders, weekends, and payout schedules push settlement into the next day or even the next month. That is normal. The sale date and the bank date answer different questions.

A refund lands in a different payout from the original order.

This is one of the most common reasons operators think the bridge is wrong. The original charge matched correctly. The later refund reduced a different payout batch. Both rows are correct, but they belong to different moments in the cash flow.

Fee rows get forced into the order match.

Stripe fees explain why net cash is lower. They do not represent separate WooCommerce orders. If you force them into the same lookup, you create fake missing-order exceptions.

One export shows the charge ID and another shows the payment intent.

This is still workable, but it is not a direct text match. You may need to recover the missing ID from order notes or logs before the bridge becomes trustworthy.

This is the same structural slowdown described in why reconciling Shopify orders against Stripe payouts is slow. The storefront changes. The mismatch pattern stays the same: order-level data on one side, settlement-level data on the other.

What a finished reconciliation should actually show

A usable output proves the path from order reference to Stripe payment to payout batch. It does not stop at "matched" or "not matched."

CategoryWhat it means
Matched chargeWooCommerce order and Stripe charge agree
Refunded laterOriginal order matched, later refund reduced a later payout
Fee explanationCash is lower because Stripe deducted fees
Timing differenceSale and payout belong to different dates or periods
Adjustment or disputeSettlement changed for a reason outside the original order row
UnresolvedMissing ID, conflicting amount, or incomplete evidence

When you lay the output out that way, the next person does not need to reopen WooCommerce and Stripe from scratch. They can follow the chain:

  • which WooCommerce order reference was tested
  • which Stripe object confirmed the payment
  • which payout absorbed that payment
  • which rows reduced the cash before it reached the bank
  • which exceptions still need action

That is the standard to aim for. Not a workbook that happens to balance this month. A match path you can defend next month.

When rebuilding the bridge every month stops being worth it

The manual approach works when payout volume is low and the export structure stays stable. It stops working well when every close repeats the same recovery steps:

  • find missing Stripe IDs in order exports
  • search logs for ch_ or pi_ values
  • break payout rows into charge, refund, and fee buckets
  • rebuild the same bridge table again
  • rewrite the same explanations for timing and net settlement

At that point, the real work is no longer accounting judgment. It is file translation.

The core fix is not finding a smarter VLOOKUP. It is accepting that WooCommerce order references and Stripe payout logs describe different layers of the same money flow, then bridging those layers in the right order.