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_ordersandread_customersscopes, 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 2tranDate->order.created_atotherrefnum->order.order_number(so you can search NetSuite by Shopify order #)externalid->shopify-{{ order.id }}(drives idempotency)memo-> "Shopify Order #{{ order.order_number }}"itemsublist -> 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 = falseflag so duplicate confirmation emails don't go out.
Common Pitfalls
- Webhook replays. Shopify retries failed webhooks. Without an
externalidbased 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.