Connecting Shopify, Magento, and WooCommerce to an Open-Source ERP
Every e-commerce integration works in staging. It syncs a test order, pushes a stock level, updates a tracking number, and everyone signs off. Then a flash sale hits, three channels sell the same last twelve units simultaneously, the connector spends its rate limit budget on a full catalogue resync at exactly the wrong moment, and someone in customer service is emailing forty people to apologise. The integration did not fail because the developer was careless. It failed because order sync and inventory sync are different problems with different consistency requirements, and almost every naive integration treats them the same way.
This guide covers what actually has to be built when you connect Shopify, Magento, or WooCommerce to an open-source ERP: the six data flows, the system of record decision that has to come first, the specific behaviour of each platform's API and inventory model, the multi-channel reservation problem in detail, and a catalogue of the failure modes that show up in production. It assumes you are the person who will own the result, not the person buying a connector from an app store.
The Six Flows: What Integration Actually Means
"Integrate our store with our ERP" is not one project. It is six flows with different directions, triggers, latency requirements, and consequences when they break. Scoping them separately is the first thing that separates a working integration from a fragile one.
| Flow | Direction | Trigger | Target latency | Consequence of failure |
|---|---|---|---|---|
| Product and catalogue publish | ERP to channel | On change, batched | Minutes to hours | New products not sellable, wrong descriptions |
| Price publish | ERP to channel | On change, or scheduled | Minutes | Selling at the wrong price, margin loss, legal exposure in some markets |
| Inventory availability | ERP to channel | Event driven, plus reconciliation | Seconds to low minutes | Overselling, or unnecessary lost sales from understated stock |
| Order capture | Channel to ERP | Webhook, plus polling safety net | Seconds to minutes | Unfulfilled or duplicated orders, revenue recognised incorrectly |
| Fulfilment and shipment status | ERP to channel | On shipment confirmation | Minutes | Customers chasing tracking, support load, marketplace metric penalties |
| Returns, refunds, cancellations | Bidirectional | On event | Minutes to hours | Inventory never released back, refunds not reconciled to the ledger |
Two supporting flows sit underneath these. Customer and party records need a deduplication and matching strategy, because the same human buys as a guest on one channel and a registered account on another. And tax, discount, and shipping amounts need to be transferred as captured rather than recalculated, because a channel and an ERP will disagree on rounding and the ledger has to match what the customer's card was actually charged.
Decision Zero: Who Owns What
Before any code, decide the system of record for each data domain and write it down. Most integration disasters are not technical failures but the consequence of two systems both believing they are authoritative over the same field.
| Data domain | Recommended owner | Reasoning |
|---|---|---|
| Product master, SKU, attributes | ERP | One catalogue definition feeding many channels, with channel-specific presentation layered on top |
| Merchandising content, imagery, SEO copy | Channel | The storefront team iterates on this daily and should not need an ERP release |
| Cost price, supplier data | ERP | Never leaves the ERP |
| Sell price and promotions | Depends. ERP for list and contract pricing, channel for storefront promotions | Decide per business. A split model needs explicit precedence rules |
| Physical inventory quantity | ERP | The ERP is the only system that sees goods receipts, transfers, adjustments, and counts |
| Sellable availability per channel | ERP calculates, channel displays | This is the crux of the whole problem, covered in detail below |
| Order once placed | ERP | The channel captured it. The ERP fulfils, invoices, and accounts for it |
| Order presentation and customer notifications | Channel | Customers expect emails from the brand, not the ERP |
| Customer master | ERP, with channel accounts linked | Deduplication has to happen somewhere authoritative |
The single rule that prevents most inventory incidents: the channel never decides what is sellable. It displays a number the ERP calculated. The moment a store's own stock arithmetic is allowed to compete with the ERP's, you have two ledgers and no truth. This is also why a properly implemented modern order management system sits between the channels and fulfilment rather than beside them.
Platform Reality: What Each One Actually Requires
The three platforms differ far more than integration vendors imply, and the differences are concentrated exactly where the risk is.
Shopify
Shopify is the most disciplined API of the three and the most opinionated. The REST Admin API became a legacy API on 1 October 2024, and Shopify's guidance is that all apps and integrations should be built with the GraphQL Admin API. New public app submissions must use GraphQL. Building a new integration on REST in 2026 means carrying migration debt from the first commit, and there are capabilities that simply do not exist on the REST surface.
Rate limiting is the part that catches teams migrating from REST habits. GraphQL does not count requests, it prices queries. Every field, connection, and pagination argument carries a cost, standard plans work from a 1,000 point bucket that restores at 50 points per second with higher tiers getting larger buckets and faster restore, and a single query cannot exceed a fixed point ceiling regardless of plan. The practical implications are that your integration must read the throttle status returned with every response and queue work against available points rather than against a requests-per-second figure, and that anything touching more than a few hundred records belongs in a bulk operation rather than a paginated loop.
The inventory model is where Shopify is genuinely sophisticated and where naive integrations do the most damage. Inventory at a location is not one number. It is a set of states, and the physical total is the sum of all of them:
| Shopify state | Meaning | Who writes it |
|---|---|---|
on_hand | Total physical units at the location | Your ERP, via inventorySetQuantities |
available | Units sellable right now | Derived. Do not overwrite with a physical count |
committed | Units on placed but unfulfilled orders | Shopify, automatically |
incoming | Units on transfers or purchase orders | Shopify or your app |
reserved | Units held by apps or draft orders | Apps |
damaged, safety_stock, quality_control | Unsellable or ring-fenced units | Your ERP or WMS |
The relationship that matters: on_hand equals available plus committed plus reserved plus damaged plus safety_stock plus quality_control. An ERP that pushes its physical stock figure into available has just re-sold every unit already committed to unfulfilled orders. This is the most common overselling bug in Shopify integrations and it is entirely avoidable by writing on_hand and letting Shopify derive available.
There is one further trap worth committing to memory. Shopify's own documentation states that changes to the committed, reserved, damaged, safety_stock, and quality_control states do not trigger webhooks. An integration that assumes it will be notified about every inventory movement will silently drift. Reconciliation by polling is not optional here, it is architectural. Shopify's inventory management app documentation is worth reading in full before designing the sync, particularly the referenceDocumentUri field, which lets you stamp every adjustment with the ERP document that caused it and gives you a real audit trail across both systems.
Magento Open Source and Adobe Commerce
Magento's Multi-Source Inventory has been the default inventory system since 2.3 and it is the most conceptually similar to an ERP of the three platforms, which creates a specific class of problem: two reservation systems that both think they are managing allocation.
The model has two layers. A Source is a physical location holding stock. A Stock is a logical grouping of Sources mapped to a sales channel, currently a website. Salable Quantity is the number the storefront actually uses, and it is calculated as the aggregated quantity across the Sources assigned to that Stock, minus reservations, minus configured thresholds. A reservation is created when an order is placed, which lowers Salable Quantity immediately without touching physical Source quantities. When the order ships, the reservation is cleared and the physical quantity at the selected Source is decremented. A Source Selection Algorithm decides which Sources fulfil a given shipment.
Three consequences follow for an ERP integration:
An integration that reads quantity rather than salable_quantity is reading the physical figure and will make allocation decisions that ignore every order Magento has already taken. Read salable quantity for anything customer-facing.
Reservations can drift out of alignment with orders, which is why Magento ships the bin/magento inventory:reservation:list-inconsistencies command. Running it on a schedule and alerting on non-empty output is a basic operational requirement, not an optimisation. Drift accumulates quietly and surfaces as overselling weeks later.
Quantity calculations are asynchronous and indexer-dependent. A write followed immediately by a read will not always reflect the write. Any integration logic that assumes read-after-write consistency against Magento inventory will produce intermittent bugs that are extremely hard to reproduce. Practitioner guidance also notes that MSI handles roughly one to twenty Sources comfortably and degrades at fifty or more, at which point moving allocation into the ERP entirely and treating Magento as a single virtual Source is usually the better architecture.
WooCommerce
WooCommerce is the most permissive and the most variable, because the platform is a WordPress plugin sitting on infrastructure you do not control and alongside plugins you did not choose.
Order storage changed materially with High-Performance Order Storage, which has been the default for new installations since WooCommerce 8.2 in October 2023. Under HPOS the wp_wc_orders tables are authoritative and the legacy posts and postmeta tables become backup, optionally kept in step by compatibility mode. The integration consequence is direct: any code that reads or writes order data through WordPress post meta functions rather than the WooCommerce CRUD layer or the current REST API is operating on the wrong tables. With compatibility mode off, that data is simply lost. Use the wc/v3 REST endpoints, which are HPOS-compatible, and treat the legacy API as out of scope.
Woo does have a short-lived stock hold mechanism. The wc_reserved_stock table backs reserve_stock_for_order and release_stock_for_order, with the hold duration defaulting to the woocommerce_hold_stock_minutes setting. This is a checkout-window protection, not a channel allocation system, and it should not be confused with one.
The two things to plan around are that WooCommerce has no native multi-location inventory model, so multi-warehouse availability has to be calculated in the ERP and published as a single figure, and that webhook delivery depends entirely on the host. Webhooks and background jobs run through Action Scheduler on WordPress cron, which on shared or aggressively cached hosting can be delayed or dropped. A Woo integration without a polling reconciliation layer is not a design choice, it is a latent incident.
Platform comparison
| Dimension | Shopify | Magento Open Source | WooCommerce |
|---|---|---|---|
| Primary API | GraphQL Admin API. REST legacy since Oct 2024 | REST and SOAP, plus async bulk endpoints | REST wc/v3 |
| Auth | OAuth access tokens, scoped | Integration tokens, OAuth | Consumer key and secret, or application passwords |
| Rate limiting | Calculated query cost, points bucket | Server capacity dependent, self-hosted | Host dependent, no platform limit |
| Bulk data | Bulk Operations API | Async bulk API and message queues | Batch endpoints, practical limits from host |
| Inventory model | Multi-location with seven quantity states | MSI with Sources, Stocks, reservations, salable quantity | Single stock figure per product or variation |
| Native multi-location | Yes | Yes | No |
| Reservation on order | Yes, committed state | Yes, explicit reservation records | Checkout hold only |
| Webhook reliability | High, with documented gaps for some inventory states | Good, message queue based | Host dependent, needs a safety net |
| Order storage caveat | None significant | Indexer and async calculation lag | HPOS versus legacy tables |
| Relative integration effort | Moderate. Well documented, strict rules | Highest. Two reservation systems to reconcile | Moderate. Simple API, unpredictable environment |
The Multi-Channel Inventory Reservation Problem
This is the section that matters most, because it is the problem that naive integrations do not know exists.
Consider one physical warehouse holding twelve units of a SKU, selling on Shopify, Magento, and WooCommerce. A naive integration reads twelve from the ERP and writes twelve to all three channels. Each channel now believes it can sell twelve units. Under normal traffic this works, because the sync loop corrects each channel a few seconds after any sale. Under concurrent load it fails predictably: the worst case oversell is not twelve units but thirty-six, and the failure probability scales with the ratio of your sync interval to the time between orders. On a normal Tuesday that ratio is harmless. During a promotion it is the whole problem.
The fix is not a faster sync loop. Faster sync narrows the window without closing it, and it consumes the rate limit budget you need most during exactly the traffic conditions that cause the problem. The fix is to stop publishing physical stock and start publishing available to promise, calculated in the ERP.
Having calculated a single pooled availability figure, you still have to decide how much of it each channel may see. There is no universally correct answer, and this is a commercial decision that engineering should not make alone.
| Allocation strategy | How it works | Oversell risk | Lost sale risk | Best for |
|---|---|---|---|---|
| Full exposure | Every channel sees the whole pooled ATP | High under concurrency | Lowest | Slow-moving SKUs, deep stock, low concurrency |
| Static buffer | Publish ATP minus a fixed unit or percentage holdback | Low | Moderate, permanent | Simple to operate, good default for mixed catalogues |
| Proportional split | Divide ATP across channels by historical share | Very low | High. Stranded stock in the wrong channel | Rarely optimal. Use only with strict channel commitments |
| Dynamic pooled ATP | Full exposure with event-driven decrement on every order and sub-second convergence | Low if convergence is genuinely fast | Low | High-velocity operations with engineering capacity to run it properly |
| Hard partition | Physically or logically ring-fence stock per channel | None across channels | Highest | Contractual channel commitments, marketplace SLAs, wholesale allocations |
| Tiered by velocity | Full exposure for slow movers, buffered or partitioned for the top few percent of SKUs by velocity | Low where it matters | Low overall | The pragmatic production answer for most catalogues |
The last row is what most mature operations converge on. Overselling risk is concentrated in a small number of fast-moving, low-stock SKUs, and the correct response is to apply expensive protection only to those rather than degrade availability across the whole catalogue.
Why the ERP has to hold the reservation ledger
An open-source ERP is a good place for this because the data model already distinguishes physical stock from promised stock. In Apache OFBiz, inventory records carry both a quantity on hand total and an available to promise total as separate fields, reservations are first-class records linking order items to specific inventory items, and the sales channel abstraction lets you define which facilities serve which channel and in what order stock is consumed, such as first in first out by receipt date. Moqui's mantle data model draws the same separation between asset quantity on hand and reservation records. In both cases you are configuring behaviour that already exists rather than building a reservation engine, which is the main reason these platforms suit multi-channel operations. The framework details are documented at ofbiz.apache.org and moqui.org.
The lifecycle looks like this end to end.
The two details that make this correct rather than merely plausible: availability is republished to every channel after each reservation, not just the channel that took the order, and physical quantity on hand only moves at pick confirmation while the reservation moves at order placement. Collapsing those two events into one is a common shortcut and it destroys your ability to reconcile stock against the warehouse. The same separation is what makes an AI-powered warehouse management system able to optimise picking without corrupting channel availability, and it underpins accurate inventory management solutions across multiple locations.
Where Naive Integrations Break
Every item below is a failure we have seen in production. Most are invisible in testing because they require concurrency, volume, or time to manifest.
| Failure mode | Symptom | Root cause | Fix |
|---|---|---|---|
| Physical stock published as sellable | Overselling that scales with promotion traffic | Publishing quantity on hand rather than ATP | Calculate ATP in the ERP, publish that |
Shopify available overwritten | Committed stock sold a second time | ERP writes its physical count to available instead of on_hand | Write on_hand with inventorySetQuantities and let Shopify derive available |
| Missing inventory webhooks | Slow, unexplained divergence in one channel | Changes to committed, reserved, damaged, safety_stock and quality_control do not fire webhooks | Treat scheduled reconciliation as mandatory, not a fallback |
| Magento physical versus salable | Allocation ignores orders Magento already took | Reading quantity instead of salable_quantity | Read salable quantity for anything customer-facing |
| Magento reservation drift | Overselling weeks after the causing event | Reservation inconsistencies never checked | Schedule inventory:reservation:list-inconsistencies and alert on output |
| Read-after-write assumption | Intermittent, unreproducible wrong quantities | Magento calculates quantities asynchronously | Never read back to confirm a write. Confirm through reconciliation |
| HPOS mismatch | Order metadata silently disappears | Integration writes WordPress post meta while HPOS tables are authoritative | Use the wc/v3 REST API or WooCommerce CRUD methods only |
| Dropped Woo webhooks | Orders missing from the ERP, discovered by customers | Action Scheduler delayed or killed on shared hosting | Polling reconciliation on a short interval, keyed on channel order ID |
| No idempotency key | Duplicate orders, duplicate reservations, duplicate invoices | Webhook retried after a timeout that actually succeeded | Idempotency key on channel order ID plus event ID, stored and checked before processing |
| Out-of-order events | Cancelled order re-opened, old status overwrites new | Events processed in arrival order rather than sequence order | Version or timestamp every event, discard stale ones, process per-entity in order |
| Rate limit exhaustion at peak | Sync stalls precisely during the highest traffic | Full catalogue resync scheduled during trading hours, or paginated loops instead of bulk operations | Move bulk work to off-peak windows and bulk endpoints, reserve live budget for orders and inventory |
| Refunds and partial cancellations unmodelled | Inventory never returns to sellable, ledger does not reconcile | Only the happy path was built | Model cancellation, partial refund, and return as distinct inbound events from day one |
| Silent failure | Nobody notices for days | No dead letter queue, no alerting on queue depth or age | Dead letter queue with alerting, plus a daily reconciliation report a human reads |
| Clock-skew polling | Records missed permanently, never retried | Incremental polling on modified-since timestamps across systems with different clocks | Overlap the polling window, poll by cursor where available, reconcile on totals not timestamps |
| Tax and rounding recalculated | Ledger does not match the customer's card charge | ERP recalculates tax rather than accepting the captured figure | Transfer captured totals as data. Recalculate only for validation and alert on mismatch |
| Currency and channel pricing collapsed | Wrong prices published to a market | Single price field mapped to multiple channels and currencies | Model channel and currency specific price lists explicitly |
The pattern across almost all of these is the same. Naive integrations are built as a set of point-to-point pushes that assume delivery, ordering, and consistency. Production integrations are built as an event pipeline that assumes none of those things and reconciles continuously.
Reference Integration Architecture
The components that are not optional, and that get cut first when a project runs late:
| Component | Purpose | What happens without it |
|---|---|---|
| Signature verification on webhook receipt | Rejects forged payloads | Anyone who learns your endpoint can inject orders |
| Fast acknowledgement, deferred processing | Returns 200 before doing work | Channel retries on timeout, producing duplicates |
| Idempotency store | Detects replays by event and order ID | Duplicate orders, reservations, and invoices |
| Durable queue with per-entity ordering | Survives restarts, keeps entity events sequential | Lost events, out-of-order state corruption |
| Versioned transformation layer | Field mapping as reviewable code | Untraceable mapping changes, no rollback |
| Dead letter queue with alerting | Failures become visible | Silent data loss discovered by customers |
| Scheduled poller | Catches events that never arrived | Permanent gaps, worst on WooCommerce |
| Reconciliation engine | Compares channel state to ERP truth, corrects and reports | Slow drift that nobody detects until it is expensive |
| Observability on queue depth and event age | Early warning before customer impact | You learn about problems from support tickets |
Sync cadence design
| Flow | Mechanism | Target latency | Reconciliation |
|---|---|---|---|
| Order capture | Webhook, with 5 to 15 minute polling safety net | Under 60 seconds | Hourly count and total comparison per channel |
| Inventory availability | Event driven on every reservation and receipt | Under 60 seconds for fast movers, minutes acceptable otherwise | Full ATP sweep nightly, plus targeted sweeps on top velocity SKUs hourly |
| Fulfilment and tracking | Event driven on shipment confirmation | Under 5 minutes | Daily open shipment comparison |
| Price | Scheduled, off-peak, plus event driven for urgent changes | Minutes to hours | Daily full price comparison per channel |
| Catalogue | Scheduled batch, off-peak, bulk endpoints | Hours | Weekly full catalogue diff |
| Returns and refunds | Event driven | Minutes | Daily financial reconciliation to the ledger |
Note what is deliberately slow. Catalogue and price sync are batch operations that belong outside trading hours, because they are the flows that consume rate limit budget and they are not time critical. Protecting live order and inventory throughput from bulk catalogue work is one of the highest-value design decisions in the whole integration.
Build, Buy, or Middleware
| Option | Typical cost | Best for | Limits |
|---|---|---|---|
| App store connector | $50 to $500 per month per channel | Single channel, standard processes, no custom fulfilment logic | Rarely models ATP or multi-channel reservation. Usually the source of the problems in this article |
| iPaaS or middleware platform | $12,000 to $60,000 per year plus build | Multiple channels, in-house integration capability, appetite for a hosted control plane | Recurring cost scales with volume. Complex logic still has to be written somewhere |
| Custom integration on your own stack | $25,000 to $70,000 per channel to build | Multi-channel operations where allocation logic is a competitive concern | You own operations, monitoring, and platform API version upgrades |
| Native ERP integration layer | Included in an ERP programme, $40,000 to $120,000 for a multi-channel build | Businesses already implementing or extending an open-source ERP | Requires the ERP work to be underway |
For a single Shopify store with simple fulfilment, a connector is often the right answer and this whole article is overkill. The calculation changes as soon as you have two or more channels sharing one stock pool, because that is the point at which allocation policy becomes a business decision that has to live somewhere you control. That is the work we do through Apache OFBiz ERP development services, Moqui ERP development and consultancy, and custom ERP development solutions, and the platform choice question is covered separately in our open-source ERP evaluation framework.
Implementation Sequence
| Phase | Duration | Deliverable | Gate to pass before proceeding |
|---|---|---|---|
| 1. Ownership and mapping | 1 to 2 weeks | System of record matrix, field-level mapping per channel, allocation policy signed off by commercial | Commercial owner has agreed the buffer and partition rules |
| 2. Master data alignment | 2 to 4 weeks | SKU parity across channels and ERP, unit of measure and variant model reconciled | Every channel SKU resolves to exactly one ERP product |
| 3. Read-only pull | 1 to 2 weeks | Orders flowing into a staging ERP, nothing written back | Order totals and tax reconcile to the cent for a full week |
| 4. Inventory publish | 2 to 3 weeks | ATP calculation and publish to one channel, reconciliation running | Zero unexplained variance for seven consecutive days |
| 5. Fulfilment write-back | 2 to 3 weeks | Shipment and tracking flowing to the channel | Customer-visible status matches warehouse reality |
| 6. Second and third channels | 1 to 2 weeks each | Additional channels on the same pipeline | Concurrency test passes with simultaneous orders on the last unit |
| 7. Exceptions and returns | 2 to 3 weeks | Cancellation, partial refund, return to stock | Inventory returns to sellable and the ledger reconciles |
| 8. Load and peak rehearsal | 1 week | Peak traffic simulation at 3x forecast | Rate limits respected, queue drains, no oversell |
Two sequencing rules earn their keep. Never connect more than one channel until the first one has run clean for a week, because debugging three channels simultaneously multiplies the work rather than adding to it. And run the concurrency test deliberately: fire simultaneous orders for the last unit across all channels and confirm the behaviour is a clean rejection or backorder rather than an oversell. That test is the entire point of the build, and it is the one most often skipped.
Pre-launch checklist
| Check | Pass criteria |
|---|---|
| Concurrency | Simultaneous orders on the final unit across all channels produce no oversell |
| Idempotency | Replaying the same webhook ten times creates exactly one order |
| Webhook loss | Disabling webhooks for an hour results in zero lost orders after the poller runs |
| Rate limits | A full catalogue sync during simulated peak does not delay order processing |
| Reconciliation | Deliberately introduced drift is detected and corrected within one cycle |
| Refund path | A partial refund releases the correct inventory and posts correctly to the ledger |
| Failure visibility | A forced failure appears in the dead letter queue and triggers an alert |
| Rollback | The integration can be disabled without corrupting either system |
Where AI Belongs in This Stack
Integration is where AI earns its place quickly, because the work is high volume, rule-bound, and full of exceptions that currently consume human attention. The sequencing matters though: automate after the pipeline is stable, never during the build.
The immediate candidates are exception triage and document handling. Address validation failures, payment mismatches, and SKU resolution errors arrive as queues that a person works through, and those queues are well suited to agent handling under policy. AI-powered document processing removes manual entry from inbound supplier documents and purchase orders on the replenishment side of the same inventory pool. From there, AI agents in order management can handle allocation exceptions and reprioritisation, while autonomous warehouse management optimises the fulfilment side using the same ATP ledger. The broader pattern, where the ERP service layer becomes a toolset that agents call under policy with the entity model providing the audit trail, is covered in our work on agentic ERP architecture and AI ERP solutions.
The prerequisite is the one this whole article is about. Agents acting on inventory data that is wrong will make confident, fast, wrong decisions. Get the reservation ledger correct first.
Frequently Asked Questions
Can Apache OFBiz or Moqui connect to Shopify, Magento, and WooCommerce?
Yes. Both expose service layers that can be called over HTTP and both can consume webhooks, so the integration is built as a pipeline between the channel APIs and ERP services rather than as a plugin. Neither ships a maintained turnkey connector for these platforms, which means the integration is a build. The advantage is that the underlying data model already separates physical stock from available to promise and holds reservations as first-class records, so you are configuring allocation behaviour rather than inventing it.
How do you prevent overselling across multiple sales channels?
Stop publishing physical stock. Calculate available to promise in the ERP as quantity on hand minus stock allocated to unshipped orders, minus outstanding channel reservations, minus a safety buffer, minus damaged and ring-fenced stock, plus inbound receipts within your promise horizon. Publish that figure, decrement it on every order event across all channels rather than just the one that sold, and run scheduled reconciliation to correct drift. For the small number of fast-moving low-stock SKUs where most risk concentrates, add a buffer or hard partition.
Should inventory live in the ERP or in the store?
Physical inventory always lives in the ERP, because the ERP is the only system that sees goods receipts, transfers, adjustments, and stock counts. The store displays a sellable figure the ERP calculated. Allowing a storefront's own stock arithmetic to compete with the ERP's produces two ledgers and no reliable answer.
Real-time or batch sync?
Both, for different flows. Orders and inventory availability are event driven with a target latency under a minute, backed by a polling reconciliation layer because webhooks are not guaranteed. Catalogue and price sync are scheduled batch operations that belong outside trading hours, both because they are not time critical and because they consume the rate limit budget that order and inventory flows need during peak.
Why does my Shopify integration oversell even though stock syncs correctly?
The most common cause is writing your physical stock count into Shopify's available state instead of on_hand. Shopify derives available by subtracting committed, reserved, and unavailable states from on_hand, so overwriting available with a physical figure re-exposes every unit already promised to unfulfilled orders. The second most common cause is assuming webhooks cover all inventory changes, when Shopify's documentation states that changes to committed, reserved, damaged, safety_stock, and quality_control do not fire webhooks.
What is the difference between quantity and salable quantity in Magento?
Quantity is the physical amount at a Source. Salable Quantity is what the storefront can sell on a given Stock, calculated by aggregating quantities across the Sources assigned to that Stock and subtracting reservations and configured thresholds. Reservations are created when an order is placed and cleared when it ships. An integration reading quantity instead of salable quantity is ignoring every order Magento has already accepted.
How long does an e-commerce to ERP integration take, and what does it cost?
A single channel with orders, inventory, and fulfilment write-back is typically 6 to 10 weeks and $25,000 to $70,000 for a custom build. A three-channel implementation sharing one stock pool with proper ATP calculation, reconciliation, and exception handling is typically 4 to 6 months and $40,000 to $120,000. App store connectors cost far less and are appropriate for single-channel operations with standard fulfilment, but they rarely model multi-channel reservation, which is why they are often the reason a business ends up reading an article like this.
Can one ERP serve multiple storefronts on different platforms?
Yes, and it is the main reason to centralise. The design pattern is one sales channel abstraction per storefront in the ERP, each mapped to the facilities that serve it and each with its own pricing, allocation policy, and order attribution. Adding a fourth channel to a properly built pipeline is one to two weeks of work. Adding it to a set of point-to-point connectors means rebuilding the allocation logic again.
Final Thoughts
Connecting a storefront to an ERP looks like an API problem and is really an inventory arithmetic problem. The APIs are documented, stable, and learnable. What is not obvious until it fails in production is that three channels sharing one stock pool need a single authoritative reservation ledger, that webhooks are a delivery optimisation rather than a guarantee, and that consistency has to be achieved through continuous reconciliation rather than assumed from the last successful push.
If you build for those three realities, the platform differences become detail: Shopify wants GraphQL and correct use of its quantity states, Magento wants you to respect its reservation system rather than fight it, and WooCommerce wants a polling safety net and HPOS-aware code. If you build without them, the integration will pass every test and then fail on the busiest day of your year.
We build and rescue these pipelines across manufacturing, retail, e-commerce, and distribution, usually as part of a wider order and warehouse management programme. If you are currently overselling and not sure why, the reservation ledger is the first place to look.



