NetSuite Ecommerce Inventory Sync: Why Your Storefront and ERP Disagree
The storefront says an item is in stock. NetSuite says it isn't. Or the reverse: NetSuite shows healthy on-hand quantity and the storefront has quietly marked the SKU unsellable. Whoever gets paged for this — and it's usually whoever owns the integration, not whoever owns the warehouse — ends up re-deriving the same mental model from scratch: which number is the system of record, which one the storefront is actually displaying, and where between the two the drift got in.
This isn't a BigCommerce problem, or a Shopify problem, or an Adobe Commerce problem. It's the same architecture problem wearing a different cart's clothes: a single ERP record has to stay reconciled with one or more downstream caches of "what's sellable right now," across a connector that's either synchronous, scheduled, or some unreliable mix of both. The storefront layer changes what breaks first and how visible it is. It doesn't change why it breaks.
It's the same disagreement on every cart
Start with what "inventory" means in NetSuite, because almost every mismatch starts with someone comparing the wrong number.
- Quantity On Hand — everything physically in the warehouse, spoken-for stock included.
- Quantity Committed — the slice of on-hand already allocated to open sales orders.
- Quantity Available — on-hand minus committed. This is usually the number a storefront should show, and Oracle's and Celigo's NetSuite connectors both document that they sync it rather than Quantity On Hand.
Turn on Multi-Location Inventory and each location carries its own set of these three numbers. "Total available" is the sum across every location flagged to make inventory available for sale — which means a location flag, a quarantine bin, or a returns location that nobody remembered to exclude will silently shift that sum in either direction. None of this is cart-specific. Shopify, BigCommerce, Adobe Commerce, and WooCommerce all eventually need the same answer to "available where, and summed across what."
What differs by platform is how that number gets represented once it lands — a single product-level field, a variant-level field, a per-location inventory record — and that's the part each spoke below gets into.
The four decisions that actually determine whether this breaks
1. What's the source of truth, and what does "available" mean here? NetSuite is almost always the system of record for inventory, but "available to sell online" is a business decision, not a fact the ERP hands you automatically. Available-to-promise, strict on-hand, or on-hand minus a deliberate safety buffer are all defensible — and they produce different storefront numbers by design. If that decision was never written down, every mismatch investigation starts from zero.
2. Event-driven or batch? A connector either reacts to a change (NetSuite workflow triggers a webhook or a RESTlet call the moment inventory moves) or polls on an interval and catches up periodically. Event-driven feels real-time but still isn't instantaneous, and it depends on NetSuite reliably firing the event — a workflow that silently stops triggering is worse than a slow poll, because nothing in the sync job's own logs tells you it stopped. Batch is simpler to reason about and easier to monitor (did the job run, did it succeed) but creates a known staleness window you have to design the storefront and the warehouse floor around.
3. Build, or buy a connector? Oracle's NetSuite Connector, Celigo's integration apps, a general iPaaS (Boomi, Workato, Celigo's own platform used generically), or custom middleware against each platform's API are all live options, and they have genuinely different ownership costs. A packaged connector is cheaper to start and someone else maintains the platform-API churn, but it only maps the fields and transaction types its authors anticipated — a vendor drop-ship, a bill-only transaction, a non-standard order type can move real inventory the connector was never built to watch. Custom middleware can cover any transaction type, but now your team owns every API version bump, every rate-limit change, and every edge case, on both ends, forever. The honest framing for a build-vs-buy conversation isn't "which is better" — it's "which gaps are you willing to carry, and who's maintaining the code that closes them."
4. How do you catch drift before a customer does? Idempotency matters more than it sounds like it should: if a sync job retries after a timeout, does it double-count the same inventory move, or does it recognize the retry and no-op? A scheduled reconciliation job — comparing NetSuite's available quantity to the storefront's displayed quantity on some interval, independent of the primary sync path — catches the drift that real-time sync misses, whether that's a silently failed webhook, a transaction type the connector doesn't watch, or a mapping that was wrong from day one. And none of this is worth anything without alerting: a dashboard nobody looks at is not observability. The question worth asking in a vendor or build review isn't "does it sync inventory" — every option on the table does that — it's "what happens the day it silently stops, and how long before anyone finds out."
Platform specifics
The mechanics above are universal. The failure modes aren't — each platform models inventory a little differently, and that difference is usually where the actual debugging time goes.
BigCommerce
BigCommerce's inventory_tracking field is set per product to none, product, or variant —
and a common cause of "the sync is broken" tickets is a product sitting on none, where BigCommerce
isn't tracking inventory at all. Multi-location lives behind the V3 Inventory and Locations APIs,
and some integrations flatten NetSuite's locations into one number and write only that, so true
per-location data never reaches BigCommerce. Full depth, including
the Locations API and connector behavior: NetSuite BigCommerce inventory sync.
Shopify
Shopify tracks inventory in several named states — available, on_hand, committed,
incoming, reserved, and a few less common ones — per location, via InventoryLevel. (on_hand
is the sum of every state except incoming, so mapping to it rather than available overstates
what's sellable.) That granularity is also where duplicate orders and oversells creep in: webhooks
can be delivered more than once, rate limits shape how fast a sync job can catch up after a
backlog, and a polling-based sync can lag behind orders that are committing against a location. Full depth: NetSuite Shopify inventory sync.
Adobe Commerce (Magento)
Adobe Commerce models inventory through Multi-Source Inventory (MSI): named "Sources" (physical or virtual locations holding stock) are grouped into "Stocks," and each Stock is what a sales channel (a website) sells against via a computed "Salable Quantity." Mapping NetSuite locations to MSI Sources — and deciding which Sources roll into which Stock — is where a NetSuite-to-Adobe-Commerce integration has to get the model right, because the Salable Quantity a shopper sees is calculated from the Sources assigned to that Stock. Adobe doesn't ship a NetSuite connector itself; integrations come from Oracle's NetSuite Connector, iPaaS vendors, marketplace extensions, or custom work against NetSuite's APIs.
WooCommerce
WooCommerce's core inventory model is simple: one stock quantity per product or variation. Its core settings don't offer multiple warehouse locations, so a WooCommerce store selling out of more than one warehouse is typically using an extension, a middleware layer, or NetSuite's own location logic as the only place multi-location math happens. That simplicity is an advantage for single-warehouse sellers and a real constraint the moment a second warehouse enters the picture, because the "which location" decision has nowhere native to live on the WooCommerce side.
Questions to ask about your current setup
- What's the actual source of truth for "available to sell," and is that decision written down anywhere, or just implied by however the connector happens to be configured?
- Is your sync event-driven, scheduled, or a mix — and if the event-driven path silently stopped firing tomorrow, how would you find out?
- What transaction types in NetSuite does your connector NOT watch? (Drop-ships and bill-only transactions are the most commonly missed.)
- Do you have a reconciliation job that runs independent of the primary sync path, or is the primary sync path the only thing checking its own work?
- If a webhook or API call gets retried, does your integration double-count it, or is it actually idempotent?
- Who owns the connector's maintenance cost today — a vendor's roadmap, or your own backlog — and does that match who should own it given how much custom logic you're actually running?
Where we'd start
We don't think there's one right connector or one right sync pattern — there's a right one for your transaction mix, your location count, and how much custom logic your team is willing to operate long-term. What we will say plainly: most of the setups we've looked at that "don't sync right" aren't missing a feature, they're missing a documented decision about what available actually means and a way to notice when the two systems have quietly stopped agreeing.
If you're trying to figure out which of this applies to your own setup, send us your integration diagram or your connector's field mapping and we'll tell you where we think the drift is actually coming from — no pitch deck, just an honest read from people who've been inside a few of these. Start that conversation.