Beta Release
This is pre-release documentation for an API in public beta and is subject to change.
Inventory API

Enable Stock Conversion

When a business receives, stocks, and sells a product in the same unit of measurement, basic inventory is sufficient to track inventory state transitions of item variations. For example, when a wine store receives, stocks, and sells by the bottle, it can use basic inventory to monitor its daily operations.

When a business receives or stocks a product in one unit of measurement and sells the product in multiple units, its inventory tracking must be able to account for conversions. For example, when a restaurant stocks its wine selection by the bottle, but serves the customer by the bottle or by the glass, its inventory system must be able to track inventory adjustments that account for different units of measurement to yield consistent results.

Important

To use stock conversion, you must have a Square for Retail Plus subscription.

Enable selling a product in multiple units Permalink Get a link to this section

A seller often stocks a product in the received or stocking unit and sells the product in different sale units. For example, a restaurant purchases and stocks a wine in bottles, but sells the wine by the bottle or by the glass. In this example, a bottle is the stocking unit and also a sale unit. On the other hand, a glass is only another sale unit.

To enable such business scenarios, the seller must determine the conversion between different units of measurement, according to the business requirements. For example, suppose that one bottle of wine can be converted into five glasses. When a customer orders one bottle of the wine, the wine's inventory counts should be decremented by 1 bottle or by 5 glasses. When a customer orders two glasses of the wine, the inventory counts should be decremented by 2/5 of a bottle or by 2 glasses. The stockable inventory count corresponds to quantities used for physical counts, whereas the non-stockable (in this case, a sellable-only) inventory count is computed based on its stock conversion specification.

In this topic, you learn how to use the Square Inventory API to maintain a component inventory of product variations in multiple units with a specified stock conversion.

Step 1: Create a product with stockable and sellable-only variations Permalink Get a link to this section

You can use the Square Catalog API to create items with item variations in different units of measurement.

Create an item with stockable and sellable-only variations using the Catalog API Permalink Get a link to this section

The following example uses the Catalog API to create a Red Wine item for sale with a Bottle variation to manage the stockable (and also sellable) inventory and a Glass variation to manage the sellable-only inventory count. The inventory quantities of the Bottle and Glass variations are synchronized according to the rule stipulated in the stockable_conversion object. In this example, one bottle equals five glasses.

The example request assumes that you have a CatalogTax object created for all your seller locations and this CatalogTax object is referenced by the ID KBPWWOXZHOGNOSQ2LIVS4H27. If your seller location has no sales tax, you can ignore the tax specification in the input.

The category of the item, as referenced by {"category_id": "JXVXTYYDLZRPXMQ7SMNJXVVG"}, refers to wine for sale at the seller locations.

In addition, you must have two different CatalogMeasurementUnit objects created, one (referenced by the {"measurement_unit_id" : "SQKOHTEZUX2QWIZXMH3Z5WGW"}) as the measurement unit of the stockable variation (Bottle) and the other (referenced by {"measurement_unit_id": "DPCQ2HA44EN3EIJT3WEXN5FE") as the measurement unit of the sellable-only variation (Glass) as the non-stockable. If a desired measurement unit does not exist, you can call UpsertCatalogObject separately to create it before making the following call. Alternatively, you can call BatchUpsertCatalogObjects to have the required measurement units and the items with stockable and non-stockable variations created all together.

Request Permalink Get a link to this section
Upsert Catalog Object
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
curl https://connect.squareupsandbox.com/v2/catalog/object \
  -X POST \
  -H 'Square-Version: 2021-09-15' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "idempotency_key": "{UNIQUE_ID}",
    "object": {
      "id": "#wine",
      "type": "ITEM",
      "item_data": {
        "name": "Red Wine",
        "product_type": "REGULAR",
        "tax_ids": [
          "KBPWWOXZHOGNOSQ2LIVS4H27"
        ],
        "description": "Vin Rouge",
        "variations": [
          {
            "id": "#bottle",
            "type": "ITEM_VARIATION",
            "item_variation_data": {
              "item_id": "#wine",
              "measurement_unit_id": "SQKOHTEZUX2QWIZXMH3Z5WGW",
              "name": "Bottle",
              "price_money": {
                "amount": 2500,
                "currency": "USD"
              },
              "pricing_type": "FIXED_PRICING",
              "sku": "wine-123-r",
              "stockable": true,
              "track_inventory": true
            },
            "present_at_all_locations": true
          },
          {
            "id": "#glass",
            "type": "ITEM_VARIATION",
            "item_variation_data": {
              "item_id": "#wine",
              "measurement_unit_id": "DPCQ2HA44EN3EIJT3WEXN5FE",
              "name": "Glass",
              "price_money": {
                "amount": 800,
                "currency": "USD"
              },
              "pricing_type": "FIXED_PRICING",
              "sku": "wine-123-r",
              "stockable": false,
              "stockable_conversion": {
                "nonstockable_quantity": "5",
                "stockable_item_variation_id": "#bottle",
                "stockable_quantity": "1"
              },
              "track_inventory": true
            },
            "present_at_all_locations": true
          }
        ],
        "category_id": "JXVXTYYDLZRPXMQ7SMNJXVVG"
      }
    }
  }'

Make sure that the two item variations subject to the stock conversion are assigned the same SKU value. Otherwise, you get two separate stockable variations.

When the request succeeds, a 200 OK response is returned with the body similar to the following:

Response Permalink Get a link to this section
{
  "catalog_object": {
    "type": "ITEM",
    "id": "WWXPVSBT3TUXKNXT3VSXQXMX",
    "updated_at": "2021-06-11T03:16:49.531Z",
    "version": 1623381409531,
    "is_deleted": false,
    "present_at_all_locations": true,
    "item_data": {
      "name": "Vin",
      "description": "Vin Rouge",
      "category_id": "JXVXTYYDLZRPXMQ7SMNJXVVG",
      "tax_ids": [
        "KBPWWOXZHOGNOSQ2LIVS4H27"
      ],
      "variations": [
        {
          "type": "ITEM_VARIATION",
          "id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
          "updated_at": "2021-06-11T03:16:49.531Z",
          "version": 1623381409531,
          "is_deleted": false,
          "present_at_all_locations": true,
          "item_variation_data": {
            "item_id": "WWXPVSBT3TUXKNXT3VSXQXMX",
            "name": "Bottle",
            "sku": "wine-123-r",
            "ordinal": 0,
            "pricing_type": "FIXED_PRICING",
            "price_money": {
              "amount": 2500,
              "currency": "USD"
            },
            "track_inventory": true,
            "measurement_unit_id": "SQKOHTEZUX2QWIZXMH3Z5WGW",
            "stockable": true
          }
        },
        {
          "type": "ITEM_VARIATION",
          "id": "IUD2QMXX4K62W35HW5CVQGL6",
          "updated_at": "2021-06-11T03:16:49.531Z",
          "version": 1623381409531,
          "is_deleted": false,
          "present_at_all_locations": true,
          "item_variation_data": {
            "item_id": "WWXPVSBT3TUXKNXT3VSXQXMX",
            "name": "Glass",
            "sku": "wine-123-r",
            "ordinal": 1,
            "pricing_type": "FIXED_PRICING",
            "price_money": {
              "amount": 800,
              "currency": "USD"
            },
            "track_inventory": true,
            "measurement_unit_id": "DPCQ2HA44EN3EIJT3WEXN5FE",
            "stockable": false,
            "composition_id": "LO3T2SO2RCEZXXJARZJJKPWI",
            "stockable_conversion": {
              "stockable_item_variation_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
              "stockable_quantity": "1",
              "nonstockable_quantity": "5"
            }
          }
        }
      ],
      "product_type": "REGULAR"
    }
  },
  "id_mappings": [
    {
      "client_object_id": "#wine",
      "object_id": "WWXPVSBT3TUXKNXT3VSXQXMX"
    },
    {
      "client_object_id": "#bottle",
      "object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ"
    },
    {
      "client_object_id": "#glass",
      "object_id": "IUD2QMXX4K62W35HW5CVQGL6"
    }
  ]
}

The ID of the stockable variation (#bottle) is PMUUU2EFXNRBKTUAMTC5SQTZ and the ID of the sellable-only variation (#glass) is IUD2QMXX4K62W35HW5CVQGL6. They are used later to adjust inventory counts when a bottle or glass is ordered.

Step 2: Add the stockable variation to the inventory Permalink Get a link to this section

In the example, a bottle is the unit of the stockable variation. When the seller takes delivery of N bottles of the wine, the quantity must be added to the seller's inventory. The associated inventory state changes from NONE to IN_STOCK.

Note

You can add the stockable variation to the inventory in the Items library in the Seller Dashboard. Look for Adjust Inventory or Manage stock.

To add a delivery of 24 bottles of wine to the inventory, call the BatchChangeInventory endpoint of the Inventory API on the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ). This is shown in the following example request:

Request Permalink Get a link to this section

Batch Change Inventory
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
curl https://connect.squareupsandbox.com/v2/inventory/changes/batch-create \
  -X POST \
  -H 'Square-Version: 2021-09-15' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "idempotency_key": "{UNIQUE_ID}",
    "ignore_unchanged_counts": false,
    "changes": [
      {
        "type": "ADJUSTMENT",
        "adjustment": {
          "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
          "from_state": "NONE",
          "to_state": "IN_STOCK",
          "occurred_at": "2021-06-10T22:00:01Z",
          "location_id": "SNTR5190QMFGM",
          "quantity": "24"
        }
      }
    ]
  }'

If the request is successful, a 200 OK response returns the results in the body similar to the following. The result includes the two component inventory counts, one for the stockable variation measured in bottles and the other for the sellable-only variation measured in glasses. The stockable variation count (24 bottles) is the physical count. The sellable-only variation count (120 glasses) is derived from the stockable variation count based on the specified stock conversion of 1 bottle = 5 glasses.

Response Permalink Get a link to this section

{
  "counts": [
    {
      "catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6",
      "catalog_object_type": "ITEM_VARIATION",
      "state": "IN_STOCK",
      "location_id": "SNTR5190QMFGM",
      "quantity": "120",
      "calculated_at": "2021-06-11T17:23:40.6115Z",
      "is_estimated": true
    },
    {
      "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
      "catalog_object_type": "ITEM_VARIATION",
      "state": "IN_STOCK",
      "location_id": "SNTR5190QMFGM",
      "quantity": "24",
      "calculated_at": "2021-06-11T17:23:40.6115Z"
    }
  ],
  "changes": [
    {
      "type": "ADJUSTMENT",
      "adjustment": {
        "from_state": "NONE",
        "to_state": "IN_STOCK",
        "location_id": "SNTR5190QMFGM",
        "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
        "catalog_object_type": "ITEM_VARIATION",
        "quantity": "10",
        "occurred_at": "2021-06-11T17:12:00.4125Z",
        "source": {
          "product": "EXTERNAL_API",
          "application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww",
          "name": "HelloCustomers"
        }
      }
    }
  ]
}

Step 3: Adjust the inventory after selling one unit of the stockable variation Permalink Get a link to this section

With the wine fully stocked, the seller can begin to take orders. Suppose the first order involves one bottle of the wine. This should decrement the inventory count of the stockable variation by one unit (bottle).

The following example request shows a call to the BatchChangeInventory endpoint on the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ) to adjust the inventory accordingly.

Request Permalink Get a link to this section

Batch Change Inventory
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
curl https://connect.squareupsandbox.com/v2/inventory/changes/batch-create \
  -X POST \
  -H 'Square-Version: 2021-09-15' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "idempotency_key": "{UNIQUE_ID}",
    "ignore_unchanged_counts": false,
    "changes": [
      {
        "type": "ADJUSTMENT",
        "adjustment": {
          "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
          "from_state": "IN_STOCK",
          "to_state": "SOLD",
          "occurred_at": "2021-06-11T17:51:00Z",
          "location_id": "SNTR5190QMFGM",
          "quantity": "1"
        }
      }
    ]
  }'

Note

In the Virtual Terminal in the Seller Dashboard, the previous request corresponds to taking a payment for one bottle of wine.

The successful request returns a 200 OK response with the payload similar to the following. The quantity of the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ) is now reduced by 1 (bottle) to become 23 (bottles). The quantity of the sellable-only variation (IUD2QMXX4K62W35HW5CVQGL6) is reduced by 5, based on the specified stock conversion, to become 115.

Response Permalink Get a link to this section

{
  "counts": [
    {
      "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
      "catalog_object_type": "ITEM_VARIATION",
      "state": "IN_STOCK",
      "location_id": "SNTR5190QMFGM",
      "quantity": "23",
      "calculated_at": "2021-06-11T17:51:51.6115Z"
    },
    {
      "catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6",
      "catalog_object_type": "ITEM_VARIATION",
      "state": "IN_STOCK",
      "location_id": "SNTR5190QMFGM",
      "quantity": "115",
      "calculated_at": "2021-06-11T17:51:51.6115Z",
      "is_estimated": true
    }
  ],
  "changes": [
    {
      "type": "ADJUSTMENT",
      "adjustment": {
        "from_state": "IN_STOCK",
        "to_state": "SOLD",
        "location_id": "SNTR5190QMFGM",
        "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
        "catalog_object_type": "ITEM_VARIATION",
        "quantity": "1",
        "occurred_at": "2021-06-11T17:50:00.6115Z",
        "source": {
          "product": "EXTERNAL_API",
          "application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww",
          "name": "HelloCustomers"
        }
      }
    }
  ]
}

Step 4: Update the inventory after selling two units of sellable-only variations Permalink Get a link to this section

Now, another customer orders two glasses of wine. To update the inventory to account for this transaction, call the BatchChangeInventory endpoint on the sellable-only variation (IUD2QMXX4K62W35HW5CVQGL6), specifying the quantity 2.

This is shown in the following example request:

Request Permalink Get a link to this section

Batch Change Inventory
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
curl https://connect.squareupsandbox.com/v2/inventory/changes/batch-create \
  -X POST \
  -H 'Square-Version: 2021-09-15' \
  -H 'Authorization: Bearer {ACCESS_TOKEN}' \
  -H 'Content-Type: application/json' \
  -d '{
    "idempotency_key": "{UNIQUE_ID}",
    "ignore_unchanged_counts": true,
    "changes": [
      {
        "type": "ADJUSTMENT",
        "adjustment": {
          "catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6",
          "from_state": "IN_STOCK",
          "to_state": "SOLD",
          "occurred_at": "2021-06-11T17:55:00Z",
          "location_id": "SNTR5190QMFGM",
          "quantity": "2"
        }
      }
    ]
  }'

Note

In the Virtual Terminal in the Seller Dashboard, the previous request corresponds to taking a payment for two glasses of wine.

The successful request returns a 200 OK response with the payload similar to the following. The quantity of the stockable variation (PMUUU2EFXNRBKTUAMTC5SQTZ) is now further reduced by 2/5 to become 22.60000. The quantity of the sellable-only variation (IUD2QMXX4K62W35HW5CVQGL6) is further reduced by 2 to become 113.

Response Permalink Get a link to this section

{
  "counts": [
    {
      "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
      "catalog_object_type": "ITEM_VARIATION",
      "state": "IN_STOCK",
      "location_id": "SNTR5190QMFGM",
      "quantity": "22.60000",
      "calculated_at": "2021-06-11T17:56:01.4135Z"
    },
    {
      "catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6",
      "catalog_object_type": "ITEM_VARIATION",
      "state": "IN_STOCK",
      "location_id": "SNTR5190QMFGM",
      "quantity": "113",
      "calculated_at": "2021-06-11T17:56:01.4135Z",
      "is_estimated": true
    }
  ],
  "changes": [
    {
      "type": "ADJUSTMENT",
      "adjustment": {
        "id": "YUGSU46HZJIKV2TTXU77E4Q4",
        "from_state": "IN_STOCK",
        "to_state": "COMPOSED",
        "location_id": "SNTR5190QMFGM",
        "catalog_object_id": "PMUUU2EFXNRBKTUAMTC5SQTZ",
        "catalog_object_type": "ITEM_VARIATION",
        "quantity": "0.40000",
        "occurred_at": "2021-06-11T17:52:00.6115Z",
        "created_at": "2021-06-11T17:52:00:00.1112Z",
        "source": {
          "product": "EXTERNAL_API",
          "application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww",
          "name": "HelloCustomers"
        },
        "adjustment_group": {
          "id": "adjGrp_4GH4NVSK6UFHJUI5",
          "from_state": "IN_STOCK",
          "to_state": "SOLD"
        }
      }
    },
    {
      "type": "ADJUSTMENT",
      "adjustment": {
        "id": "UQ4TDTMP7IYSWBD2WMUA4YMO",
        "from_state": "COMPOSED",
        "to_state": "SOLD",
        "location_id": "SNTR5190QMFGM",
        "catalog_object_id": "IUD2QMXX4K62W35HW5CVQGL6",
        "catalog_object_type": "ITEM_VARIATION",
        "quantity": "2",
        "occurred_at": 2021-06-11T17:52:00.6115Z",
        "created_at": "2021-06-11T17:52:00:00.1112Z",
        "source": {
          "product": "EXTERNAL_API",
          "application_id": "sq0ids-hLgkXFJ58T_vJI5g1Dpoww",
          "name": "HelloCustomers"
        },
        "adjustment_group": {
          "id": "adjGrp_4GH4NVSK6UFHJUI5",
          "root_adjustment_id": "UQ4TDTMP7IYSWBD2WMUA4YMO",
          "from_state": "IN_STOCK",
          "to_state": "SOLD"
        }
      }
    }
  ]
}

Adjusting the inventory on the sellable-only variation involves two separate adjustments:

  • The inventory adjustment on the stockable variation from the IN_STOCK state to the COMPOSED state.

  • The inventory adjustment on the sellable-only variation from the COMPOSED state to the SOLD state.

The two component inventory adjustments are included in an adjustment group that represents a single inventory change event transitioning from a representative from_state of IN_STOCK to a representative to_state of SOLD.

This behavior is different from the inventory change on a stockable variation.