Shopify Incoming Inventory API Issues

A clear explanation of fundamental problems affecting app developers and merchants.

The Core Problem in Brief

The root of these issues is that Shopify's API abstracts away critical information. Apps cannot distinguish their inventory contribution from other sources (like Shopify POs) and cannot see the underlying ledger structure. This forces developers to operate blindly, leading to hidden, uncorrectable inventory states.

Issue 1: "Stuck" Incoming Inventory After App Uninstallation

When a merchant uninstalls an app, Shopify immediately severs all permissions, preventing the app from making any further changes. Although apps are required to delete their data upon uninstallation, any "incoming" inventory adjustments they created—whether positive or negative—remain on the product.

Because the app's connection is terminated, it has no opportunity to clean up or "zero out" these leftover quantities. This leaves the inventory in a "stuck" state. The merchant is unable to resolve these lingering incoming inventory figures because the app that created them is no longer present to manage them.

The only way for a merchant to fix this is to reinstall the app solely for the purpose of having the app correct the inventory. This problem persists even if an app is behaving perfectly, as it is a fundamental limitation of the uninstall process COMBINED with a decision by Shopify to not "zero out" incoming inventory from apps when they are uninstalled.

Issue 2: The Inability of Apps to "Zero Out" Their Own Inventory

The fundamental problem is that an app cannot isolate and remove only its own contribution to a product's "incoming" inventory. This issue stems from the behavior of Shopify's inventoryAdjustQuantities API mutation.

Key Components of This Issue:

  • Net Total vs. App-Specific Inventory: The API only allows an app to see and modify the net total incoming inventory for a product. This net figure is the sum of all incoming sources, including Shopify Purchase Orders (POs) and any adjustments from apps.
  • Lack of Visibility: An app has no way to see the specific incoming quantity contributed by Shopify POs or other sources. It also cannot see its own true value stored by Shopify; it can only see the final net total.

The "Zeroing Out" Paradox in Action:

1. A product has +10 units incoming from a Shopify PO.

2. An app attempts to remove its influence by using the API to set its incoming quantity to 0.

3. However, the API interprets this as a command to set the net total incoming quantity to 0.

4. To make the math work (10 - 10 = 0), Shopify forces the app's contribution to become -10 units.

Therefore, the act of setting the app's value to "0" perversely results in it becoming a negative number. The app is then "stuck," as it cannot know the correct value needed to truly offset its influence. This is caused by the "lack of visibility". This behavior puts apps in an impossible situation where they cannot function correctly.

Issue 3: Hidden "per-Ledger" Balances Complicate Zeroing Out

A further complication exists even when an app attempts to zero itself out. Shopify tracks incoming inventory not just as a total, but on a per-ledgerDocumentUri basis.

The problem occurs if an app does not use the identical ledgerDocumentUri when both increasing and decreasing inventory:

  • An app adds +10 units with ledgerDocumentUri: "doc-A".
  • Later, it attempts to cancel this by subtracting 10 units, but uses ledgerDocumentUri: "doc-B".

Instead of canceling each other out, this creates two separate, hidden ledger entries: one for `+10` and another for `-10`. While the app's net incoming quantity may appear as `0` in the UI, these underlying non-zero balances remain and can block other critical store functions, such as deactivating a location.

This behavior is undocumented and the per-URI balances are completely invisible to both apps and merchants. It is impossible for a developer to diagnose or correct this issue without Shopify Support manually providing a report of the hidden ledger entries.

Frequently Asked Questions

Q: Is this caused by an app failing to delete its purchase orders?

A: No. The issue is not dependent on app-created purchase orders. Issue 2 can occur even if an app is never uninstalled. The core problem lies in how the API calculates and exposes incoming inventory, not in app data management.

Q: Why can't the app just fix the negative inventory?

A: An app cannot see its own incoming inventory value versus Shopify's. It only sees the net total incoming. To "fix" a -10 value it doesn't know exists, it would need to know the Shopify PO quantity (+10) and add that amount. The API provides no way for the app to get this information.

Q: Doesn't the inventoryAdjustQuantities mutation only affect "Available" inventory?

A: No, that is incorrect. This mutation is allows for an app to programmatically adjust "Incoming" inventory quantities. This issue has absolutely nothing to do with "Available" inventory.

Q: Is the app deleting or nullifying Shopify Purchase Orders?

A: No. There is no API for an app to delete Shopify Purchase Orders. The app's action of setting the net incoming inventory to zero has the net effect of zeroing the incoming quantity from a Shopify PO.

Q: Can't the merchant just correct the "stuck" inventory themselves?

A: No. There is no interface in the Shopify admin for a merchant to manually edit or remove the individual incoming inventory contributions from a specific app. Their only recourse is to reinstall the app and have it attempt a correction, which is not truly possible due to the "zeroing out" paradox.

Q: What is the `ledgerDocumentUri` and why is it so important?

A: It's an identifier for a specific inventory adjustment. Shopify treats each URI as a self-contained ledger. If an app doesn't use the exact same URI to decrease inventory as it did to increase it, the balances won't cancel out, creating hidden non-zero entries. This is critical because this behavior is undocumented and the data is not visible through the API or UI, making it impossible for developers to handle correctly without Shopify's direct assistance.

Q: Does this relate to merchant managed locations or app managed locations?

A: I believe that it's both.

Q: Does our upcoming inventory transfers API's resolve any of this?

A: No. An app might be able to avoid issues 2 and 3 if they use that API exclusively. However, once an app uses the regular API, then it is susceptible all of the issues. I don't know how Shopify handles inventory transfers when an app is uninstalled.

Q: Why are specific examples (SKUs, timestamps) not relevant for this issue?

A: While specific examples can illustrate the problem, the issue itself is not with a specific merchant, variant, or timeframe. It is a fundamental flaw in the behavior of the Shopify API itself. Focusing on individual cases distracts from the need to address the systemic problem.