Skip to content

Shopify Dude Fix

Shopify Inventory Syncs in 2026: Compare-and-Swap and Idempotency

Shopify inventory mutations changed in API 2026-04. Learn when to use changeFromQuantity, why idempotency keys matter, and how to stop ERP syncs overwriting fresh sales.

Type: Complete Guide · Stage: Optimize / Scale · Topic: Data + AI Commerce / Inventory

On this page

Quick answer

If an ERP, WMS, or custom inventory sync fails after upgrading to the 2026-04 or later Shopify Admin API, review the mutation’s concurrency and idempotency requirements. For inventorySetQuantities, use changeFromQuantity rather than older compareQuantity examples, and supply an @idempotent key. Read the current quantity before writing when you need compare-and-swap protection. An absolute stock write is appropriate only when your integration truly owns that inventory quantity.

Why this matters

Imagine Shopify shows 100 units. Your sync reads 100 and decides to set 90. A customer buys 20 units before the sync writes. Without a comparison, the integration can write 90 over the legitimate new quantity of 80. Compare-and-swap rejects the stale update so the integration can re-read and reconcile rather than silently inflate inventory.

Idempotency solves a different problem: if a request times out after Shopify processes it, retrying the same adjustment must not apply it twice. An idempotency key identifies one logical operation across retries. These protections are complementary, not interchangeable.

What changed

Shopify’s 2026-04 API release introduced the changeFromQuantity approach across inventory mutations and requires idempotency for specified operations. In current examples for inventorySetQuantities, the expected existing quantity is carried in changeFromQuantity, and the mutation includes @idempotent(key: $idempotencyKey). Be careful: older compareQuantity examples can still appear on documentation pages. Use the current, idempotency-enabled example for your target API version.

Practical implementation

  1. Identify your source of truth. If an ERP sends authoritative absolute balances, inventorySetQuantities may be appropriate. If your app is applying a stock change rather than asserting an absolute balance, consider inventoryAdjustQuantities.
  2. Work at the inventory-item and location level. A SKU alone is not a safe identifier for every stock write. Resolve the inventory item and location, and check whether that inventory level is active.
  3. Read the current quantity. Include it as changeFromQuantity so a concurrent update produces a detectable conflict.
  4. Use a stable idempotency key per logical write. Reuse the same key for retries of the same operation; use a new key for a genuinely new stock update.
  5. Inspect GraphQL userErrors. A successful HTTP response does not mean the inventory mutation succeeded. Handle stale-quantity errors by re-reading and reconciling, not by blindly disabling the check.
  6. Log the audit trail. Include a meaningful referenceDocumentUri and reason. Record old quantity, intended new quantity, location, source record ID, and result.

GraphQL example for API 2026-10

mutation InventorySet(
  $input: InventorySetQuantitiesInput!,
  $idempotencyKey: String!
) {
  inventorySetQuantities(input: $input)
    @idempotent(key: $idempotencyKey) {
    userErrors { code field message }
    inventoryAdjustmentGroup {
      reason
      changes { name delta quantityAfterChange }
    }
  }
}

Example variables for one test inventory item:

{
  "input": {
    "name": "available",
    "reason": "correction",
    "referenceDocumentUri": "logistics://erp/stocktake/12345",
    "quantities": [{
      "inventoryItemId": "gid://shopify/InventoryItem/123",
      "locationId": "gid://shopify/Location/456",
      "quantity": 42,
      "changeFromQuantity": 40
    }]
  },
  "idempotencyKey": "REPLACE-WITH-ONE-STABLE-UUID-PER-OPERATION"
}

Replace all sample IDs, values, and the idempotency key. Do not run an example mutation against production inventory.

Common misunderstanding

“I can just set changeFromQuantity to null.” That is an explicit opt-out of the comparison, not a fix for concurrent updates. It can be valid for a carefully controlled source-of-truth reconciliation, but it removes a safety net.

“Idempotency fixes stale reads.” It does not. Idempotency protects duplicate execution of the same request; compare-and-swap protects against an outdated view of stock.

How to test this

  1. On a development store, read a known inventory quantity and send a valid idempotent write with the expected changeFromQuantity.
  2. Repeat the same logical request with the same idempotency key. Verify it does not double-apply.
  3. Change the quantity through another process, then retry a write with a stale expected quantity. Verify a user error rather than an overwrite.
  4. Test separate locations and inactive inventory levels; Shopify’s 2026-04 inventory changes distinguish stored quantity from active sellable inventory.
  5. Run a limited production reconciliation with logging and alerting before enabling full ERP synchronization.

Sources and further reading

Documentation checked October 9, 2026.