Operations · 6 min read
How to keep Shopify inventory in sync across multiple vendors
The vendor sends spreadsheets, someone retypes them, the site sells stock that doesn't exist. Here's why that pipeline actually fails — and the shape of the one that doesn't.
Why it actually breaks
Overselling isn't a sync-speed problem — it's a data-integrity problem wearing a sync costume. The failures we see in the wild come in four repeatable flavors.
First, SKU identity. The vendor's SKU is not your SKU. A sectional arrives as one vendor record and exists in Shopify as six variants across two products. Any sync that doesn't maintain a real vendor_sku to shopify_sku mapping table is guessing — and guessing is how you sell three units of stock you have one of.
Second, partial truth. Vendor feeds lie by omission: a row disappears instead of reporting zero stock, a field goes blank instead of saying discontinued. If your sync treats missing data as unchanged data, it keeps selling what the vendor stopped carrying weeks ago.
Third, cost drift. The price column updates silently and your margin leaks on every sale until someone notices a report. Stock sync that ignores cost is only solving half the problem.
Fourth, ghosts. Products that exist in your catalog but no feed claims — they stay purchasable forever unless something explicitly retires them.
The architecture that holds
The pipeline that survives production looks like five stages, and the mistake is collapsing them into one cron job.
Ingest each vendor however they send it — API, CSV drop, portal export — but land it raw and timestamped. Never normalize at fetch time; you want the ability to replay exactly what the vendor said.
Normalize next: one canonical product/variant/stock schema regardless of source. Twelve vendors arrive as twelve dialects and leave as one language. This is the stage cheap sync tools skip, and it's why they can't scale past two feeds.
Match against your catalog through a durable mapping — vendor SKU to Shopify variant ID, maintained explicitly, with unmatched items surfaced as a queue, not silently skipped.
Diff before you write. Compare normalized feed state to current Shopify state and compute the delta — what's new, what changed, what's gone. Blind writes are how you get 40,000 API calls to change 200 products.
Then sync the delta, and grade every run. Each pass produces a report: rows ingested, matched, changed, errors, anomalies. A run that looks wrong gets held and flagged instead of pushed live — that's the difference between automation and scheduled damage.
The edge cases nobody warns you about
Sets and bundles. A bedroom set is one vendor record and four Shopify products — or the reverse. Splitting needs rules per vendor, not per product.
Shared stock. Two storefronts drawing from one warehouse can each individually look correct while together overselling. Sync has to reason about the pool, not the channel.
Rate limits at the worst time. Vendor APIs throttle hardest during their own sale events — exactly when stock moves fastest. Retry budgets and run schedules need to expect it.
The 3 AM problem. Feeds break at night and nobody reads cron logs. The fix isn't more logging — it's a watchdog that grades runs and raises a flag a human actually sees before trading hours.
We run this pipeline for a live retailer today: 42,865+ products, 12 vendor feeds, 4 storefronts. Every failure mode above is on that list because it happened on ours.
The short checklist
If you're evaluating any sync — app, agency, or in-house — ask five questions: Does it maintain an explicit vendor-to-store SKU map? Does missing data mean zero or unchanged? Does it diff before writing? Does it sync cost as well as stock? And what grades each run before it can hurt you?
Five yeses is a system. Anything less is a cron job with a UI.
We run this system, not just write about it.
The sync described above keeps 42,865+ products correct across 12 vendor feeds and 4 storefronts, graded by a watchdog on every run.