Importing Refunds
The Refunds import issues refunds against your orders from a CSV/Excel file, a Google Sheet, or directly from another connected store. Each row resolves a real order in your store, finds its refundable line items, and creates a refund with the line items, restock and shipping you specify.
⚠️ Refunds move real money. A refund cannot be un-created — there is no update or cancel. Treat this import with care and always run the dry run (preview) first. EcomSolo defends you three ways: customer emails are off by default, the preview resolves everything without refunding, and the amount you request is validated against Shopify's maximum refundable — a request that exceeds it fails the row rather than over-refunding.
Because an order can be refunded in several line items, the import uses one row per line item — rows that share the same Order are merged into one refund. A row with no SKU / Line Item ID but a Shipping Amount refunds shipping only.
For the wizard itself — uploading, mapping, dry runs, schedules — see Importing into EcomSolo.
Columns
| Column | Notes |
|---|---|
| Order | Required. The order to refund, by name (#1001) or ID. This must be a real order in the target store — the import looks it up and reads its refundable line items. Rows sharing an Order are grouped into one refund. |
| Line Item ID | The order line-item GID/ID to refund. Optional — usually you match by SKU instead. |
| SKU | The variant SKU to refund on that order. Must be a real, still-refundable SKU on that order. |
| Quantity | How many of that line item to refund. Defaults to the refundable quantity; capped at what's still refundable. |
| Restock Type | How the refund affects inventory: RESTOCK, RETURN, LEGACY_RESTOCK, or NO_RESTOCK. Defaults to NO_RESTOCK (no inventory change). Unknown values fall back to NO_RESTOCK rather than failing the row. |
| Location | The location to restock to (ID/GID). Only meaningful when restocking; omit to let Shopify choose. |
| Shipping Amount | A specific shipping amount to refund. |
| Shipping Full Refund | true to refund shipping in full (overrides Shipping Amount). |
| Refund Amount | The total you expect to refund. Validation only — it's checked against Shopify's calculation. If it exceeds the maximum refundable the row fails; if it merely differs, the row warns and refunds Shopify's calculated amount. |
| Note | An optional note / reason attached to the refund. |
| Notify Customer | true to email the customer about the refund. Defaults to false (safe). |
Common export headers map automatically: Order Name / Name / # → Order,
Variant SKU → SKU, Qty → Quantity, Restock → Restock Type, Amount /
Total → Refund Amount, Reason → Note, Notify → Notify Customer.
How the money is calculated — the safety net
Before creating any refund, the import calls Shopify's suggestedRefund for
the exact line items and shipping in your row. That gives the calculated
amount, the maximum refundable, and the gateway transactions needed to
return the money. The import then:
- drives the actual money leg from Shopify's suggested transactions, never from the raw number in your file — so a malformed cell can't inflate a refund;
- skips an order that has nothing left to refund (a safe re-run no-op);
- fails any row whose Refund Amount exceeds the maximum refundable;
- warns (and refunds Shopify's amount) when your Refund Amount differs from the calculation.
The dry run on the Review step shows the refund / skip split — and the exact amount each row would refund — before anything is written.
How a refund is laid out
Each refund is a group of rows sharing the same Order:
- Line-item refund — one or more rows with the same Order and different SKU + Quantity. Each SKU is matched to the order's refundable line items and capped at the remaining refundable quantity.
- Shipping-only refund — a single row with just Order and Shipping
Amount (or Shipping Full Refund =
true).
Idempotency — safe to re-run (with care)
Refunds are create-only and can't be de-duplicated by matching an existing refund — a merchant may legitimately issue several partial refunds on one order. The one automatic guard is: an order with nothing left to refund (Shopify's maximum refundable is 0) is skipped. Beyond that, re-running a file will issue the refunds again, so only run each file once and preview first.
Importing from another store
On the wizard's Source step, pick From another store to copy the source
store's refunds as import rows — one row per refunded line item, grouped by
Order, with the SKU, quantity and restock type. Each row refunds the matching
line items on the target order, matched by Order name and SKU — so
both stores must hold the same orders and variants (import your Orders
first). The refund amount is not copied: the target recomputes it from
suggestedRefund, so a cross-store copy can never over-refund. Already
fully-refunded orders on the target are skipped.
Results and freshness
Refunds you create take effect in Shopify immediately, and EcomSolo's Refunds dashboard (Orders → Refunds) refreshes within seconds of the run.
Sample file
A ready-to-run sample lives under features/importing/examples/:
refunds-create-sample.csv— covers every case in one file.
Order,Line Item ID,SKU,Quantity,Restock Type,Location,Shipping Amount,Shipping Full Refund,Refund Amount,Note,Notify Customer
#1001,,HAT-BLK-01,1,RETURN,,,,,"Customer returned the hat",false
#1002,,SCARF-RED-02,2,RESTOCK,,,,,Damaged in transit,true
#1002,,SOCKS-WHT-03,1,NO_RESTOCK,,,,,Damaged in transit,true
#1003,,,,,,5.00,,,"Refund shipping only",false
#1004,,MUG-CER-04,1,RETURN,,,true,,"Full return incl. shipping",false
#1005,,TEE-GRY-05,1,NO_RESTOCK,,,,12.50,"Goodwill partial refund",false
These cover a single line-item return (#1001), a multi-line refund of
two SKUs with different restock types on one order (#1002), a shipping-only
refund (#1003), a full return including shipping (#1004), and a partial
amount refund validated against Shopify's calculation (#1005).
Swap in real values.
OrderandSKUmust resolve in your target store, so replace#1001–#1005and the sample SKUs (HAT-BLK-01,SCARF-RED-02, …) with order names and SKUs that actually exist and are still refundable. An order or SKU that can't be found produces a row-level error naming the unresolved value — the rest of the file still runs.
Troubleshooting
| Error in the report | What it means / what to do |
|---|---|
row requires an Order | Every row needs the order name or ID to refund. |
order '#1001' not found | No order with that name/ID exists in the target store — check the value. |
SKU 'HAT-BLK-01' has no refundable quantity on order '#1001' | The order has no still-refundable line item with that SKU (already refunded, or a typo). |
requested refund … exceeds Shopify's maximum refundable … | Your Refund Amount is larger than what Shopify will allow — the row is refused so nothing is over-refunded. |
has nothing left to refund … skipped | The order is already fully refunded — the row is skipped, not an error. |
FAQ
Will re-importing create duplicate refunds? Only fully-refunded orders are auto-skipped. Re-running a file with refundable orders will refund again — run each file once and preview first.
Do customers get emailed? Only if you set Notify Customer to true. It
defaults to false.
Can I refund part of an order? Yes — give each SKU its own row with a Quantity, or set a Shipping Amount for a shipping-only refund.
What if my Refund Amount is wrong? If it's higher than Shopify's maximum refundable the row fails (no over-refund). If it just differs, the row warns and refunds Shopify's calculated amount.