Back to Blog
returnsecommerceunit-economicsbugs

Returns Refund Accuracy: The Bug That Overpaid Customers

A subtle returns bug valued refunds at catalog price, not net paid, overpaying customers. Here's how I found it and the two rules that fixed returns refund accuracy.

By Mike Hodgen

Short on time? Read the simplified version

The refund that should have been $9.37 was $52

A customer returned a single item to my DTC fashion brand. The system processed the return and tried to refund $52. Clean transaction, no errors, customer happy.

Waterfall diagram showing how a $52 catalog price drops to $9.37 net paid after line and order discounts, revealing a $42.63 refund overpayment Catalog price vs net paid breakdown

The problem: that customer never paid $52. They paid $9.37.

The item carried a line-level markdown and the order had a sitewide coupon stacked on top. By the time the discounts shook out, the actual net price for that piece was under ten bucks. But the returns system valued it at full catalog price and was about to hand back $42.63 we never collected in the first place.

One return. One overpayment. Not a catastrophe.

Except this isn't one return. Most of my orders carry some kind of discount. A seasonal code, a markdown, a free-gift threshold, a returning-customer offer. If the returns refund accuracy bug fires on every discounted return, and most returns come from discounted orders, the leak doesn't stay small. It compounds quietly, return after return, month after month, while every dashboard says everything is fine.

What made it worse is that this wasn't one bug. It was two distinct failures that happened to live in the same valuation path. The first overpaid refunds by using catalog price instead of net paid. The second leaked store credit on exchanges through price drift, and could stack credit every cycle if a customer swapped sizes more than once.

Either one alone is expensive. Together they bleed money in a way that looks perfectly healthy from the outside.

Let me walk through both, how I caught them, and the fix. Then I'll give you a checklist to test your own returns math this week, because there's a real chance this is happening to you right now and your reports wouldn't show it.

Why catalog price is the wrong basis for a refund

The core mistake is simple to state and easy to miss: returns were valued at catalog price, not at what the customer actually paid.

What the customer actually paid

Net paid is the real number. It's the catalog (list) price minus every discount applied to that line item, allocated proportionally across the cart. Catalog price is the sticker, the list value, the number before any discount touches it.

Those two numbers can be wildly different. And the gap between them is exactly the money you give away when you refund on the wrong basis.

How discounts disappear in the math

Discounts come in two layers, and both have to be subtracted.

Line-level discounts are item-specific. A markdown on that one product, a clearance price, a bundle adjustment. These reduce what the customer paid for that exact item.

Order-level discounts apply to the whole cart. A 20% sitewide code, free-gift logic that effectively spreads value across items, a threshold reward. These have to be allocated down to each line proportionally so you know what share of the discount belongs to the item being returned.

Run the arithmetic on my $52 item. Apply a line markdown that drops it to $26. Then spread a sitewide code and a free-gift adjustment across the cart, and that item's share of the order-level discount pulls its net price down under $10. The customer paid $9.37.

Refund the $52 and you've handed back $42.63 you never received. That's not a refund, that's a gift.

This is the single most common returns refund accuracy failure I see. The catalog price is sitting right there in the product record, easy to grab, and someone wired the refund logic to use it because it was the obvious number. Obvious and wrong.

The second leak: exchanges that stack credit every cycle

The first bug overpays. The second one is sneakier, because it leaks through exchanges in a way that nobody audits.

Comparison of two refund bugs: catalog-price overpayment versus exchange price-drift store credit leakage Two distinct refund bugs in one valuation path

The price-drift trap

A customer returns a medium and wants a large of the identical product. Same item, same color, just a different size. This should cost nothing. It's an even swap.

But the exchange pricing bug valued it as the difference between what the product cost at order time and what it costs now. Prices drift. If the item went up since they bought it, the customer technically owed the difference, except the system often just ate it. If the item dropped in price, the system handed the customer credit for a pure size swap.

They returned a medium, got a large, and walked away with store credit. For nothing. Because the price happened to move.

Exchange-on-exchange compounding

Here's where it gets ugly. Price drift accumulates.

Flow diagram showing how repeated even-swap exchanges accumulate store credit from price drift across multiple cycles Exchange-on-exchange credit compounding

A customer who exchanges, then exchanges again, could stack credit each cycle. First swap captures one chunk of drift. Second swap captures more. Each event looks tiny in isolation, a dollar here, a few dollars there, so nothing ever trips a flag.

That's store credit leakage in its purest form. A slow drip nobody audits, because every individual event is too small to notice and the customer is genuinely happy. They're not committing fraud. The system is just quietly minting credit out of price movement. I wrote about another returns valuation bug leaking store credit that worked the same way, because these failures travel in packs.

How I caught it (and why it hid so long)

Nothing tripped an alarm. That's the part operators need to sit with.

Refunds completed successfully. Customers got their money, sometimes more than they should have, and nobody complains about that. Support saw clean transactions. The returns flow looked healthy by every operational measure. No error logs, no failed payments, no angry tickets.

The only signal was margin running quietly below model on discounted cohorts. Not dramatically. Just enough that when I looked at profitability on heavily discounted orders, the numbers didn't match what the pricing model predicted. A few points off, consistently, in a direction I couldn't immediately explain.

I found it by auditing the returns valuation path line by line, not from a complaint. I traced what number the refund logic was actually using and watched it grab catalog price instead of net paid. Then I found the exchange drift problem sitting right next to it.

This is the trust point I want every operator to internalize: a returns process can overpay for months and look perfectly healthy, because the failure mode is silence, not errors. Errors get noticed. Overpayments don't. The customer is happy, the transaction succeeds, and the only victim is your margin, which doesn't file a complaint.

Money-moving logic should be provable, not just functional. It's the same principle behind why I build a ledger that can't be wrong. If you can't read the math and prove the number is correct, "it ran successfully" means nothing.

So let me answer the doubt directly. Yes, this could be happening to you right now. Your dashboard wouldn't show it. Your support team wouldn't catch it. Your customers definitely won't tell you. The money just leaves.

The fix: two composing rules and a tamper hole closed

The fix is two rules that compose cleanly, plus closing a security hole I found along the way.

Vertical diagram of the fix: net-paid refund rule, zero-cost even-swap rule, and server-side price derivation to close the tamper hole The fix: two composing rules plus server-side derivation

Rule one: net-paid basis

Every refund and every credit is now valued at net paid, not catalog. That means catalog price minus all line-level discounts, minus the item's proportional share of all order-level discounts, allocated across the cart.

The system computes what the customer actually paid for that specific item, down to the cent, and refunds exactly that. No more, no less. My $52 phantom refund became the correct $9.37.

Rule two: same-product even-swap at zero

Returning size X for size Y of the identical product is forced to settle at exactly zero. No price-drift math allowed. No "what does it cost now" comparison.

If it's the same product in a different size, it's an even swap by definition. The exchange pricing bug had room to operate because the system was doing arithmetic it never should have done. Removing the arithmetic removes the leak. A size swap costs nothing, every time, regardless of how prices moved.

Closing the client-tamper hole

While I was in there, I found a second problem. The refund price was being computed from values that could come from the client side of the request. That's a tamper hole. A manipulated request could inflate the refund amount, and the system would honor it.

So I derived the price server-side from a re-fetched order record. The system pulls the real order, recalculates net paid from the source of truth, and ignores any value passed in from the client. You can't tamper with a number the server refuses to trust.

Why compose rules instead of patching one bug at a time? Because patches don't generalize. If I'd just fixed the catalog-price refund, the exchange drift would still leak. If I'd fixed both as one-off patches, the next discount type or exchange flow would reopen the same wound. Two clean rules that always hold, applied to every refund and every exchange, close the entire class of failure instead of the specific instances I happened to find. This fix lives inside the system where I rebuilt our returns intake from scratch, so the rules apply everywhere a return touches money.

How to check your own returns math this week

You don't need me to find out if this is happening to you. Here's the audit any operator can run in an afternoon.

Three-step vertical checklist for auditing returns refund accuracy: sample discounted returns, test a size swap, and confirm server-side pricing Three-check returns audit you can run this week

Pull a sample of discounted returns

Grab 10 to 20 recent returns from orders that carried any discount. A markdown, a coupon, a free-gift threshold, anything that reduced the price.

For each one, compare the refund amount to what the customer actually paid net of discounts. Calculate net paid the way I described: catalog minus line-level discounts minus the proportional share of order-level discounts. Any refund above net paid is leakage, plain and simple. If you find even two or three in a sample of twenty, you have a structural problem, not a one-off.

Test a same-product size swap

Run a real test exchange. Return one size for another size of the identical item and watch what the system does.

It should settle at exactly zero. If it produces any number based on current versus original price, you have the exchange pricing bug. Confirm it does the same on a second consecutive exchange, because that's where the compounding store credit leakage lives.

Confirm prices are computed server-side

Check where the refund number comes from. If your returns logic accepts a price or amount passed in from the client, that's a tamper hole. The refund value should be derived server-side from the order record every time, never trusted from the request.

Three checks. One afternoon. That's all it takes to answer the question "is my returns process overpaying?" with actual evidence instead of a hopeful guess.

Most returns leaks are invisible until someone reads the math

Here's the structural truth. Returns refund accuracy fails silently, and the businesses bleeding the most money on it are the ones with the most discounting and the most exchanges. That describes most DTC brands. That describes mine.

This isn't an edge case you can ignore until you scale. The more you discount, the bigger the gap between catalog and net paid, which means the bigger every overpaid refund. The more exchanges you process, the more price drift accumulates into leaked credit. The structure of a healthy, promotion-driven ecommerce business is exactly the structure that maximizes this leak.

The fix took three things: clean composing rules, server-side derivation of every money value, and someone willing to read the valuation path line by line. None of it showed up in a dashboard. All of it showed up in margin once it was fixed.

I build and audit this kind of money-moving logic across the brands I run and the clients I work with. If you just realized your returns might be quietly overpaying, the next step is simple: have me audit your returns math and we'll find out what the silence is costing you.

Want to explore what AI could do for your business?

Book a free 30-minute strategy call. No pitch deck, no sales team, just a real conversation about your operations and where AI actually fits.

Book a Discovery Call

Get AI insights for business leaders

Practical AI strategy from someone who built the systems — not just studied them. No spam, no fluff.

Ready to automate your growth?

Book a free 30-minute strategy call with Hodgen.AI.

Book a Strategy Call