Klarna settlement CSVs and Shopify sales logs rarely disagree because sales disappeared. They disagree because Klarna settles captured orders on payout timing, while Shopify records orders on storefront timing and labels them with different references.
That means a clean Shopify export can still look wrong beside a clean Klarna file. One row may carry a Shopify order name. The other may carry a Klarna order_id, a short_order_id, or one of the merchant reference fields. A refund can land in a later settlement. A partially shipped order can become more than one capture. Fees, holdbacks, and reversals can reduce the payout without ever having a matching sales row in Shopify.
If you compare the two files row by row from the first tab you exported, the mismatch looks random. It is not random. You are comparing order activity, settlement activity, and payout adjustments as if they were the same thing.
The fix is to separate those layers first, choose one match key, and only then compare amounts.
Read the mismatch before you touch the data
Most failed matches fall into the same handful of patterns. Identify which one you have before you build formulas or start filtering unmatched rows.
| What you see on screen | How Klarna stores it | How Shopify stores it | What happens when you match blindly |
|---|---|---|---|
#10482 appears in Shopify, but no equal value appears in Klarna | order_id = c504a9bb-1948-46d5..., merchant_reference1 = #10482 | Name = #10482 | The order looks missing if you matched Shopify Name to Klarna order_id |
| The order date matches, but the payout date does not | sale_date = 2026-05-02T21:18:00Z, payout_date = 2026-05-04T07:45:00Z | Paid at = 2026-05-02 | The order looks delayed or missing when it is only settled later |
| A refund exists in Klarna, but not under the same capture row | type = RETURN, capture_id = "", same order_id as original sale | Refund recorded on the order or transaction history under the original order name | The refund looks orphaned if you use capture_id as the main key |
| Klarna shows negative rows that Shopify does not | type = FEE, HOLDBACK, CHARGE | No matching order row in a sales log | The settlement looks short even though the sales are fine |
| One Shopify order total becomes two Klarna sales rows | Two SALE rows with different capture_id values under one order_id | One order row or one order name in the sales log | The order looks duplicated or partially missing unless you group it first |
If your files look like more than one row in that table, that is normal. Klarna and Shopify are tracking different stages of the same commercial event. The comparison works when you decide which stage each file is responsible for proving.
Put each file on the right level first
The Klarna settlement CSV proves what Klarna included in a payout and why that payout moved up or down. The Shopify sales log proves that an order was created, paid, refunded, or adjusted inside the store. Those are related records, but they are not interchangeable.
Use the Klarna file to prove settlement composition, payment reference, and whether fees came out of the payout or were invoiced separately. Use the Shopify file to prove which orders were paid through Klarna, which order identifier belongs to each sale, and whether refunds or duplicate line-item rows exist.
| File | Keep these fields | Use it to prove | Do not use it to prove |
|---|---|---|---|
| Klarna settlement CSV | payment_reference, payout_date, type, amount, order_id, short_order_id, merchant_reference1, merchant_reference2, capture_id | Settlement composition and payout logic | That every row should have a one-to-one Shopify sales twin |
| Shopify sales log | Order name/number, payment method or gateway, paid date, refund date, amount, status | Store-side order and transaction activity | The exact makeup of a Klarna settlement payout |
This is the first place many reconciliations go wrong. The bookkeeper expects the Shopify sales file to explain fees and reserves. It cannot. Then they expect the Klarna settlement file to behave like an order export. It does not.
Choose the match key before the amount
Amounts are the last thing to compare. If the key is wrong, equal amounts only create false confidence.
The best cross-system match key is usually one of the merchant reference fields in Klarna, because those are the values submitted when the order was created. If merchant_reference1 or merchant_reference2 contains the Shopify order name or order number, use that first. If those fields are blank or unreliable, the next best option is the relationship between Klarna short_order_id and the Shopify order name.
Klarna order_id still matters, but for grouping Klarna activity across the life of one order: sale, fee, return, reversal, correction. It is not automatically the best direct bridge to Shopify because Shopify may never display that UUID. Do not use capture_id as the main key either. Returns and reversals can have it blank, and one Shopify order can produce multiple captures when fulfillment is split.
| Key | Best use | Weak point |
|---|---|---|
merchant_reference1 / merchant_reference2 | Direct match to Shopify order name or order number | Sometimes blank or inconsistently populated |
short_order_id | Fallback when Klarna and Shopify expose the same customer-facing order reference | Not always the same as the merchant's internal order name |
order_id | Group every Klarna event for one order | Usually not present in Shopify sales logs |
capture_id | Diagnose split captures and shipment-level activity | Returns and reversals can have no value here |
If the same order already has to be bridged across storefront and payout systems elsewhere in your workflow, the underlying problem is the same one described in why matching Shopify orders to payout files gets slow: the data is not failing because the amounts are wrong, but because the references and event timing drift across exports.
Build the comparison in three passes
Once the key is chosen, run the comparison in layers. Do not start with the payout total.
1. Isolate Shopify rows that belong to Klarna
Filter the Shopify sales log to the relevant gateway first. If the file contains card payments, PayPal payments, gift cards, or manual orders beside Klarna transactions, every later comparison gets noisy.
Then reduce the Shopify side to one order identifier, one paid amount, one paid date, one refund amount if refunded, and one payment status. If your Shopify export repeats an order across multiple product lines, collapse that to one order-level record before matching to Klarna.
2. Split the Klarna settlement into order-linked rows and settlement-only rows
Not every Klarna row is supposed to match a Shopify sales row. Keep order-linked rows such as SALE, RETURN, REVERSAL, REVERSAL_MERCHANT_PROTECTION, CORRECTION, and FEE separate from settlement-only rows such as HOLDBACK, RELEASE, CHARGE, CREDIT, COMMISSION, and FEE_REFUND. If you mix them together, the comparison produces fake exceptions that are really reserve movements or payout-level adjustments.
3. Compare presence first, amounts second, payout impact third
Presence is the first test. Ask whether the order exists on both sides under the chosen key.
Then compare the order economics:
- Shopify gross sale against Klarna
SALEtotal - Shopify refunds against Klarna
RETURNandREVERSALtotals - Klarna fee rows separately, not inside the gross sale match
When one order produced several SALE rows from split captures, total them by order_id before you compare to the Shopify sale:
=SUMIF(Klarna!$F:$F,F2,Klarna!$H:$H)Here column F is order_id and H is the row amount. Compare that subtotal, not each capture line.
Only after those checks pass should you tie the settlement back to the payout amount. That final step is where payment reference, payout date, holdbacks, releases, and other non-order adjustments belong.
This grouped view is the level you want:
| Order reference | Shopify sales log | Klarna settlement view | Meaning |
|---|---|---|---|
#10482 | Paid 120.00 | SALE 120.00, FEE -3.20 | Order matches; fee explains part of net payout |
#10483 | Paid 80.00, later refunded 80.00 | SALE 80.00, later RETURN -80.00 | Refund timing must be tracked separately from original sale |
#10484 | Paid 150.00 | No SALE row in current settlement | Likely not yet captured, not yet settled, or outside date range |
#10485 | One order row for 200.00 | Two SALE rows of 120.00 and 80.00 under one order_id | Partial capture; group before testing amounts |
The question is not "Do these two exports look identical?" They should not. The useful question is "Can I explain every difference at the right level?"
Separate delayed settlements from real mismatches
The most expensive mistake in this workflow is treating a timing difference as a missing sale.
Klarna exposes at least three dates that matter in practice:
sale_date: when the order was createdcapture_date: when the event was registered and, forSALE, when the goods were shipped and capturedpayout_date: when Klarna initiated the payout
Shopify sales logs often center the order or payment event instead. That means a valid order can appear in Shopify on one day, in Klarna capture rows on another day, and in the payout on a later day again.
Use this decision table when a row looks missing:
| Pattern | What it usually means | What to do |
|---|---|---|
Present in Shopify, absent from Klarna SALE rows, payment still pending or not captured | The order is not settled yet | Do not mark missing; review capture status and next settlement window |
| Present in Shopify, absent from Klarna, but other gateways appear in the same export | The gateway filter is wrong | Rebuild the Shopify subset for Klarna-only transactions |
Present in Klarna SALE rows, absent from Shopify match key | The reference mapping is wrong | Check merchant_reference1, merchant_reference2, and order-name formatting |
Present as Klarna RETURN or REVERSAL in a later settlement | A later refund or dispute is reducing a current payout | Match it back to the original order and classify as delayed negative activity |
This is also where month-end confusion starts. A Shopify sales log for April can contain orders whose cash impact hits a May Klarna settlement. That is not bad data. It is settlement timing.
If your unresolved list still contains a large block of negative or unmatched rows after you separate timing from presence, the next problem is often reference structure rather than missing sales. The same pattern shows up in other cross-platform comparisons, including finding unmatched sales between Shopify and another payment export, where the order reference exists but not in the same shape on both sides.
Handle the rows that should never be forced into a one-to-one order match
Some Klarna rows belong in the reconciliation but not in the order match grid.
FEE rows matter because they explain why sales do not equal the payout. But they are not evidence that a Shopify order is missing. They are deductions on top of matched order activity.
HOLDBACK and RELEASE rows matter because they move cash without representing new customer sales. A holdback reduces this payout to cover future risk. A release returns previously held funds into a later payout. Neither should be tested against a Shopify order amount.
CHARGE, CREDIT, and COMMISSION rows also belong in their own bucket. They can change the settlement total without meaning that the order-level sales comparison failed.
You also need to check Klarna's settlement type. If the merchant settlement type is NET, Klarna fees are deducted from the payout. If it is GROSS, the fees are invoiced separately, so your order match can be right even when the payout math differs from a net-settlement expectation. That single field changes the logic of the final cash tie-out.
A clean reconciliation therefore has four outputs, not one:
| Output | What belongs there |
|---|---|
| Matched orders | Sales and refunds that agree by the chosen order key |
| Delayed settlements | Valid orders whose settlement or payout sits in a later window |
| Settlement-only adjustments | Fees, holdbacks, releases, charges, credits, commissions |
| True exceptions | Rows that still fail after reference and timing checks |
If those four groups are clear, you are done. If they are still blended together in one unmatched tab, the comparison is not finished yet.
When the monthly comparison stops being worth rebuilding by hand
This workflow works. It also repeats the same labor every cycle: export Shopify, export Klarna, strip out non-Klarna rows, choose the same key again, regroup split orders, separate payout adjustments, and rebuild the exception list.
That is manageable when the volume is low and the payout mix is stable. It becomes expensive when every settlement contains delayed refunds, partial captures, reserve movements, and a fresh round of reference cleanup.
At that point the bottleneck is no longer accounting judgment. It is file preparation and exception sorting, and that is the part worth taking out of the spreadsheet.
