The cardigan comes back on a Thursday. Tags attached, folded the way it left, a size small that fit like a medium. The refund went out Tuesday, because the store refunds fast and is proud of it. And the product page has said sold out for a week, which matters, because a customer emailed this morning asking when the small is coming back, and the small is eleven feet from the door, in a black bin with nine other boxes, invisible to every system the store owns.
Nothing about that bin is unusual. Americans returned $890 billion of merchandise in 2024, about 17 percent of everything retail sold, and online the rate runs closer to one order in five. The industry has a name for the trip those boxes make, reverse logistics, and the name is doing a lot of work, because the forward trip has checkout, payment, a pick list, a label, and tracking, and the return trip has a bin. Every returned unit has to cross a doorstep twice. The first crossing built your revenue. The second one, nobody staffs.
Merchants meet this problem as a mystery. The count says three, the shelf says five. A customer buys a sweater that arrives smelling of someone else's perfume. The purchase order goes out for units that came back two weeks ago. Different symptoms, one disease: on Shopify, a return is a money event that is supposed to also be a shelf event, and the shelf half runs on memory.
A refund is a money event, not a shelf event
Here is the entire native machinery for putting a returned item back into inventory: a checkbox. When you refund an order, Shopify shows a Restock option, selected by default when you track inventory, and what it does is arithmetic. Tick it, and the returned quantity is added straight back to the available count at the location that originally fulfilled the order, the same minute you click. The newer returns flow separates the restock step from the refund, which mostly means there are now two moments to do half the job.
Read that mechanism against what a return actually is. Available means buyable: the unit you just restocked can be sold again before anyone opens the carton. There is no arrival check, so you can restock a box that is still in the customer's trunk, and merchants do, every day, because the refund screen is where the checkbox lives and the refund happens when the customer asks, not when the box lands. There is no condition step, so the worn one and the pristine one go back to the same shelf at the same price. And the restock lands at the location that fulfilled the order, which is a fine default exactly until your returns address and your fulfillment location stop being the same building.
Untick it, and the silence is total. Sometimes unticking is
right, the item came back destroyed, and sometimes it is
Tuesday and the queue is long. Shopify cannot tell those two
apart, keeps no queue of unrestocked returns, and never asks
again. Under the hood the API records the distinction
precisely: every refund line carries a restock type,
RETURN, CANCEL,
NO_RESTOCK, or the deprecated
LEGACY_RESTOCK, and the documentation for
RETURN promises that the returned quantity will be
added back to the available count. The data model knows exactly
what happened to every unit. It just was never asked to care
whether what happened was right.
The platform knows the word for inspection
The obvious move is to automate the gap, and Shopify Flow looks ready for it. The trigger list has a whole return section: Return requested, Return approved, Return declined, Return closed, Return processed, Return reopened. Wire them up and you can tag orders, post to Slack, and time your approvals. Then look at what every one of those triggers has in common: each fires when a person clicks something in the admin. None of them fire when the carrier scans the box at your door. The return label has tracking, the tracking hits Delivered, and that event, the only event in the whole journey that means your inventory is physically back, starts nothing, anywhere. Flow can hear your buttons. It cannot hear the doorbell.
The stranger discovery is one layer down. Since August 2023,
Shopify's Admin API has carried inventory states built for
exactly this workflow: quality_control for units
under inspection, damaged for units that failed
it, both counted inside on-hand but displayed as Unavailable,
both impossible to oversell. The documented list of inventory
adjustment reasons includes restock, defined as
adding a returned unit back to available so it can be resold,
and shrinkage, defined as actual inventory
falling short of the record through theft or loss. Which is to
say the platform has a word for inspecting a return, a word
for restocking it, and a word for what it costs you when
neither happens.
Shopify has a word for inspection and a word for skipping it. The returns flow says neither.
The returns flow touches none of them. The checkbox routes every restocked unit straight to available, no inspection state on the way, and the location it restocks to has been a community complaint for years, in threads asking to change the restock location on a return. The common shape: a 3PL in New Jersey ships the orders, returns come back to the studio in Charleston, and the checkbox faithfully adds the cardigan back to New Jersey, where a picker will eventually open an empty bin. The count is not wrong. It is right about the wrong building.
Four ways a return dies between the door and the shelf
The first death is the quiet one: the refund with no restock. Unticked deliberately, unticked accidentally, it looks the same in the ledger, which is to say it looks like nothing. The available count drifts a unit low, then four, then a size run. The product page says sold out while sellable stock sits in the bin, ads keep buying traffic to the dead page, and the story ends with the store reordering inventory it already owns, paying wholesale twice for the same cardigan.
The second death is louder: the blind restock. The checkbox cannot see inside the box, so the evening dress that went to a wedding goes back to available next to the one that never shipped, and the count is perfectly correct while the shelf is quietly poisoned. The next customer pays full price for a worn item, and now one return has become two returns, a one star review, and a support thread, which is how a single unticked inspection step compounds into a reputation problem.
The third death is geographic: the restock at the wrong building, the New Jersey cardigan. Multi-location stores hit it constantly, because return addresses and fulfillment locations diverge the moment a 3PL, a pop-up, or a second warehouse enters the picture, and the API is strict about the mismatch: a restock against a fulfillment service location it does not control simply errors. The stock exists, the count says so, and no picker will ever find it.
And the fourth death is the pile itself. A box that has landed but not been received exists in no inventory state at all: not incoming, not available, not damaged, not anything. If your policy refunds after inspection, the customer is watching a tracking page that says her return was delivered to you five days ago, composing the email that mentions a chargeback. Meanwhile the customer from this morning, the one on the waitlist for the small, buys it somewhere else at full price. The pile is small, nine boxes. What it is costing is not.
What the automation actually has to do
None of this needs heroics. It needs the job description of a good receiving clerk, executed every time: notice the box is coming, meet it when it lands, look inside before anything moves, put it where it actually is, pay the customer promptly, and write down what you saw. As a Dugong playbook, in plain prose:
# trigger
On every return, from the moment
the return label exists
# steps
1. Watch the inbound leg: the return
label's own tracking, until the
delivered scan lands at your door
2. Open a receiving task that hour:
box matched to order, items,
quantities, intake photo attached
3. Grade before anything moves: new,
open-box, or damaged, a 20 second
checklist per line item
4. Route by grade: available where the
box sits, open-box to the outlet,
damaged to the damaged state
5. Release the refund on the grade,
same hour, reason and outcome
tagged on the order
6. Chase the exceptions: labels never
scanned, boxes landed unmatched,
grades pending past 24 hours
7. Report Fridays: recovery rate,
shrinkage named, and the SKUs
that keep coming back
Step one is the trigger Shopify never built. The return label is a tracking number like any other, and the same infrastructure that watches your outbound packages can watch the inbound leg, so the delivered scan stops being a fact nobody looks at and becomes the start of a clock. The receiving task it opens is what kills the pile before it forms: every box on the bench is attached to an order, a customer, and a deadline, and a bin of anonymous cardboard becomes a queue with names.
Step three is where the judgment lives, and the point is not that AI inspects the sweater. A person opens the box; the automation makes the opening cost twenty seconds instead of a context switch. It has the order up, the photos from the customer's return request beside it, and a checklist bound to your written policy: apparel with tags attached grades new, anything opened grades open-box at 20 percent off, skincare and candles never restock regardless of seals, and anything graded damaged needs one photo for the log. The policy is a paragraph. It just has to be written down once instead of re-derived at every bench, by every temp, in every busy week.
Steps four and five are the honest bookkeeping. Sellable units go to available at the location where the box physically sits, and if the stock belongs at the 3PL, the automation drafts the transfer instead of pretending the shelf is somewhere it is not. Open-box units go to the outlet listing, which recovers most of the margin without lying to anyone. Damaged units go to the damaged state, still owned, still counted, impossible to oversell, and the true write-offs get named as shrinkage in the week they happened instead of surfacing as a stocktake mystery in January. The refund releases the hour the grade clears, tagged with reason and outcome, which is faster than the store that refunds on receipt and safer than the one that refunds on request.
Steps six and seven close the loop. The label that never got scanned gets a nudge to the customer at day seven, before the return window argument starts. The box that landed with no match gets a human, with the three most likely orders already pulled up. The grade pending past 24 hours gets escalated, because a bench backlog is a pile wearing a nicer name. And Friday's report carries the numbers this whole pipeline exists to move: what share of returned units made it back to sellable inside a week, what got written off and why, and which three SKUs keep coming back, a signal that belongs with buying before the next purchase order repeats the mistake.
Why this is a compiler problem, not an app problem
Returns apps are real products, and most of them run the front door well: the portal, the label, the approval rules, the exchange flow. We wrote about that half of the problem in June. But follow any of those flows past the label and they end at the same cliff: refund processed, restock toggled, done. The receiving dock, the grading bench, the outlet routing, the location honesty, the shrinkage ledger, the report that tells buying what to stop ordering: that is not a settings page anyone ships, because it is your policy, with your categories and your thresholds and your exceptions folded into every clause.
This is the argument behind the automations no one builds: a paragraph of judgment should compile into a running workflow, instead of being shaved down until it fits the checkboxes an app happened to ship. Run the cardigan again with the paragraph running. The label scans Thursday at 10:12 and the receiving task is open before the box is on the bench. Tags attached, graded new at 10:14, restocked at Charleston, where it sits. The available count goes from zero to one, the waitlist email goes out on the restock, and the customer from this morning owns it by lunch. The refund released at 10:15, tagged return, resellable, restocked. Or the cuff is worn: open-box at 20 off, listed by 10:20, sold by Saturday, refund released the same minute either way. Nobody argued. Nobody remembered anything. The bin stayed empty.
The workflow worth building this week
Start with the autopsy, which takes an hour. Pull ninety days of refunds and check each line's restock outcome, which the data has been recording all along. Count the lines with no restock and no note saying why. Then walk your top ten returned SKUs and compare the shelf to the count. Most stores find a low four figure sum sitting in the gap, some of it in the bin, some of it restocked into a building it never entered, and the project funds itself before lunch.
Then run the playbook in draft mode for two weeks: let it watch the inbound labels, open the receiving tasks, and propose every grade and restock without touching a count. You are auditing its judgment against yours. Does it route the worn dress where you would, hold the refund you would hold, draft the transfer you keep forgetting. When the proposals match your calls for fifty boxes straight, let the clean grades run and keep the write-offs and the weird ones for a human, which is where they belonged all along.
Then say the paragraph out loud, the way you would brief a new receiving clerk. Watch every return label to our door. Match every box the hour it lands, grade it within a day, restock it where it sits or mark it what it is. Never put anything back on the shelf without eyes on it, never make a customer chase a refund we owe, and tell me on Fridays what came back, what we recovered, and which products keep making the trip. That is the brief. The compiler turns it into the workflow, and the black bin by the door goes back to being a bin, instead of the place where your margin goes to be forgotten.
If you are a Shopify merchant with a bin like this one, a
stocktake that never reconciles, or a customer who received
someone else's return as new, the inbox is open:
field-notes@dugong.live. We are collecting case
studies for the next issue.