Inventory API Process Flow

Applies to: Inventory API

Learn about the inventory process flow and how the Inventory API works.

Link to section

Overview

Square tracks inventory by adding up all adjustments since the last physical count. If a seller has never done a physical count, Square starts from zero.

Because inventory adjustments and physical counts can arrive in any order (like when processing offline sales), each update needs a client-generated RFC 3339 timestamp. This helps Square put all changes in the right sequence. For example, an item variation starts with 100 units. Updates might come from both offline POS sales and your application's API calls. The RFC 3339 timestamp includes time zone information that's taken into account when Square determines the order of inventory transactions.

Did you know?

When automatic inventory tracking is enabled, Square automatically updates seller inventory counts whenever an Order is completed through the Orders API. In this case, step one in the following example is done by Square when your Order is completed.

  1. At 1:10 PM GMT, your application sends a BatchChangeInventory request (type ADJUSTMENT) to record a sale of 3 items. This reduces the in-stock count from 100 to 97.
  2. At 1:20 PM, the POS goes offline. During this time, the seller:
    1. Sells 2 items.
    2. Starts counting their remaining inventory.
  3. At 1:30 PM, the seller counts 95 items. Your application sends a BatchChangeInventory request (type PHYSICAL_COUNT) to update Square's system from its calculated count of 97 to the actual count of 95.
  4. At 1:35 PM, the POS reconnects and reports the offline sale of 2 items (type IN_STOCK to SOLD). Even though this update arrives last, Square applies it using its original timestamp (1:20 PM), before the BatchChangeInventory physical count at 1:30 PM. The final count stays at 95 because the physical count has the latest timestamp.
  5. At 1:40 PM, your application sends a BatchChangeInventory request to move 2 items from IN_STOCK to WASTE. Because this timestamp is after the physical count, the system updates to 93 items in stock and 2 in waste.

A diagram showing inventory state transitions involving a Square application, the Square backend, and Square Point of Sale.

Link to section

Reconciliation with InventoryPhysicalCount

InventoryPhysicalCount should only be used to reconcile the inventory count computed by Square with the results of performing a physical count or syncing with a trusted external system.

Warning

Don't calculate inventory levels and return them to Square as a physical count. Your application might miss sales made through Square POS while offline, leading to incorrect calculations. A physical count adjustment should be based on an actual count of items at a location and posted with the correct occurred_at time.

Consider the case where Square Point of Sale captures a sale after your application gets an inventory count from Square but before your application sends a new physical count.

In the following example, the application subtracted an arbitrary 3 units from the last calculated stock level and returned it as a new physical count. Had the seller done an actual physical count before sending the inventory physical count, they would have accounted for the 2 offline sales that were made. Because Square Point of Sale was offline, Square sent an inventory count of 10 rather than 8.

An image showing an Inventory API reconciliation flow  done incorrectly.

In this example, the application knows that 3 units were sold through a non-Square channel. It calls the Inventory API, which shows 10 units in IN_STOCK. Meanwhile, Square Point of Sale sells 2 units, moving them from IN_STOCK to SOLD, leaving 8 units in IN_STOCK.

The application incorrectly believes there are 10 units in IN_STOCK. If it uses InventoryChange.type == PHYSICAL_COUNT to reduce the count by three, it forces the count to seven units (10 – 3), instead of the correct five units (10 – 2 – 3).

If your application doesn't integrate the Orders API to track sales, you can track sales made through your application using BatchChangeInventory with InventoryChange.type == ADJUSTMENT, which ensures that inventory changes are applied in the correct order.

An image of an Inventory API reconciliation flow done correctly.

Link to section

Batched state transitions

Square records inventory operations based on client timestamps and batched updates succeed or fail as atomic operations. For example, one request batches these changes for a single item variation:

  • 100 units move from the NONE state to the IN_STOCK state.
  • 5 units move from the IN_STOCK state to the WASTE state.
  • Record a physical count of 90 units.

A diagram showing batch inventory state transitions.

Each change in a batch request is recorded with its own timestamp, but all changes are applied together as a single request. Assuming the inventory count for the catalog item starts at zero:

  1. 100 units move from NONE to IN_STOCK with a timestamp of 11:00 PM GMT, making the calculated inventory count 100.
  2. 5 units move from IN_STOCK to WASTE with a timestamp of 11:10 PM, making the calculated inventory count 95.
  3. Square records a physical count of 90 units with a timestamp of 11:30 PM, resetting the calculated inventory count to 90.

If all three changes succeed, the new calculated inventory count for IN_STOCK units is 90. However, if any of the individual changes fail, the entire update fails and the calculated inventory count remains unchanged at zero.

Inventory quantities are also affected by the Square Orders API and POS applications. For example, when the Square Point of Sale records an order, it moves 3 units from IN_STOCK to SOLD. If the order timestamp is after the batch update, the new IN_STOCK count is 87.

Link to section

Special InventoryState values

Link to section

NONE

NONE isn't an actual inventory state; it's just a placeholder used when a new CatalogItemVariation is initially added to the system. While inventory can move from NONE to other states, nothing can move back to NONE.

Link to section

IN_STOCK

Items can move both in and out of the IN_STOCK state. This movement doesn't reduce the total quantity, it just tracks which state items are in.

For example, if an item has 100 units and 3 units are damaged, you have 97 units in IN_STOCK and 3 in WASTE, still totaling 100 units. The IN_STOCK state is special because Square Point of Sale and Square Dashboard use it to show available units for sale.

Link to section

SOLD

The SOLD state is a final state where units are no longer tracked. Moving quantities from SOLD to another state adds new inventory instead of changing the SOLD quantity.

For example, if "Small Leather Collar" has 100 units in IN_STOCK and 8 units are sold, 92 units remain tracked. If 2 units are returned, there are 94 units tracked: 92 in IN_STOCK and 2 in RETURNED_BY_CUSTOMER.

Link to section

Supported state transitions

Inventory state transitions represent real-world changes to inventory quantities. As a result, some state changes are permitted (such as IN_STOCK to SOLD) while others aren't (such as WASTE to RETURNED_BY_CUSTOMER). Square supports the following inventory state transitions:

An updated diagram showing supported inventory state transitions.

From state To state Related event
NONEIN_STOCKA quantity of items was received and is available for sale.
IN_STOCKSOLDA quantity of items was sold.
IN_STOCKWASTEA quantity of items was damaged or lost and cannot be sold.
UNLINKED_RETURNIN_STOCKA quantity of items was returned by the customer and is available for sale. The return isn't affiliated with a specific transaction.
UNLINKED_RETURNWASTEA quantity of items was returned by the customer and deemed to be unsellable. The return isn't affiliated with a specific transaction.

The Inventory API might also show additional read-only states in the change history of an item variation. Transitions to or from these read-only states can only be initiated by Square products.

Link to section

Automatic IN_STOCK adjustments

If inventory tracking is enabled in the Square Dashboard, completing an itemized transaction with Square products automatically moves the quantity sold from the IN_STOCK state to the SOLD state.

For example, consider a Payment API request that references an Order object containing three catalog line items: a small leather dog collar, a 5-foot retractable leash, and Chewy chicken trainer treats.

A diagram showing the inventory state after the inventory count is reconciled.

When the CompletePayment or PayOrder endpoint is called to process the transaction, Square automatically adjusts the IN_STOCK quantities by moving one unit of the small leather dog collar from IN_STOCK to SOLD, one unit of the 5-foot retractable leash from IN_STOCK to SOLD, and two units of Chewy chicken trainer treats from IN_STOCK to SOLD.

Link to section

ignore_unchanged_counts flag

The BatchChangeInventory endpoint has an ignore_unchanged_counts flag (enabled by default) that skips inventory updates when:

  • The new count matches the previous count.
  • No adjustments occurred between counts.

This prevents duplicate entries in the Square Dashboard when third-party systems send repeated data. To record consecutive physical count adjustments with the same quantity, disable the flag.