Shopify

The Right Way to Set Up Inventory Sync Between Shopify and Your Accounting Software

Dean Robbins · · 4 min read

If you're running a Shopify store and using separate accounting software, you've probably tried to sync inventory between them. And if you have more than a handful of SKUs, you've probably experienced the pain of it breaking.

Here's why most sync setups fail, and how to build one that doesn't.

Why the obvious approach breaks

The most common setup I see is a third-party app from the Shopify App Store that "connects" Shopify to QuickBooks or Xero. These work fine when:

  • You have fewer than 100 SKUs
  • You're doing fewer than 50 orders a day
  • You don't have bundles, kits, or variants with complex rules
  • You never need to handle returns, exchanges, or partial shipments

Once you outgrow those constraints, the sync starts failing silently. Quantities drift. Orders show up in accounting without the right line items. Returns don't reverse correctly. And you end up reconciling everything manually anyway.

The architecture that holds up

Here's how I build inventory sync for clients who need it to work reliably at scale:

1. Pick a source of truth

For most businesses, Shopify is the source of truth for orders and your accounting/ERP system is the source of truth for inventory levels. Don't try to make both authoritative — that's how you get conflicts.

2. Use webhooks, not polling

Polling Shopify's API every 5 minutes for changes is slow and wastes API calls. Instead, register webhooks for the events you care about:

  • orders/create — new order placed
  • orders/updated — order modified (refund, cancellation)
  • products/update — product or variant changed

Your server receives these events in near real-time and processes them accordingly.

3. Build an idempotent sync layer

Network requests fail. Webhooks fire twice. APIs time out. Your sync layer needs to handle all of this gracefully.

Every sync operation should be idempotent — meaning you can run it twice with the same input and get the same result. Use unique identifiers (order ID, SKU) as keys, and upsert rather than insert.

4. Queue everything

Don't process syncs inline with the webhook request. Accept the webhook, validate it, and push it onto a queue. Process the queue with workers that can retry on failure.

This decouples your webhook response time from your sync processing time, and it means a slow API response from your accounting software doesn't cause Shopify to mark the webhook as failed.

5. Log aggressively

Every sync operation should log:

  • What was synced (order ID, SKU, quantities)
  • The source and destination
  • Whether it succeeded or failed
  • The raw API response

When something goes wrong — and eventually something will — these logs are the difference between a 5-minute fix and a 5-hour investigation.

6. Handle edge cases explicitly

The edge cases are where most sync setups die:

  • Bundles/kits: A single Shopify product might map to multiple inventory items. Your sync needs to know the component mapping.
  • Partial shipments: An order with 3 items might ship in 2 batches. Each shipment should update inventory independently.
  • Returns to a different warehouse: The return might go to a different location than it shipped from.
  • Manual adjustments: Someone physically counts inventory and updates it in the ERP. That change needs to flow back to Shopify.

Don't ignore these. Handle them explicitly in your sync logic, even if it's just logging a warning that says "manual review needed."

When to build vs. when to use an app

If your sync needs are simple and you're under 100 SKUs, a Shopify app is fine. Save your money.

If you're dealing with any of the edge cases above, or if you're doing enough volume that silent failures cost real money, build a custom sync. It's not as expensive as you think, and it pays for itself quickly in time saved and errors avoided.

Need help building a reliable sync? Learn more about my e-commerce solutions or my API integration services, or get in touch to talk it through.