Bidirectional Shopify ↔ NetSuite Integration
A UK industrial distributor with 8,000 SKUs and 150+ trade accounts was running Shopify and NetSuite as completely separate systems. Orders were re-keyed twice daily. Inventory mismatches caused weekly oversell incidents. We built a production-grade bidirectional integration.
The problem
The operations team was exporting orders from Shopify twice daily and manually importing them into NetSuite. Inventory levels in NetSuite were being manually copied to Shopify weekly — meaning Shopify inventory was always 3–7 days out of date. Oversell incidents were frequent and expensive to resolve with trade customers who depended on stock accuracy for their own production planning.
Technical challenge
NetSuite's REST API has strict rate limits and inconsistent response times — a synchronous webhook handler that calls NetSuite directly would time out regularly. The integration needed to be observable at every step so the operations team could identify failures before they caused business impact. Idempotency was critical: Shopify delivers webhooks at least once, and duplicate orders in NetSuite are extremely difficult to clean up.
Architecture
Webhook queue architecture
Shopify order webhooks land in a Redis queue rather than being processed synchronously. A Bull worker processes the queue at a rate that respects NetSuite's API limits. Webhook receipt returns 200 immediately — no timeout risk.
Idempotent order creation
Every order is stored in PostgreSQL with its Shopify order ID before being sent to NetSuite. Duplicate webhook deliveries check this table first and skip processing if already handled. NetSuite's ExternalId field is set to the Shopify order ID for further deduplication.
Inventory sync
NetSuite inventory levels are fetched via Saved Search every 15 minutes during business hours. Changes are detected by comparing against the previous sync snapshot. Only changed SKUs are updated in Shopify using the bulk inventory mutation — up to 250 variants per API call.
Observability layer
Every sync run is logged with record count, duration, and status. Sentry captures all exceptions with the original payload. A simple admin dashboard (built with Remix) shows the last 50 sync runs with error details — no log access needed for the operations team.
Results
Manual re-keying was eliminated on day one. Inventory accuracy improved from a 3–7 day lag to 15-minute updates during business hours, eliminating oversell incidents entirely in the first 6 months. The integration has maintained 99.8% uptime over 6 months — the only downtime was a planned NetSuite maintenance window. The operations team now spends the time previously spent on re-keying on account management instead.
Have a project
like this?
Tell me what you're building. I'll tell you exactly how I'd approach it.