How to Create NetSuite Sales Orders from Shopify

Automatically push Shopify orders into NetSuite as sales orders.

What This Integration Does

Shopify is the system of record for the storefront but NetSuite is the system of record for revenue, inventory, and fulfillment. Without an integration, finance has to re-key orders or run a nightly CSV import, which delays fulfillment and creates reconciliation headaches. This workflow listens for new orders in Shopify, looks up or creates the matching customer in NetSuite, and creates a sales order with line items, taxes, and shipping mapped over.

The workflow is triggered in real time via Shopify webhooks. Each incoming order is enriched with customer detail, transformed to NetSuite's sales order shape, and pushed via the NetSuite REST record API. The Shopify order ID is stamped onto the NetSuite sales order so re-runs are idempotent and finance can trace every transaction back to its source.

Prerequisites

  • A Shopify connection with read_orders and read_customers scopes, plus a webhook configured to fire on order creation.
  • A NetSuite connection with REST + SuiteQL access and permission to create Customer and Sales Order records.
  • Mapping data: a NetSuite item internal ID for every Shopify SKU you sell, and a default subsidiary / location / customer-form configured.
  • Optional: a Slack connection for failure alerts.

Step 1: Webhook Trigger

Drop a Trigger node and set it to Webhook. In Shopify admin, configure a webhook on the orders/create topic pointing at the Spojit webhook URL. The full order payload arrives on the trigger.

Step 2: Resolve the Customer in NetSuite

Add a Connector node calling netsuite run-suiteql to look up the customer by email:

SELECT id, entityid, email FROM customer
WHERE email = '{{ order.customer.email }}' AND isinactive = 'F'

Then a Condition node on result.length > 0. If found, use the existing customer. If not, branch to a Connector node calling create-customer with the Shopify customer's name, email, and billing address, and capture the new internal ID.

Step 3: Transform Shopify Order to NetSuite Sales Order

Add a Transform node that builds the sales order payload. Key mappings:

  • entity -> the customer internal ID from step 2
  • tranDate -> order.created_at
  • otherrefnum -> order.order_number (so you can search NetSuite by Shopify order #)
  • externalid -> shopify-{{ order.id }} (drives idempotency)
  • memo -> "Shopify Order #{{ order.order_number }}"
  • item sublist -> per line item: item (NetSuite internal ID from your SKU map), quantity, rate, amount
  • Shipping line, tax line, discount line as separate sublist entries with the right NetSuite account refs

Step 4: Create the Sales Order (Idempotent)

Add a Connector node calling netsuite upsert-record with record type salesOrder and the externalid from step 3. Upsert ensures a webhook replay does not create duplicate sales orders. If your NetSuite account doesn't allow upsert on sales orders, use create-record after first checking for an existing record via SuiteQL on externalid.

Step 5: Stamp Shopify with the NetSuite Reference

Add a Connector node calling shopify update-order (or raw-graphql to set a metafield). Write the NetSuite sales order internal ID back to the Shopify order as a metafield (netsuite.salesOrderId) so the link is visible from both sides.

Step 6: Error Handling and Alerting

Wrap the NetSuite write in a Condition on success. On failure, log the order ID and error to mongodb insert-documents (collection: netsuite_sync_errors) and send a slack send-message to the operations channel so the order can be created manually before fulfillment is delayed.

Tips

  • Pre-build the SKU -> NetSuite item internal ID map and cache it in a Spojit variable or a MongoDB collection. Don't query NetSuite per line item.
  • Run a SuiteQL nightly to detect Shopify orders that exist with no matching NetSuite sales order (a self-healing pass).
  • For B2B / wholesale flows, pick the customer-form variant up front so NetSuite applies the right pricing tier.
  • Use NetSuite's tobeemailed = false flag so duplicate confirmation emails don't go out.

Common Pitfalls

  • Webhook replays. Shopify retries failed webhooks. Without an externalid based on the Shopify order ID, you'll get duplicate sales orders during transient NetSuite outages.
  • Tax handling. Shopify reports tax-included totals in some regions. Mapping these to NetSuite tax codes incorrectly will throw your GL off. Test against an Australian or UK store before going live.
  • SKU mismatches. Any Shopify variant SKU without a NetSuite item mapping will silently drop the line. Validate the SKU map after every new product launch.
  • Subsidiary / location. OneWorld NetSuite accounts require subsidiary on the sales order. Pick a default and override based on the Shopify location.

Testing

Create a Shopify draft order for a single low-priced SKU, complete it, and watch the workflow run. Confirm a sales order appears in NetSuite with the right line, customer, and externalid. Re-fire the webhook from Shopify admin and confirm no duplicate is created. Then turn it on for real traffic.

Learn More

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