Do return/RMA records and their approval history migrate cleanly to Shopify's returns model or a returns app like Loop/AfterShip?
Return records do not migrate. Shopify's returnCreate mutation requires at least one fulfilled line item that has not yet been refunded, and the Return object exposes no field for backdating a request or importing prior approval history (per shopify.dev, September 2026). Historical RMAs land as order notes or a read-only archive, not as returns.
The blocking constraint, stated precisely
Shopify's returns model is built for returns you are about to process, not returns you already processed. Two documented facts close the door on importing history:
returnCreate"requires at least one fulfilled line item that hasn't yet been refunded" (per shopify.dev, September 2026). A closed RMA is, by definition, already refunded. The mutation will not accept it.- The
Returnobject carriescreatedAt,requestApprovedAtandclosedAt, but the mutations that create and approve returns take no timestamp arguments (per shopify.dev, September 2026). Even a return you could create would be stamped today.
There is one useful exception in the docs worth knowing: "If you create a return on an archived order, then the order is automatically unarchived" (per shopify.dev, September 2026). That matters for open RMAs, not closed ones.
So what do you actually do with the history
| Category of RMA | Where it goes | Why |
|---|---|---|
| Closed, refunded, resolved | Read-only archive outside Shopify, plus a summary tag or note on the migrated order | Cannot be expressed as a Shopify return at all |
| Open, item not yet received | Recreate by hand in the returns app after cutover, as a new return | Small volume, and the customer-facing state has to be right |
| Open, item received but not refunded | Refund at the old processor if its window allows, then record the refund on the migrated order | Avoids a return object that would try to restock into the wrong location |
| Warranty claims with a long tail | Archive plus a customer metafield flagging the entitlement | Warranty periods outlive the migration and nothing in Shopify models them |
Do Loop or AfterShip fix this
No, and for the same reason. Both are live and both are real options for returns going forward. Loop Returns & Exchanges lists a free Core tier, Essential at $155 per month and Advanced at $340 per month (verified on both apps.shopify.com and loopreturns.com, September 2026). AfterShip Returns & Exchanges is rated 4.7 stars across about 1,540 reviews, with a free tier, Essentials at $19 per month including 20 returns, and Premium at $119 per month including 100 returns (verified on the app listing and the AfterShip partner page, September 2026).
What neither does is invent an import path Shopify does not expose. A returns app builds its return objects on top of Shopify's orders and fulfillments. It inherits the same constraint: no fulfilled, unrefunded line item means no return to attach to.
The thing teams get wrong: approval history is a compliance artifact, not a data model
Approval history usually matters for one of three reasons, and only one of them needs the data to be inside Shopify.
- Customer service context. Solved by an order note or a tag. An agent needs to know a return happened and why, not to replay the approval workflow.
- Vendor chargeback and supplier recovery. Solved by the archive. The counterparty is the supplier, not Shopify.
- Regulatory or contractual retention. Solved by keeping the old records, in the old format, for the required period. Re-expressing them inside a new system is the version that fails an audit, because the re-expression is not the original record.
When NOT to try
- When an integrator promises to import returns. Ask which mutation. If the answer is a custom metaobject, you are paying to build an archive inside Shopify that no Shopify screen will render.
- When your return rate is high and the history is large. The archive gets better as the volume grows, not worse.
- When open RMAs number in the hundreds at cutover. Freeze new return requests for a short window instead, clear the backlog on the old platform, and migrate with an empty queue.
The Deploi point of view
Our own position, from building on Shopify. Separate from the facts above.
- Our take: Plan the returns cutover as a queue-drain, not a data migration. We scope it as three dates: last day a return can be requested on the old platform, last day it can be received there, and the day the new returns app goes live. Anything still open on the third date is recreated by hand and counted, because the count is small and the alternative is a build with no supported path.
- Where we disagree: Migration vendors list returns alongside orders and customers as a migratable object class. It is not one. Orders have an import API and returns do not, and quoting them in the same breath is how a fixed-price migration acquires an unpriced surprise in week six.
- What this page adds: that the blocker is a specific documented precondition on returnCreate plus the absence of any timestamp argument, which is why no app, including Loop and AfterShip, can offer an import path.
Reviewed by Martin Dejnicki, Director of SEO & AI Search. Facts verified 2026-09-14.
Where we worked this out
Our decision records