How to Sync Cancelled Adobe Commerce Orders to NetSuite and Restock Inventory

Build a scheduled Spojit workflow that finds newly cancelled Adobe Commerce orders, marks the matching NetSuite sales order as cancelled, and returns the ordered units to available stock.

What This Integration Does

When a storefront order is cancelled in Adobe Commerce, two downstream systems usually fall out of sync: your NetSuite sales order still shows the order as open, and the inventory that was committed to that order never makes it back to available stock. This workflow closes both gaps automatically. On a fixed schedule it pulls the orders that moved to a cancelled state, locates the matching sales order in NetSuite, sets its status to cancelled, and pushes the cancelled line quantities back into available inventory so the units can be sold again.

The workflow runs on a Schedule trigger, so nothing has to call it: every run looks at a recent time window, processes each cancelled order it finds, and leaves NetSuite and your stock counts reflecting the cancellation. Because each run filters on a time window and you key the NetSuite lookup on the Adobe Commerce order number, re-runs are idempotent in practice: an order already marked cancelled in NetSuite is simply skipped or re-written to the same state, and you can guard the restock step so the same units are not added twice.

Prerequisites

  • An Adobe Commerce REST connection with permission to read orders. See the Adobe Commerce REST connector docs.
  • A NetSuite connection with access to read and update sales order records. See the NetSuite connector docs.
  • A Shopify connection with inventory write access, used here as the stock system that holds available quantities for the cancelled items. See the Shopify connector docs.
  • A reliable key that links an Adobe Commerce order to its NetSuite sales order (commonly the Adobe Commerce increment_id stored on the NetSuite sales order, for example in otherRefNum or a custom field).
  • A way to map each cancelled line item's SKU to its Shopify inventoryItemId and the locationId it should be restocked at.

Step 1: Start the workflow on a Schedule trigger

Add a Trigger node and set its type to Schedule. Use a 5-field Unix cron expression and an IANA timezone so the window lines up with your business hours. For example, run every 15 minutes during the working day with */15 * * * * and a timezone such as Australia/Sydney. A single Schedule trigger can hold more than one schedule if you want different cadences. The trigger output is { scheduledAt }, which you will use to build the lookback window in the next step.

Step 2: Compute the lookback window

Add a Connector node in Direct mode on the date utility connector and pick the subtract tool to shift {{ trigger.scheduledAt }} back by your polling interval plus a small safety margin (for example 20 minutes). Then use the format tool to render that timestamp as YYYY-MM-DD HH:MM:SS, which is the format Adobe Commerce expects. Store the formatted value as something like {{ window.createdAfter }}. A small overlap is intentional: it guarantees you never miss an order that was cancelled right on a run boundary, and the NetSuite lookup in Step 4 keeps duplicates harmless.

Step 3: Fetch cancelled orders from Adobe Commerce

Add a Connector node in Direct mode on the Adobe Commerce REST connector and choose the list-orders tool. Filter to the cancelled state and the recent window:

status: canceled
createdAfter: {{ window.createdAfter }}
pageSize: 50
sortField: created_at
sortDir: DESC

Adobe Commerce uses the spelling canceled for this status. The tool returns a paginated result, so if a busy window can exceed pageSize, increment currentPage and call the tool again until the returned page is short. If you need full line item detail that is not in the list payload, follow up with the get-order tool using the order's id.

Step 4: Loop each order and find the NetSuite sales order

Add a Loop node in ForEach mode over the order list from Step 3 (for example {{ adobe_orders.items }}). Inside the loop, add a Connector node in Direct mode on the NetSuite connector and use the run-suiteql tool to find the sales order that carries the Adobe Commerce order number. A query keyed on the stored reference returns the internal ID you need:

SELECT id, status FROM transaction
WHERE type = 'SalesOrd'
AND otherRefNum = '{{ order.increment_id }}'

If your account stores the storefront order number in a different field, adjust the WHERE clause to match. As an alternative to SuiteQL, the list-sales-orders tool accepts a SuiteTalk filter in its q field. Capture the returned internal ID as {{ netsuite_so.id }} for the next step.

Step 5: Mark the NetSuite sales order as cancelled

Add a Condition node to confirm a matching record was found (for example that {{ netsuite_so.id }} is not empty), so you do not attempt to update a missing record. On the true branch add a Connector node in Direct mode on the NetSuite connector and choose the update-record tool. Set recordType to salesOrder, set id to the internal ID from Step 4, and put the status change in body:

recordType: salesOrder
id: {{ netsuite_so.id }}
body: {
  "orderStatus": "_cancelled"
}

Use the exact status value your NetSuite account expects for a cancelled sales order. The update-record tool performs a patch update, so only the fields you list in body change; the rest of the record is left untouched.

Step 6: Return the cancelled units to available stock

Still inside the loop, iterate the cancelled order's line items and add a Connector node in Direct mode on the Shopify connector using the adjust-inventory tool. For each line, add the cancelled quantity back to available stock with a positive delta and the restock reason:

inventoryItemId: {{ item.inventoryItemId }}
locationId: {{ item.locationId }}
delta: {{ item.qty_canceled }}
reason: restock

The delta is a signed change, so a positive value adds units back to available. If you want to verify counts before and after, call the get-inventory-levels tool on the same item first. To notify your team that stock was returned, add a Send Email node after the loop summarising the orders processed.

Tips

  • Use Miraxa, the intelligent layer across your automation, to scaffold the skeleton: try "Build a scheduled workflow that lists cancelled Adobe Commerce orders, looks up the matching NetSuite sales order, and restocks Shopify inventory", then fine-tune each node in the properties panel.
  • Keep the lookback window a little wider than your cron interval so an order cancelled on a boundary is never skipped; the NetSuite lookup keeps the overlap safe.
  • Map SKUs to inventoryItemId and locationId once and store the mapping where the workflow can read it, rather than hardcoding ids per run.
  • If a single run can return many cancellations, raise pageSize and page through results so nothing is left unprocessed between runs.

Common Pitfalls

  • Status spelling. Adobe Commerce uses canceled (one "l"); filtering on "cancelled" returns nothing.
  • Timezone drift. The Schedule trigger uses an IANA timezone, but Adobe Commerce date filters are evaluated in the store's own timezone. Confirm both line up or you will query the wrong window.
  • Double restocking. Because the window overlaps between runs, the same order can appear twice. Guard the restock with a Condition (for example only restock when the NetSuite status was not already cancelled) so units are not added back more than once.
  • Wrong NetSuite status value. The accepted value for a cancelled sales order varies by account configuration. Test the update-record body on one record before turning the schedule on.

Testing

Before enabling the schedule, narrow the scope to one or two known orders: temporarily set createdAfter to a fixed timestamp that captures a single cancelled test order, and run the workflow with the Run button. Check the execution log to confirm list-orders returned the expected order, that run-suiteql resolved the correct NetSuite internal ID, that update-record reported success, and that the Shopify adjust-inventory delta matches the cancelled quantity. Verify the sales order status in NetSuite and the available count in Shopify by hand, then switch back to the rolling window and let the Schedule trigger take over.

Learn More

Did this answer your question? Thanks for the feedback There was a problem submitting your feedback. Please try again later.