Now in open beta — close the books in 2 days, not 2 weeks.Read the case study →
E-commerce · February 15, 2026 · 9 min read

Shopify refunds and COGS: the correct flow

Refunds are the single biggest cause of Shopify margin drift. The refund webhook fires, revenue reverses, and somewhere along the way COGS does not. After 200 refunds, a 38% gross margin reads as 32% on paper. The fix is to treat refunds as full inverse transactions, not as adjustments.

Full refund with restock.

A customer returns a $42 order in full. The unit goes back into sellable inventory. The original sale posted at $42 revenue with $9.80 COGS at branch A’s WAC. The refund must reverse all of it: debit Sales returns $42, credit Shopify clearing $42, debit Inventory $9.80, credit COGS $9.80. The unit returns to stock at $9.80, not at current WAC.

The reason matters. If you restock at current WAC, say $10.50, you have moved $0.70 of margin from the past period to the current one. Across hundreds of refunds, that is enough to make any month look better or worse than it actually was. Restocking at original cost is the only way to keep periods clean.

Full refund with restock — $42DEBITCREDITSales returns42.00Shopify clearing42.00Inventory (at original WAC)9.80COGS9.80TOTAL DR51.8TOTAL CR51.8
Both revenue and COGS reverse. The unit re-enters stock at the WAC it left at, not today's.

Full refund without restock.

Sometimes the unit is unsellable. Maybe it arrived damaged, maybe the customer kept the unit and got refunded as a goodwill gesture. The unit does not go back to stock. Revenue still reverses, but COGS does not. Instead, you book the cost as a separate expense, often Inventory write-off or Customer accommodation expense.

Journal: debit Sales returns $42, credit Shopify clearing $42, debit Inventory write-off $9.80, credit Inventory $9.80. The inventory ledger is correct (the unit is gone) and gross margin is honest (cost was incurred but goods did not return). Booking this as a normal restock would silently inflate stock counts.

Partial refund mechanics.

A $42 order had two units at $21 each. One is refunded. The other stays. Only one unit reverses revenue and COGS. Sales returns $21, COGS reversal at one unit times branch A’s WAC at the time of the original sale, restock of one unit. The remaining order still settles at $21 sales and one unit’s COGS.

Where merchants get this wrong is when the partial refund is a discount, not a return. A customer complains, you refund $5 as a courtesy. No goods come back. The $5 is a customer accommodation, not a sales return, and certainly not a COGS reversal. Booking it as a sales return overstates returns; booking it as a discount understates.

Shipping and tax on refunds.

Shopify lets you refund shipping or not. If shipping is refunded, the journal includes a debit to Shipping income (the inverse of the original Shipping income credit). If not, shipping stays as recognized income. Tax behaves similarly: if tax is refunded, it reverses against the same tax liability account it was originally credited to.

On a $124 order with $6 shipping and $9.92 sales tax (8% in a Wayfair state), a full refund with shipping reversed is debit Sales returns $99.40, debit Shipping income $6, debit Sales tax payable $9.92, credit Shopify clearing $124. If shipping is kept (a common policy on customer-initiated returns), the $6 shipping debit becomes zero and Shopify clearing reverses by only $118.

  • Shipping refunded: debit Shipping income for the refunded amount
  • Shipping kept: shipping income remains, only merchandise reverses
  • Tax refunded: debit the same tax payable account that was originally credited
  • Tax kept: tax stays as a liability, refund only covers net of tax

Restocking fees.

A restocking fee is income, not a reduction of returns. On a $42 refund with a $2 restocking fee, the refund to the customer is $40. Journal: debit Sales returns $42, credit Shopify clearing $40, credit Restocking fee income $2. COGS reverses normally if the unit restocks.

Booking the restocking fee as a credit to Sales returns understates returns and overstates net sales. Booking it as a credit to revenue is worse, because it confuses what category the money came from. The restocking fee is operationally a fee, a separate income line that helps merchants see whether their returns process is self-funding.

Refunds that span periods.

A March order is refunded in May. The original sale and COGS hit March. The reversal hits May. This is operationally normal but accounting-sensitive. Some accountants prefer to push refunds back to the original period; others recognize them in the current period. The principle is consistency.

For Shopify merchants, the cleanest approach is current-period recognition with a returns-aging report. You can see how much of current-period sales are likely to come back based on aging, and you can hold a returns reserve if material. Nonari aggregates this aging automatically so you can decide if a reserve is needed.

COD-specific refunds.

For cash-on-delivery orders (common in some markets and for marketplaces like Mercado Libre, Daraz, Jumia), the refund flow is operationally different. The courier attempts delivery, the customer refuses or returns the package, the courier returns it to your warehouse. Revenue was likely never recognized (you only post on delivery confirmation), so the reversal is much simpler: just don’t post the original revenue.

If you did post on order, you will need a true reversal: debit Sales, credit COD receivable, debit Inventory, credit COGS. The courier RTO (return to origin) report is the trigger. Nonari ingests RTO reports automatically and reverses the order without a manual entry.

Where Nonari fits.

Every Shopify refund webhook fires through Nonari. The system snapshots the original WAC at sale time on every order, so the refund reverses at the correct cost basis automatically. Partial refunds, shipping flags, tax flags, and restocking fees all flow through the same pipeline with separate accounts. RTO reversals on COD orders work the same way.

The result is that gross margin per period reflects what the warehouse actually did. Margin does not drift with refund volume. Refund-aging is a built-in report. Returns reserves can be set based on actual aging, not a guess. Most importantly, none of this requires the merchant to remember a single accounting rule.

Frequently asked

Common questions.

Should restocked units come back at original WAC or current WAC?

Original WAC. Restocking at current WAC silently shifts margin between periods. Nonari snapshots the order-time WAC for this reason.

How do I handle a courtesy partial refund?

Treat it as a discount or customer accommodation, not a sales return. No COGS reversal. Customer accommodation lives as its own expense or contra-revenue line.

Should refunds be pushed back to the original period?

Most Shopify merchants recognize in the current period and use returns aging to assess if a reserve is needed. Either approach is acceptable if applied consistently.

How does Nonari reverse COD orders that the courier returns?

It ingests the courier RTO report and reverses the order automatically. If revenue was never posted (delivery-confirmation policy), there is nothing to reverse; if it was, the reversal posts cleanly.

Are restocking fees revenue?

Yes, but as a separate income line, not a reduction of returns. This keeps return KPIs honest.

Try nonari

Put your books on autopilot.

Free to start. No credit card. Bring your books, kick the tires, export everything if you decide to leave.