Manage Products

Inventory API Overview

Adjust inventory quantities and review inventory changes for products in a Square Catalog.

The Connect v2 Inventory API replaces the Connect v1 Inventory API and introduces new functionality:

  • Moving item variations quantities through predefined states (e.g., from IN_STOCK to WASTE).
  • Viewing the inventory adjustment history for an item variation.
  • Batch inventory adjustments and information retrieval.

Requirements and limitations

  • The Inventory API is only available for applications using Square-Version 2018-09-18 or later. See the Connect V2 API Versioning Overview for more details.
  • Inventory quantities can only be tracked on Square CatalogItemVariations. See the Catalog API Overview for more information on the Square Catalog.
  • Inventory API does not support tracking for fractional quantities, subcomponents, ingredients, and product bundling.
  • Anonymous Inventory API calls are not allowed. All Inventory API calls must include an authorization token for the targeted Square account.
  • All applications using OAuth to read inventory information must have INVENTORY_READ permissions for the targeted Square account.
  • Applications using OAuth to modify inventory quantities must have INVENTORY_WRITE permissions for the targeted Square account.
  • The Inventory API is not supported in the sandbox.

How to use it — the Inventory API data model

The Inventory API accepts inventory adjustments and physical counts for quantities of item variations and transitions those quantities to the relevant inventory state. Key data types for the Inventory API are:

  • InventoryCount — The computed quantity of an item variation at a specific location with a specific inventory state.
  • InventoryAdjustment — The quantity of an item variation transitioning from one inventory state to another.
  • InventoryPhysicalCount — The verified quantity of an item variation at a specific location with a specific state as determined by a manual count or trusted system.
  • InventoryTransfer — The quantity of an item variation transitioning from one location to another. Inventory transfer information is currently read-only in the API. Transfer functionality is limited to the Items Dashboard for Retail subscribers.
  • SourceApplication — Information about the application that applied an inventory change. SourceApplication records provide traceability for inventory changes.

InventoryCount and InventoryPhysicalCount objects are similar in that they both indicate the current quantity of a CatalogItemVariation, but InventoryPhysicalCount is a provided value and InventoryCount is a computed value.

InventoryPhysicalCount represents the quantity of an item variation that is physically present. For example, a physical count might come from an employee counting the item variations on hand or from syncing with an external system. InventoryCount represents the quantity Square thinks is present based on the known sequence of inventory adjustments since the last physical count update. In an ideal world, the values of InventoryCount and InventoryPhysicalCount are identical. But in most cases, item loss, accidental damage, and human error will create discrepancies between InventoryCount and InventoryPhysicalCount.

As a specific example, consider the case where a merchant receives a quantity of dog collars into inventory, sells some, accidentally damages some, and then re-counts them at the end of the day to reconcile their inventory. Initially, there are no collars in stock. Before opening the store in the morning, the merchant receives 100 small leather collars from a vendor and adds them to inventory by transitioning 100 units from NONE to IN_STOCK to make them available for sale. During the course of the day:

  • The merchant sells 3 collars to a customer in the store using Square Point of Sale, which automatically moves 3 units from IN_STOCK to SOLD.
  • An online customer buys 1 collar on the store site (built with Square APIs), which moves 1 unit from IN_STOCK to SOLD.
  • An accident in the store damages 2 collars so the merchant manually transitions 2 units from IN_STOCK to WASTE because they are no longer available for sale.

At this point, the calculated inventory count for small leather collars in the IN_STOCK state is: 100 − 3 − 1 − 2 = 94 units.

At the end of the day, the merchant closes the store and counts all the small, leather collars in the store and finds that there are only 93 collars available for sale. To reconcile the computed and verified counts, the merchant pushes the physical count to Square, which updates the IN_STOCK quantity of small leather collars to 93.

Example inventory tracking

The key thing to understand is that inventory adjustments are handled by moving quantities of item variations at a given location from one state to another rather than assigning and decrementing a single quantity.

Batched state transitions

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:

  • 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.
Example batch update

The individual changes in a batched state changes are recorded based on their individual client timestamps but they are applied, all-or-nothing, as a single request. Assuming the inventory count for the targeted catalog item variation starts at 0:

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

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

Inventory quantities are also affected by Square payment APIs and Point of Sale applications. In the example above, when the Square Point of Sale app records a transaction, it moves 3 units from the IN_STOCK state to the SOLD state. Assuming the transaction timestamp places it after the batch update succeeds, the new calculated inventory count for IN_STOCK units will be 87 units.

Special InventoryState values

NONE

The NONE state is not 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.

IN_STOCK

The IN_STOCK state does not represent a pool of available items decremented over time. Item variation quantities move into, and out of, the IN_STOCK state as they do with any other state. In general, when quantities move between states, the total quantity for that item variation across all states does not 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 3 units become damaged, there are still 100 units at the end of the day: 97 units in the IN_STOCK state and 3 in the WASTE state. The IN_STOCK state is only special in that the Square Point of Sale app and Square Dashboard use the quantity of item variations with IN_STOCK state to determine the number of units currently available for sale.

SOLD

SOLD 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 5 units are sold online and 3 units are sold in the store, there will be 92 units tracked at the end of the day. If a customer then returns 2 units in the store, there will be 94 units tracked: 92 units with IN_STOCK state and 2 units with RETURNED_BY_CUSTOMER state.

Automatic IN_STOCK adjustments

If inventory tracking is enabled in 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 Transactions API request that links to an itemized Order object containing three catalog line items: a small leather dog collar, a 5 foot retractable leash, and chicken "chewy trainer" treats.

Automatic updates

When the Charge endpoint processes the transaction, Square automatically adjusts the IN_STOCK quantities by moving 1 unit of the small leather collar from IN_STOCK to SOLD, 1 unit of the 5 foot retractable leash from IN_STOCK to SOLD, and 2 units of Chewy chicken trainer treats from IN_STOCK to SOLD.

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. DO NOT use InventoryPhysicalCount to apply sequential adjustments to CatalogItemVariation quantities. Retrieving an InventoryCount from the server, modifying the count based on recent changes, then pushing the updated inventory count as an InventoryPhysicalCount forces Square to ignore changes that may have occurred in the interim and results in inaccurate tracking.

Consider the case where the Square Point of Sale app captures a sale after the InventoryCount request but before the InventoryPhysicalCount update.

Timeline bad

Assume an application knows that 3 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 Point of Sale application captures a sale of 2 units and moves those 2 units from IN_STOCK to SOLD. There are now 8 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 3, the final quantity of IN_STOCK units is forced to be 7 units (10 IN_STOCK units − 3 units sold externally) when it should be 5 units (10 IN_STOCK units − 2 units sold through Square Point of Sale − 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 3 units sold externally after subtracting the 2 units sold through Square Point of Sale app.

How it works — The Inventory API process flow

Inventory tracking overview

There are 4 key endpoints provided by the Inventory API:

  • RetrieveInventoryCount — Retrieves the current, computed count for an item variation at the given location for a specific state (e.g., IN_STOCK).
  • BatchRetrieveInventoryCounts — Retrieves the current, computed count for one or more item variation.
  • BatchRetrieveInventoryChanges — Retrieves the change history for one or more item variation based on location and state for the specified point in time.
  • BatchChangeInventory — Pushes 1 or more adjustment or physical count to Square.

The Inventory API also includes endpoints for reporting on inventory change history (RetrieveInventoryAdjustment and RetrieveInventoryPhysicalCount). See the Inventory API Technical Reference for more information on all the Inventory API endpoints.

Client timestamp versus adjustment request order

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 0.

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 app processes transactions in offline mode while a custom inventory management solution makes inventory adjustments through the API.

Timeline good

Assume the related item variation starts with 100 IN_STOCK units.

  1. At 13:10 GMT, the inventory management backend sends an InventoryAdjustment request using the Inventory API to record a sale through a non-Square system and move 3 units from IN_STOCK to SOLD. At this point, there are 97 IN_STOCK units.
  2. At 13:20 GMT, the Square Point of Sale device goes offline. The merchant sells 2 units in offline mode with a recorded transaction time of 13:20 GMT.
  3. At 13:30 GMT, the inventory management backend sends an 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).
  4. At 13:35 GMT, the Square Point of Sale device reconnects to the internet and pushes the offline sale to Square, which moves 2 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 Point of Sale 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 client timestamp was the InventoryPhysicalCount request.
  5. At 13:40 GMT, the inventory management backend sends another InventoryAdjustment request using the Inventory API to move 2 from IN_STOCK to WASTE because they are 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 2 units.

Supported state transitions

Inventory state transitions represent real world changes to inventory quantities. As a result, some state changes are permitted (e.g., IN_STOCK to SOLD) while others are not (e.g., WASTE to RETURNED_BY_CUSTOMER). Square supports the following inventory state transitions:

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 and the return is not affiliated with a specific transaction.
UNLINKED_RETURN WASTE A quantity of items was returned by the customer and deemed to be unsellable and the return is not affiliated with a specific transaction.

In addition to the support state transitions above, the Inventory API may 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.

The ignore_unchanged_counts flag

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 Square Dashboard with necessary adjustments.

ignore_unchanged_counts is enabled by default so developers do not inadvertently spam Square servers with redundant InventoryPhysicalCount requests. Do not disable the ignore_unchanged_counts flag unless the associated InventoryPhysicalCount request represents a true reconciliation, such as an actual physical count by a person.

Next
Inventory API Setup >

Contact Developer Support, join our Slack channel, or ask for help on Stack Overflow