Applies to: Inventory API
Learn about the inventory process flow and how the Inventory API works.
Applies to: Inventory API
Learn about the inventory process flow and how the Inventory API works.
Inventory unit counts are calculated by applying all the adjustments received since the last recorded physical count. If no physical count has been recorded, the adjustments are applied with an assumed starting unit quantity of zero.
Inventory changes (including changes due to sales transactions) can be sent to Square out of order. As a result, adjustments and physical count updates require a client-specified RFC 3339 timestamp (occurred_at
) so the inventory history can be ordered correctly.
Consider a situation where the Square Point of Sale (POS) application processes transactions in offline mode while a custom inventory management solution makes inventory adjustments through the API.
Assume that the related item variation starts with 100 IN_STOCK units.
InventoryAdjustment
request using the Inventory API to record a sale through a non-Square system and move three units from IN_STOCK
to SOLD
. At this point, there are 97 IN_STOCK
units.InventoryPhysicalCount
request using the Inventory API to reconcile the computed quantity in the Square inventory service (97 units) with a verified physical quantity available for sale (90 units).IN_STOCK
units to SOLD
. Square applies the transaction results, with a client timestamp of 13:20 GMT, before the InventoryPhysicalCount
request that occurred at 13:30 GMT. Although the POS transaction was the last change sent to Square, the IN_STOCK
quantity is still 90 units, as indicated by the physical count update, because the last change according to the client timestamp was the InventoryPhysicalCount
request.InventoryAdjustment
request using the Inventory API to move two from IN_STOCK
to WASTE
because they're no longer suitable for sale. The InventoryAdjustment
request has a client timestamp that happens after the count reconciliation so the IN_STOCK
count is now 88 units and the WASTE
count is two units.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. Don't use InventoryPhysicalCount
to apply sequential adjustments to CatalogItemVariation
quantities. Retrieving an InventoryCount
from the server, modifying the count based on recent changes, and pushing the updated inventory count as an InventoryPhysicalCount
forces Square to ignore changes that might have occurred in the interim and results in inaccurate tracking.
Consider the case where the Square POS application captures a sale after the InventoryCount
request but before the InventoryPhysicalCount
update.
Assume that an application knows that three units were sold through a non-Square channel. The application calls the Inventory API and the InventoryCount
result indicates 10 units in the IN_STOCK
state. At the same time, the Square POS application captures a sale of two units and moves those two units from IN_STOCK
to SOLD
. There are now eight units in the IN_STOCK
state.
Based on the InventoryCount
result, the application incorrectly believes there are currently 10 units in the IN_STOCK
state. If the application uses InventoryPhysicalCount
to reduce the IN_STOCK
quantity by three, the final quantity of IN_STOCK
units is forced to be seven units (10 IN_STOCK
units − 3 units sold externally) when it should be 5 units (10 IN_STOCK
units − 2 units sold through the Square POS application − 3 units sold externally).
The correct way to track sales through a non-Square system is to push an InventoryAdjustment
that moves units from IN_STOCK
to SOLD
. Inventory adjustments force Square systems to apply inventory changes in the correct order rather than explicitly overwriting the count. For example, by subtracting the three units sold externally after subtracting the two units sold through the Square POS application.
Square servers record inventory operations based on timestamps provided by the communicating client and batched updates succeed or fail as atomic operations. For example, consider the case where a single request batches the following changes for a single item variation:
NONE
state to the IN_STOCK
state.IN_STOCK
state to the WASTE
state.Individual changes in a batched state are recorded based on their individual client timestamps, but they're applied (all or nothing) as a single request. Assuming that the inventory count for the targeted catalog item variation starts at zero:
NONE
to IN_STOCK
with a timestamp of 23:00 GMT, making the calculated inventory count 100.IN_STOCK
to WASTE
with a timestamp of 23:10 GMT, making the calculated inventory count 95.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 Square payment APIs and POS applications. In the previous example, when the Square POS application records a transaction, it moves three units from the IN_STOCK
state to the SOLD
state. Assuming that the transaction timestamp places it after the batch update succeeds, the new calculated inventory count for IN_STOCK
units is 87.
The NONE
state isn't a true inventory state. NONE
is a from_state
placeholder to represent the fact that a given CatalogItemVariation
was introduced as new inventory. Inventory quantities can be transitioned from the NONE
state, but cannot be transitioned to the NONE
state.
The IN_STOCK
state doesn't represent a pool of available items decremented over time. Item variation quantities move in to and out of the IN_STOCK
state as they do with other states. In general, when quantities move between states, the total quantity for that item variation across all states doesn't change. For example, consider the item variation "Small Leather Collar" with a total of 100 units. Initially, all 100 units are in the IN_STOCK
state. If three units become damaged, there are still 100 units at the end of the day: 97 units in the IN_STOCK
state and three in the WASTE
state. The IN_STOCK
state is only special in that the Square POS application and Seller Dashboard use the quantity of item variations with the IN_STOCK
state to determine the number of units currently available for sale.
The SOLD
state is a terminal state. When inventory items move to the SOLD
state, the units are no longer explicitly tracked. Transferring quantities from SOLD
to some other state introduces a new quantity into inventory rather than changing the quantity in the SOLD
state. For example, consider the case where "Small Leather Collar" has 100 units in the IN_STOCK
state. If five units are sold online and three units are sold in the store, there are 92 units tracked. If a customer returns two units to the store, there are 94 units tracked: 92 units with the IN_STOCK
state and two units with the RETURNED_BY_CUSTOMER
state.
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:
From state | To state | Related event |
---|---|---|
NONE | IN_STOCK | A quantity of items was received and is available for sale. |
IN_STOCK | SOLD | A quantity of items was sold. |
IN_STOCK | WASTE | A quantity of items was damaged or lost and cannot be sold. |
UNLINKED_RETURN | IN_STOCK | A quantity of items was returned by the customer and is available for sale. The return isn't affiliated with a specific transaction. |
UNLINKED_RETURN | WASTE | A quantity of items was returned by the customer and deemed to be unsellable. The return isn't affiliated with a specific transaction. |
In addition to the support state transitions, the Inventory API might return additional read-only states as part of the change history for a given item variation. Transitions to or from read-only states can only be triggered from within Square products.
If inventory tracking is enabled in the Seller 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.
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
.
Requests to the BatchChangeInventory
endpoint include an ignore_unchanged_counts
flag. The ignore_unchanged_counts
flag tells Square to skip updates for the CatalogItemVariation
if nothing has changed. When the new physical count for a CatalogItemVariation
is the same as the previous physical count and no InventoryAdjustment
requests have been received between the two physical counts, the physical count update is skipped. The ignore_unchanged_counts
flag lets third-party systems push potentially redundant inventory counts to Square without polluting the Seller Dashboard with unnecessary adjustments.
The ignore_unchanged_counts
flag is enabled by default so developers don't inadvertently spam Square servers with redundant InventoryPhysicalCount
requests. Don't disable the ignore_unchanged_counts
flag unless the associated InventoryPhysicalCount
request represents a true reconciliation, such as an actual physical count by a person.
If you need more assistance, contact Developer and App Marketplace Support or ask for help in the Developer Forums.