The Shopify – NetSuite D2C template aligns with Shopify's native exchanges and returns workflow using Shopify's GraphQL Return APIs. This support applies to both online and POS orders.
For return scenarios, a Return Authorization (RA) is created in NetSuite for the returned line items. For exchange scenarios, a new NetSuite order (Sales Order or Cash Sale) is also created for the exchange line items, matching the record type of the original order.
Shopify's native exchange model allows merchants to process returns and add exchange items directly within the original order in Shopify Admin. Instead of creating a separate replacement order manually, merchants can:
-
Open an existing order.
-
Initiate a return.
-
Select the items being returned.
-
Add exchange items within the same return workflow.
-
Process any price difference (a refund or an additional charge).
When processed this way, returned and exchanged items remain linked to the original Shopify order. Inventory restocking follows the restock settings selected during return processing.
To sync Shopify's native exchanges and returns with NetSuite, the template uses three coordinated flows. Each flow manages a specific stage of the lifecycle.
|
Flow |
Type |
What it does |
|---|---|---|
|
Flow 1: Shopify requested returns to NetSuite return authorization (add) |
Scheduled |
Creates Return Authorization in NetSuite when a return is requested in Shopify |
|
Flow 2: NetSuite pending receipt RMA to approved return in Shopify |
Scheduled |
Syncs NetSuite approval decisions back to Shopify |
|
Flow 3: NetSuite received RMA to process return and exchange in Shopify |
Scheduled |
Processes the return in Shopify after items are received in NetSuite and issues a refund |
|
Flow 4: Shopify hold fulfillments on payment pending release |
Scheduled |
Manages fulfillment holds for upsell exchanges |
Together, these flows ensure that:
-
Returns created in Shopify are reflected in NetSuite as Return Authorizations.
-
Approvals made in NetSuite are synced back to Shopify without manual intervention.
-
Refunds are issued in Shopify only after returned items are physically received in NetSuite, maintaining financial accuracy.
-
Return Authorizations must be enabled in NetSuite (Setup > Company > Enable Features > Transactions > Return Authorizations).
-
The eTail custom fields must be enabled on the NetSuite Return Authorization and Item Receipt forms (see NetSuite Prerequisites).
-
The NetSuite bundle (81289) must be installed and up to date.
-
The Shopify connection must be re-authorized to grant the
read_returnsandwrite_returnsAPI scopes. -
The original sales order or cash sale must exist in NetSuite with the Shopify Order ID in the eTail Order ID field before any return flows are run.
Important
The NetSuite saved searches included with this D2C template are managed by the Celigo bundle (ID 81289). When Celigo releases a bundle update, any changes made directly to these saved searches will be overwritten, which can break your integration flows. Before making any changes to a template saved search, clone it first and use the cloned copy in your flow. Do not modify the original template saved searches directly. This ensures your customizations are preserved when the bundle is updated. To clone a saved search in NetSuite: open the saved search > click More > select Copy.
-
Even, upsell, and downsell exchanges: Creates exchange orders as Sales Orders or Cash Sales matching the original order type.
-
Multi-location exchange support: Returns and exchanges across multiple locations are supported using the Locations mapping.
-
Restocking fee handling: If a restocking fee is configured in Shopify, it is synced to NetSuite as a line item on the RA using the NetSuite item to track Shopify restocking fee setting.
-
Return shipping fee handling: The return shipping fee from Shopify is synced as a line item on the RA using the NetSuite item to track Shopify return shipping fee setting.
-
Unverified returns: Returns where the returned items cannot be individually identified (for example, POS returns without item-level detail) are handled as unverified returns. For unverified returns, the RA is created with status Pending Receipt, using line items with
currentQuantity < 0on the original order.
This scheduled flow exports returns that have been requested in Shopify and creates corresponding Return Authorizations in NetSuite.
How the flow works
-
For each return line item, the script finds the corresponding NetSuite line (matched by
stOrderLineId) and calculates the rate usingoriginalUnitPriceSet. -
Cart-level discounts on return lines are calculated by finding the
Celigo_Discount_Line_entry on the original NetSuite order and applying it proportionally. -
Restocking fees are added as separate RA lines using the configured
NetSuite item for restocking fee. -
Return shipping fees are added as a single RA line using the configured
NetSuite item for return shipping fee. -
The RA location is determined using the
reverseFulfillmentOrders[0].lineItems[0].dispositions[0].locationfrom Shopify, falling back to the returnable fulfillment location if not available.
-
When disabled (default): Shopify status REQUESTED maps to NetSuite RA status Pending Receipt; OPEN maps to Pending Receipt; CLOSED maps to Closed.
-
When enabled: REQUESTED maps to Pending Approval; OPEN maps to Pending Receipt; CLOSED maps to Closed.
-
Get returned orders from Shopify (Export): Uses the GraphQL
orders(first, query, after, reverse:true)query to find orders withreturns(first: 10)that have been updated since the last flow run. The flow processes Shopify returns with statusREQUESTED, OPEN,orCLOSED. -
Get return info from Shopify (Lookup): For each return, retrieves detailed return information from Shopify including: return status, return line items, fulfillment line items, exchange line items, reverse fulfillment orders, and return shipping fees. Uses the GraphQL
return(id)query. -
Get returnable fulfillments from Shopify (Lookup): Uses the GraphQL
returnableFulfillments(first, orderId, after, reverse)query to retrieve fulfillment line items that can be returned. These are used to match return line items to the correct NetSuite sales order lines during RA creation. -
Get order info from NetSuite (Lookup): Uses saved search
customsearch_celigo_shopify_lines_returnto retrieve the original NetSuite order's line items (NS line IDs, eTail line IDs, tax data). These are required to map each Shopify return line item to its corresponding NetSuite sales order line. -
postResponseMap - build the RA record: The
postResponseMaphook builds the Return Authorization object for NetSuite import: -
Post verified return authorization to NetSuite (Import): Creates the Return Authorization in NetSuite with the appropriate status based on the Sync RMAs with Pending Approval status setting:
-
Post unverified return authorization to NetSuite (Import): For unverified returns (where
returnLineItemscontainUnverifiedReturnLineItemtype items), creates a separate RA with status Pending Receipt. Unverified return items are identified as order line items withcurrentQuantity < 0. -
Post item receipt to NetSuite (Import): Creates item receipt records in NetSuite for verified returns using distributed, one-to-many processing. Maps return line items, quantities, and locations, and links the receipt to the corresponding Return Authorization.
-
Update return authorization in NetSuite (Import): Updates Return Authorization records in NetSuite after item receipt creation by closing processed return lines and marking the return as completed for further processing.
This flow keeps the return approval status synchronized between NetSuite and Shopify. It is triggered when a Return Authorization in NetSuite is approved or closed, and automatically updates the corresponding Shopify return.
How the flow works
-
Approve return in Shopify (Import): NetSuite RA status = Pending Receipt AND Shopify return status = REQUESTED: approves the return in Shopify.
-
Cancel return in Shopify (Import): NetSuite RA status = Closed AND Shopify return status = REQUESTED: cancels the return in Shopify.
If the Shopify return is already in a state other than REQUESTED (for example, OPEN or CLOSED), neither branch matches and the record is skipped.
-
Get return authorizations from NetSuite (Export): Uses saved search
customsearch_celigo_shopify_rma_pending(type: once) to retrieve RAs in Pending Receipt or Closed status. For each RA, the Shopify Return ID (stReturnId) is retrieved from the eTail tab to identify the matching Shopify return. -
Get return status from Shopify (Lookup): Uses the GraphQL
return(id).statusquery to check the current Shopify return status. -
Router: Approve or Cancel
This scheduled flow processes the return in Shopify after the returned items have been physically received in NetSuite (an Item Receipt has been created against the Return Authorization). It also triggers the refund in Shopify based on the received items and any applicable exchange adjustments.
How the flow works
-
Get return authorizations from NetSuite (Export): Uses saved search
customsearch_celigo_shopify_received_rma(delta) to retrieve RAs in the following states: Pending Refund, Partially Received, or Closed. The search also includes the corresponding Item Receipt lines (SKU, quantity, location, restock flag) and the Shopify Return ID. -
Get related item receipt from NetSuite (Lookup): Uses saved search
customsearch_celigo_shopify_receipts_rma(type: once) to identify Item Receipts associated with each RA. These are required to determine which return lines have been physically received and are ready for processing. -
Get return information from Shopify (Lookup): Retrieves the current state of the Shopify return using the GraphQL
return(id)query, including exchange line items and any fulfillment orders on hold. -
postResponseMap - build lines to receive and remove: The
postResponseMapscript processes the RA and Item Receipt data to build two lists:-
linesToReceive: Item Receipt lines where
closed = false(items to be processed in Shopify) -
linesToRemove: RA lines where
closed = true(lines to be removed from the Shopify return, for example, cancelled lines or lines not received)
If Process all exchange items is enabled, the script also builds exchangeLinesToConfirm exchange line items from the Shopify return that should be automatically processed once the return is received.
The Item Receipt's
restockflag is used to determine whether each returned item should be restocked in Shopify's inventory. When the Restock checkbox is checked on the NetSuite Item Receipt, the item is restocked. When unchecked, it is not restocked. -
-
Router - Receive or Remove (all matching branches)
-
Post return received lines to Shopify (Import):
linesToReceive.length > 0: posts the received return lines to Shopify and triggers the refund calculation. The refund respects the Shopify settings for refund method (original payment or store credit).-
Release the fulfillment hold in Shopify (Import): Releases fulfillment holds in Shopify for fulfillment orders associated with the return, allowing order processing or exchange fulfillment to proceed.
-
-
Post return closed lines to Shopify (Import):
linesToRemove.length > 0: removes the specified lines from the Shopify return (for example, when a return was partially cancelled in NetSuite).
This router uses all matching branches, meaning both branches can execute on the same record if both conditions are true.
-
This flow monitors fulfillment orders that are on manual hold in Shopify, typically exchange orders in an upsell scenario where additional payment is pending. When payment is captured in NetSuite, this flow releases the fulfillment hold in Shopify so that the exchange order can be fulfilled.
The flow uses the GraphQL manualHoldsFulfillmentOrders(first, after, reverse:true) query to retrieve fulfillment orders currently on hold.
Note
This flow is only needed when the Auto-Release Fulfillment Hold setting (Returns flow group) is enabled. If you do not process upsell exchanges, you can leave this flow disabled.
How exchange orders are created
When the Process all exchange items setting is enabled, and the Shopify return includes exchange line items, the flow automatically processes the exchange items in Shopify once the return is received. This triggers the creation of the exchange order in Shopify.
The exchange order is then picked up by the Shopify order to NetSuite order – Exchanges flow, which creates the corresponding Sales Order or Cash Sale in NetSuite. The exchange order is routed to the same record type as the original order (Sales Order or Cash Sale).
If the Auto-Release Fulfillment Hold setting is enabled, the fulfillment hold on the exchange order in Shopify is automatically released after the exchange is processed, allowing the warehouse to fulfill the exchange items.
To configure, navigate to Settings > Returns.
|
Setting |
Description |
|---|---|
|
Sync RMAs with Pending Approval status |
Controls how Shopify return statuses map to NetSuite RA statuses. When enabled: REQUESTED: Pending Approval, OPEN: Pending Receipt, CLOSED: Closed. When disabled (default): REQUESTED: Pending Receipt, OPEN: Pending Receipt, CLOSED: Closed. |
|
Notify Customer |
When enabled, Shopify sends a notification to the customer when a return is approved. Default: disabled. |
|
NetSuite item to track Shopify restocking fee as a line item (Settings > General) |
Select the NetSuite non-inventory, payment, or other charge item to use as the restocking fee line item on Return Authorizations. Must be configured to sync Shopify restocking fees to NetSuite. |
|
NetSuite item to track Shopify return shipping fee as a line item (Settings > General) |
Select the NetSuite non-inventory, payment, or other charge item to use as the return shipping fee line item on Return Authorizations. Must be configured to sync Shopify return shipping fees to NetSuite. |
|
Process all exchange items |
When enabled, exchange items linked to a return are automatically processed in Shopify when the return is received in NetSuite. When disabled, exchange items must be processed manually in Shopify Admin. |
|
Auto-Release Fulfillment Hold |
When enabled, the fulfillment hold on exchange items is automatically released in Shopify after the exchange is processed. When disabled, the hold must be released manually using the Shopify hold fulfillments on the payment pending release flow or directly in Shopify Admin. |
-
Flow 1: Schedule every 15–30 minutes.
-
Flow 2: Schedule every 15–30 minutes. Run after Flow 1 in the same scheduling cycle.
-
Flow 3: Schedule every 15–30 minutes. Run after Flow 2. Do not enable Flow 3 before Flows 1 and 2 are stable and running without errors.
-
The template supports up to 10 exchange items per single Shopify order.
-
The template supports up to 250 return/refund records per order in Shopify.
-
Do not manually close a Shopify return until the integration has completed processing. If you need to stop a return in progress, cancel it in Shopify instead of closing it. Manually closing a return before the flow runs may cause errors or inconsistent records.
-
When an item receipt is created manually in NetSuite without restocking the item, and the return is later closed through Flow 3, the integration cannot retroactively update the Shopify restock status back to true.
-
The Shopify returns to NetSuite return authorization flow does not support mapping the StaffMember field.
-
The integration does not sync shipping refunds to the NetSuite Return Authorization.
The following $0 exchange-refund scenarios are currently not supported. In these scenarios, the refund sync may fail with the error: "Failed to save record because the total cannot be negative."
-
Per-line tax disabled + Overwrite tax enabled: When an exchange generates a $0 refund and a separate manual refund exists, the refund flow may process both, causing the $0 exchange refund to fail.
-
Tax-inclusive with per-line tax enabled: The $0 exchange refund amount may not calculate correctly.
-
Tax-inclusive when the exchanged item matches the original item: A $0 refund may be triggered and fail.
-
Upsell exchange scenario: After the exchange order is created, a $0 refund may be initiated and fail during processing.
Return Authorization not created in NetSuite
-
Verify the Shopify return status is REQUESTED, OPEN, or a state the flow is configured to process.
-
Check that the original Sales Order in NetSuite has the Shopify Order ID populated in the eTail Order ID field.
-
Ensure Return Authorizations are enabled in NetSuite (Setup > Company > Enable Features > Transactions).
RMA approval not syncing to Shopify
-
Check the Flow 2 run history to confirm it ran after the RA was approved in NetSuite.
-
Verify the Shopify return status is still REQUESTED; if it has already been approved or closed externally, the flow will skip it.
Access denied for returns field
Re-authorize the Shopify connection to grant the read_returns and write_returns API scopes. This error typically indicates that the Shopify connection was authorized before the returns scopes were added to the Celigo Shopify app.