GUARDLABS
GuardLabs ยท Technical note

Sync Inventory Between Your Online Store and Accounting Software via API

Automating inventory synchronization between an e-commerce platform (such as Shopify or WooCommerce) and accounting software (such as QuickBooks Online or Xero) prevents overselling and eliminates manual data entry errors. This guide outlines the architecture, data mapping, and implementation code required for a robust, event-driven API integration.

Integration Architecture: Webhooks vs. Polling

To keep stock levels aligned in near-real time, use an event-driven architecture based on webhooks rather than scheduled polling:

  • Webhooks (Event-Driven): Your store fires an HTTP POST payload to a custom middleware endpoint immediately when an order is placed, cancelled, or restocked. This minimizes API call volume and reduces sync delay.
  • Polling (Fallback Reconciliation): A scheduled background cron job queries both APIs daily to catch missed webhooks, reconcile discrepancies, and fix inventory drift.

Step 1: Map Core Identifiers and Attributes

Both systems must share a single source of truth for stock keeping. Standardize the following attributes before writing code:

  • SKU / Item Code: Must match exactly between the store product variant and the accounting item. Do not use platform-generated internal database IDs (e.g., Shopify variant_id vs. QuickBooks ItemRef).
  • Location Identifiers: Map store fulfillment location IDs to corresponding warehouse IDs or classes in your accounting software.
  • Adjustment Reasons: Standardize mapping for quantity updates (e.g., Sales Order, Return, Shrinkage, Restock).

Step 2: Implement the Webhook Listener & API Gateway

The middle tier receives the webhook, extracts the SKU and new stock quantity, looks up the target item in the accounting API, and posts an inventory adjustment.

Below is an Express.js (Node.js) sample demonstrating a complete flow from store webhook to accounting API update:

const express = require('express');
const axios = require('axios');
const app = express();

app.use(express.json());

// Endpoint receiving store inventory update webhooks
app.post('/api/webhooks/inventory-update', async (req, res) => {
  const { sku, updated_quantity, location_id } = req.body;

  if (!sku) {
    return res.status(400).send('Missing SKU identifier');
  }

  try {
    // 1. Fetch matching item from Accounting Software API
    const searchResponse = await axios.get(`https://api.accounting.com/v1/items`, {
      params: { sku: sku },
      headers: { 'Authorization': `Bearer ${process.env.ACCOUNTING_API_KEY}` }
    });

    const accountingItem = searchResponse.data.items[0];
    if (!accountingItem) {
      console.warn(`SKU ${sku} not found in accounting software.`);
      return res.status(404).send('Item not found in accounting software');
    }

    // 2. Push inventory adjustment to Accounting Software API
    await axios.post(`https://api.accounting.com/v1/inventory-adjustments`, {
      itemId: accountingItem.id,
      locationId: location_id,
      newQuantityOnHand: updated_quantity,
      transactionDate: new Date().toISOString()
    }, {
      headers: { 
        'Authorization': `Bearer ${process.env.ACCOUNTING_API_KEY}`,
        'Content-Type': 'application/json'
      }
    });

    return res.status(200).json({ status: 'success', syncedSku: sku });

  } catch (error) {
    console.error('Sync failed:', error.response?.data || error.message);
    
    // Return 500 so the e-commerce platform retries the webhook
    return res.status(500).send('Failed to push inventory update');
  }
});

app.listen(3000, () => console.log('Inventory sync service running on port 3000'));

Step 3: Handle Concurrency and API Rate Limits

Production environments require safeguards to maintain data integrity under heavy traffic:

  • Message Queues: Push incoming webhooks into a queue (e.g., Redis BullMQ, RabbitMQ, or AWS SQS) before calling the accounting API. This throttles outbound calls to prevent hitting rate limits (e.g., QuickBooks' 500 requests per minute limit).
  • Idempotency Controls: Store the unique event ID or high-resolution timestamp of each update. Ignore updates that arrive out of chronological order to prevent older stock counts from overwriting newer ones.
  • Dead-Letter Queues (DLQ): Route failed sync requests (e.g., missing SKUs or deleted items) to a DLQ for administrator review rather than discarding them.

Need this done fast? order an integration on FreelanceHunt.

Published 2026-07-30 3 min read All articles
Need help with this?

I take on freelance fixes and builds in this area.