← All articles

8 min read

Odoo Inventory Sync to Shopify: Avoiding Overselling at Scale

Overselling is the integration failure that costs you the most — not in money, but in trust. Every refund, every "sorry, out of stock" email, every chargeback. Here's the sync model that actually prevents it.

Why overselling happens

Three causes, in order of frequency:

1. Sync latency

Odoo says 10 in stock. Shopify says 10 in stock. A retail customer buys 8 in 90 seconds while the next sync runs in 10 minutes. By the time Odoo updates Shopify, a wholesale buyer has ordered 5 more.

2. Allocated vs available confusion

Odoo tracks forecast quantity, on-hand quantity, and allocated quantity. If you sync on-hand instead of available (on-hand minus allocated), you'll oversell every product that has open sales orders waiting to ship.

3. Multi-warehouse misconfiguration

Odoo has 3 warehouses with 10 units each. Shopify shows 30. A buyer in Region A orders 15 — Warehouse A only has 10, but Shopify accepted the order. Now ops has to either split-ship from another warehouse (paying the difference) or refund.

The sync architecture that prevents it

Push, don't poll

Use Odoo webhooks (or a queue worker watching stock.move records) to push inventory updates to Shopify within seconds. Polling every 10 minutes is the single biggest oversell cause.

Sync available, not on-hand

Always: `available = on_hand - reserved_for_open_orders`. If Odoo's API exposes free_qty or virtual_available, use those.

Map warehouses to Shopify locations explicitly

Don't aggregate. If Warehouse A maps to Shopify Location A, sync them 1:1. Let Shopify's own location routing handle the fulfilment decision.

Reserve a safety buffer on fast-movers

For top-20% SKUs by velocity, sync `available - 2` instead of `available`. Costs you 2 units of catalogue visibility, saves you the oversell.

What to log

Every inventory sync event should log: timestamp, SKU, source quantity, destination quantity, delta, warehouse, and trigger (webhook / cron / manual). When overselling happens — and at scale it eventually does — you need the audit trail to find the gap in under 5 minutes.

Hasil Sync logs all six fields per event with 30-day retention and surfaces conflicts in a dashboard. If you build your own, this is the contract that turns a 3-hour incident into a 5-minute fix.

The honest performance ceiling

Webhook-driven sync handles ~1,000 inventory events per hour comfortably on standard Shopify rate limits. Above that you need batching + Shopify Plus or the GraphQL Bulk Operations API. Most merchants never hit this ceiling — but if you're syncing 10K+ SKUs across multiple warehouses, plan for it on day one.

Want this working on your store?

Hasil ships wholesale portals and Odoo ↔ Shopify sync. 14-day free trial.

Start free trial
Start your 14-day free trial