Manage Products

Inventory API Setup

Prerequisites

To use the Inventory API, the following must be true:

  • You have items defined in your Square product catalog. See the Catalog API Overview for details on working with the Catalog API.
  • You have a valid access token for the targeted Square account. Applications using OAuth must have INVENTORY_READ permissions to read inventory information and INVENTORY_WRITE permissions to update inventory states.
  • You are using Square-Version 2018-09-18 or later.

Assumptions

  • You have read the related product guides. We recommend reading the Inventory API Overview and Catalog API Overview before continuing.
  • You are familiar with HTTP and JSON. If you are new to JSON, we recommend reading the JSON Getting Started Guide on Codular before continuing.
  • You are using Java version 1.8 or later. Java was selected for the example code because it is a commonly used server language, but the Inventory API is language agnostic and the setup steps are comparable across languages.
  • You are using the Square Connect v2 Java SDK. Installing the SDK is optional. As long as you can package and receive JSON messages you can use Square APIs, but installing the SDK makes things easier.

Step 1: Get your authorization ID

You cannot use the Inventory API endpoints without authorizing access to your Square account. The Inventory API is not currently supported in sandbox so you will need to use a valid production access token. Inventory API supports OAuth tokens and personal access tokens. OAuth tokens must have INVENTORY_READ and INVENTORY_WRITE permissions for the targeted account. OAuth is the preferred method because it provides better security for the targeted merchant account, but personal access tokens are appropriate for testing and development. To find your personal access token:

  1. Open your Application Dashboard.
  2. If you DO have an application you want to use for inventory management, click on the application.
  3. If you DO NOT have an application you want to use for inventory management, click New Application, enter a name for your application (e.g., "My Inventory App") and click Create Application.
  4. Copy the Personal Access Token on the Credentials tab of the application control panel.

Step 2: Get your location ID

CatalogItemVariation quantities are always tied to a location, and inventory adjustments must be credited to a valid location ID for the associated Square account. Use the Locations API find your location ID:

  1. Initialize the API object.
// Create and configure a new API client object
ApiClient apiClient = Configuration.getDefaultApiClient();

// Configure OAuth2 access token for authorization: oauth2
OAuth oauth2 = (OAuth) apiClient.getAuthentication("oauth2");
oauth2.setAccessToken("MY_ACCESS_TOKEN");

String locationId; // we'll set this programmatically

// Create a LocationsApi client to load the location ID
LocationsApi locationsApi = new LocationsApi();
locationsApi.setApiClient(apiClient);
  1. Call listLocations and save the first location ID.
List<Location> locations = locationsApi.listLocations().getLocations();
locationId = locations.get(0).getId();

Note: If you have more than one location, you can loop over the locations to check the location names for your account in the Square Dashboard and select the correct location by name. For example:

String locationName = "MY_LOCATION_NAME";

List<Location> locations = locationsApi.listLocations().getLocations();

for (Location location : locations) {
    if (locationName.equals(location.getName())) {
        locationId = location.getId();
    }
}

Step 3: Add IN_STOCK quantities for one or more item variations

  1. Look up the CatalogItemVariation IDs you want to modify using the Catalog API. The example code below searches for 2 CatalogItemVariation objects ("Small", "Medium") under the "Leather collar" CatalogItem.
String itemName = "Leather collar"; // Replace with your CatalogItem name
String variation1Name = "Small";  // Replace with your CatalogItemVariation name
String variation2Name = "Medium"; // Replace with your CatalogItemVariation name
String variation1Id = "";
String variation2Id = "";

CatalogApi catalogApi = new CatalogApi();

// Search for an Item with the desired name attribute.
SearchCatalogObjectsResponse itemResponse =
    catalogApi.searchCatalogObjects(new SearchCatalogObjectsRequest()
        .addObjectTypesItem(SearchCatalogObjectsRequest.ObjectTypesEnum.ITEM)
        .query(new CatalogQuery()
            .exactQuery(new CatalogQueryExact()
            .attributeName("name")
            .attributeValue(itemName))));

// Retrieve the first returned object, an Item.
CatalogObject item = itemResponse.getObjects().get(0);

// Retrieve the desired ItemVariations from the Item.
List<CatalogObject> variations = item.getItemData().getVariations();
for (CatalogObject variation : variations) {
    String name = variation.getItemVariationData().getName();
    if (variation1Name.equals(name)) {
        variation1Id = variation.getId();
    } else if (variation2Name.equals(name)) {
        variation2Id = variation.getId();
    }
}
  1. Create a BatchChangeInventoryRequest with an InventoryAdjustment that moves a quantity of the CatalogItemVariation objects from NONE to IN_STOCK:
// Create an adjustment for 5 units of "small" variation from NONE to IN_STOCK.
InventoryAdjustment addStockAdjustment = new InventoryAdjustment()
    .catalogObjectId(variation1Id)
    .locationId(locationId)
    .fromState(InventoryAdjustment.FromStateEnum.NONE)
    .toState(InventoryAdjustment.ToStateEnum.IN_STOCK)
    .quantity("5");

// Create an adjustment for 7 units of "medium" variation from NONE to IN_STOCK.
InventoryAdjustment damagedStockAdjustment = new InventoryAdjustment()
    .catalogObjectId(variation2Id)
    .locationId(locationId)
    .fromState(InventoryAdjustment.FromStateEnum.NONE)
    .toState(InventoryAdjustment.ToStateEnum.IN_STOCK)
    .quantity("7");

List<InventoryChange> changes = asList(
    new InventoryChange().adjustment(addStockAdjustment),
    new InventoryChange().adjustment(damagedStockAdjustment));

// Construct a request with an idempotency key and a single InventoryChange object.
BatchChangeInventoryRequest addStockRequest = new BatchChangeInventoryRequest()
    .idempotencyKey(UUID.randomUUID().toString())
    .changes(changes);
  1. Send the BatchChangeInventoryRequest to the server.
BatchChangeInventoryResponse addStockResponse =
    inventoryApi.batchChangeInventory(addStockRequest);

// Check for errors.
if (!addStockResponse.getErrors().isEmpty()) {
    System.err.println("Error calling BatchChangeInventory: " +
        addStockResponse.getErrors());
    return;
}

// The response contains the quantity following the adjustment.
for (InventoryCount count : addStockResponse.getCounts()) {
    System.out.println("item variation: " + count.getCatalogObjectId());
    System.out.println("  new quantity: " + count.getQuantity());
}

Step 4: Transition a quantity of item variations to a new state

Recording a transition from one state to another works the same way as adding IN_STOCK quantities. For example, to indicate 2 units of variation1Id are no longer suitable for sale:

  1. Create a BatchChangeInventoryRequest containing an InventoryAdjustment from IN_STOCK to WASTE:
// Create an adjustment to move 2 units from state IN_STOCK to WASTE.
InventoryAdjustment wasteAdjustment = new InventoryAdjustment()
    .catalogObjectId(variation1Id)
    .locationId(locationId)
    .fromState(InventoryAdjustment.FromStateEnum.IN_STOCK)
    .toState(InventoryAdjustment.ToStateEnum.WASTE)
    .quantity("2");

InventoryChange wasteChange = new InventoryChange().adjustment(wasteAdjustment);
BatchChangeInventoryRequest wasteRequest = new BatchChangeInventoryRequest()
    .idempotencyKey(UUID.randomUUID().toString())
    .addChangesItem(wasteChange);
  1. Send the BatchChangeInventoryRequest to the server.
BatchChangeInventoryResponse wasteResponse =
    inventoryApi.batchChangeInventory(wasteRequest);

// Check for errors.
if (!wasteResponse.getErrors().isEmpty()) {
    System.err.println("Error calling BatchChangeInventory: " +
        wasteResponse.getErrors());
    return;
}
  1. Inventory change requests always return the current quantities of the targeted item variation in each state. You can use this information to determine the number of IN_STOCK units after the adjustment is applied.
// Display IN_STOCK and WASTE quantities.
for (InventoryCount count : wasteResponse.getCounts()) {
    if (count.getState() == InventoryCount.StateEnum.IN_STOCK) {
        System.out.println("In stock: " + count.getQuantity());
    } else if (count.getState() == InventoryCount.StateEnum.WASTE) {
        System.out.println("Waste: " + count.getQuantity());
    }
}

Reminder: If you are processing itemized transactions with Square APIs or hardware, item variation quantities are automatically transitioned from IN_STOCK to SOLD. If you are using any other method, you will need to apply the adjustment manually.

Step 5: Retrieve the quantities of multiple item variations

Use the BatchRetrieveInventoryCounts endpoint to retrieve quantities for multiple item variations at once. For example, to request the current counts of all item variations sold through an eCommerce site

  1. Create a BatchRetrieveInventoryCountsRequest containing the Catalog object IDs of the item variation quantities you want to retrieve. You can also use location IDs to filter the search against specific locations.
BatchRetrieveInventoryCountsRequest countsRequest = new BatchRetrieveInventoryCountsRequest()
    .addLocationIdsItem(locationId1)
    .addLocationIdsItem(locationId2)
    .addCatalogObjectIdsItem(item1VariationToken)
    .addCatalogObjectIdsItem(item2VariationToken);
  1. Send the BatchRetrieveInventoryCountsRequest to the server.
BatchRetrieveInventoryCountsResponse countsResponse =
    inventoryApi.batchRetrieveInventoryCounts(countsRequest);

Optional: Reconcile the computed quantity of inventory

To reconcile the inventory count calculated by Square with the results of a physical count (or the inventory reported by a trusted system):

  1. Create a BatchChangeInventoryRequest containing one or more InventoryPhysicalCount objects. Each request assigns an explicit count to the indicated state:
InventoryPhysicalCount physicalCount1 = new InventoryPhysicalCount()
    .catalogObjectId(variation1Id)
    .locationId(locationId1)
    .state(InventoryPhysicalCount.StateEnum.IN_STOCK)
    .quantity("5");

InventoryPhysicalCount physicalCount2 = new InventoryPhysicalCount()
    .catalogObjectId(variation2Id)
    .locationId(locationId1)
    .state(InventoryPhysicalCount.StatesEnum.IN_STOCK)
    .quantity("12");

InventoryChange physicalCountChange1 = new InventoryChange().physicalCount(physicalCount1);
InventoryChange physicalCountChange2 = new InventoryChange().physicalCount(physicalCount2);

BatchChangeInventoryRequest physicalCountRequest = new BatchChangeInventoryRequest()
    .idempotencyKey(UUID.randomUUID().toString())
    .addChangesItem(physicalCountChange1)
    .addChangesItem(physicalCountChange2);
  1. Send the BatchChangeInventoryRequest to the server.
BatchChangeInventoryResponse physicalCountResponse =
    inventoryApi.batchChangeInventory(physicalCountRequest);

See the BatchChangeInventoryResponse endpoint in the Inventory API Technical Reference for more details.

Optional: Retrieve the IN_STOCK quantity of a specific item variation

To request the IN_STOCK quantity of a single item variation (for example, to show the quantity available when an item variation is select on an eCommerce site), call the RetreiveInventoryCountRequest endpoint with Catalog object ID of the item variation. You can also use a location ID to filter the search against specific locations.

String cursor = null; // Fetch initial page of results
while (true) {
    RetrieveInventoryCountResponse countResponse =
        inventoryApi.retrieveInventoryCount(variation1Id, locationId1, cursor);
    for (InventoryCount count: countResponse.getCounts()) {
        System.out.println("item variation " + count.getCatalogObjectId() +
            " at location " + count.getLocationId() + ":");
        System.out.println("  state: " + count.getState());
        System.out.println("  quantity: " + count.getQuantity());
        System.out.println("  calculated at: " + count.getCalculatedAt());
    }

    // Use cursor from response to fetch additional pages.
    cursor = countResponse.getCursor();
    if (cursor == null || cursor.length() == 0) {
        break;
    }
}

See the RetrieveInventoryCount endpoint in the Inventory API Technical Reference for more details.

Optional: Retrieve the history of inventory changes for an item

To retrieve the history of inventory adjustments and physical counts for a specific item variation (for example, to create an audit log), call the RetrieveInventoryChanges endpoint with the Catalog object ID of the item variation you care about. You can also use a location ID to filter the search against specific locations.

String cursor = null; // Fetch initial page of results
while (true) {
    RetrieveInventoryChangesResponse changeResponse =
        inventoryApi.retrieveInventoryChanges(variation1Id, locationId1, null);

    for (InventoryChange change: changeResponse.getChanges()) {
        // Process change (physical count or adjustment)
        switch (change.getType()) {
        case ADJUSTMENT:
            InventoryAdjustment adjustment = change.getAdjustment();
            System.out.println("Adjustment for item variation " +
                adjustment.getCatalogObjectId() + ":");
            System.out.println("  From state: " + adjustment.getFromState() +
                " at location " + adjustment.getLocationId());
            System.out.println("    To state: " + adjustment.getToState() +
                " at location " + adjustment.getLocationId());
            System.out.println("     Quantity: " + adjustment.getQuantity());
            break;

        case PHYSICAL_COUNT:
            InventoryPhysicalCount count = change.getPhysicalCount();
            System.out.println("Physical count for item variation " +
                count.getCatalogObjectId() + ":");
            System.out.println("     Counted at: " + count.getOccurredAt());
            System.out.println("       Location: " + count.getLocationId());
            System.out.println("       Quantity: " + count.getQuantity());
            break;
        }

        case TRANSFER:
          InventoryTransfer transfer = change.getTransfer();
            System.out.println("Transfer for item variation " +
                transfer.getCatalogObjectId() + ":");
            System.out.println("  From location: " + transfer.getFromLocationId() +
                " at state " + transfer.getState());
            System.out.println("    To location: " + transfer.getToLocationId() +
                " at state " + transfer.getState());
            System.out.println("     Quantity: " + transfer.getQuantity());
            break;
    }

    // Use cursor from response to fetch additional pages.
    cursor = changeResponse.getCursor();
    if (cursor == null || cursor.length() == 0) {
        break;
    }
}

See the RetrieveInventoryChanges endpoint in the Inventory API Technical Reference for more details.

Prev
< Inventory API Overview
Next
Inventory API Technical Reference >

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