How to Sync WooCommerce Orders to NetSuite
Push WooCommerce orders into NetSuite as sales orders automatically.
What This Integration Does
WooCommerce captures the order; NetSuite invoices, ships, and books revenue from it. Keeping these in sync manually is one of the most common sources of finance pain in mid-market e-commerce. This workflow takes a WooCommerce order, resolves or creates its NetSuite customer, and writes the matching NetSuite sales order with all line items.
It can run via WooCommerce webhook (real-time) or schedule (batch poll). Each NetSuite sales order carries the WooCommerce order number on otherrefnum, so re-running the workflow on the same order is a no-op rather than a duplicate.
Prerequisites
- A WooCommerce connection with consumer key + secret and read access to orders.
- A NetSuite connection with permission to create customers and sales orders and run SuiteQL.
- An SKU-to-NetSuite-item map (preloaded in MySQL or MongoDB) - this is the slowest call to make per line, so caching matters.
Step 1: Trigger
For real-time, configure a WooCommerce webhook for the order.created topic pointing at a Webhook trigger. For batch, use a Schedule trigger every 10-15 minutes with a since timestamp variable.
Step 2: Fetch the WooCommerce Order
On the webhook path, take id from the payload and call woocommerce get-order for the full record. On the schedule path, call woocommerce list-orders with after={{ since }} and status=processing,completed, then loop.
Step 3: Resolve or Create the NetSuite Customer
Call netsuite run-suiteql to find by email:
SELECT id FROM customer WHERE email = '{{ order.billing.email }}'
Branch on the result via a Condition node. On no-match, call netsuite create-customer with WooCommerce's billing address. Capture the NetSuite internal id in nsCustomerId.
Step 4: Transform Line Items and Reconcile Tax
Use a Transform node to convert each WooCommerce line_item:
- Look up
nsItemIdfor the line'sskufrom the cached SKU map. - Set
quantityfromline.quantity. - Pick a price strategy: NetSuite expects either tax-inclusive or tax-exclusive rates. WooCommerce reports both
subtotal(ex tax) andtotal(inc tax). Pick one and configure NetSuite tax codes to match, or totals will drift by the rounding error.
Step 5: Create the Sales Order in NetSuite
Call netsuite create-record with type salesOrder:
{
"entity": { "id": "{{ nsCustomerId }}" },
"otherrefnum": "{{ order.number }}",
"trandate": "{{ order.date_created }}",
"memo": "WooCommerce order {{ order.id }}",
"item": {
"items": [
{ "item": { "id": "{{ line.nsItemId }}" }, "quantity": {{ line.quantity }}, "rate": {{ line.rate }} }
]
}
}
Step 6: Write Back the NetSuite ID and Alert on Failure
On success, call woocommerce update-order to stamp a meta field netsuite_id with the NetSuite internal id - this gives finance an immediate cross-reference. On failure, route via Condition to slack send-message with the order id and error so on-call can resolve quickly without log-trawling.
Tips
- WooCommerce can emit the same webhook twice during retries. Rely on the
otherrefnumnatural key in NetSuite to reject duplicates. - Pre-cache the SKU map nightly - the per-line SuiteQL lookup is the slowest part of this workflow if uncached.
- Decide which order statuses count as "ready to sync" up front (
processingis usually right;pendingmeans payment hasn't cleared).
Common Pitfalls
- Tax method mismatch - The single biggest source of cent-level drift. Lock down inc-vs-ex tax on day one and validate totals on the first dozen orders.
- Shipping as a line - WooCommerce reports shipping as its own object. Add it as an explicit shipping line on the NetSuite SO or totals won't reconcile.
- Currency - For multi-currency WooCommerce stores, push
order.currencyinto the NetSuite SO currency field explicitly. - Refunds and partial refunds - This workflow creates orders; refunds are a separate workflow listening on
order.refunded.
Testing
Place a single test order in WooCommerce, trigger the workflow, and open the NetSuite sales order. Verify customer (resolved, not duplicated), each line item, tax, shipping, and grand total. Re-fire the webhook on the same order and confirm the duplicate is rejected at the otherrefnum check before going live.