This page outlines the methods for managing real-time price and quantity updates for the Vertex AI Search for commerce catalog using the Retail API.
While the Product create, read, update, and delete (CRUD) methods are used to
broadly modify a Product's attributes, there is a set of Product methods
that can be used for updating inventory-specific fields with varying levels of
granularity.
Understand inventory
In general terms, inventory usually refers to stock levels (quantity) and price for items on an ecommerce site. For the Retail API, inventory refers to price, availability, available quantity, fulfillment information and local pricing and additional local attributes. These fields are defined in the Product schema with the following fields:
Product.availabilityProduct.availableQuantityProduct.priceInfoProduct.fulfillmentInfoProduct.localInventories
Product-level inventory
For ecommerce site merchants with an online catalog only, inventory is usually represented as the products in the catalog only. Price, availability and all other data is set on each Product entry in the catalog. The fulfillmentInfo and localInventories fields aren't used.
Local inventory
For retailers that have multiple locations, products are still represented by the Product entries in the catalog, but local inventory (price, availability and fulfillment) can be added to locations (placeId) for a product with the addLocalInventories method.
There are two separate Product fields used for local inventory: Product.fulfillmentInfo and Product.localInventories. One or both can be used, depending on the requirements. Both fulfillmentInfo and localInventories are lists of locations with associated data.
fulfillmentInfo specifies how a product is fulfilled at a particular location, whereas localInventories specifies price and other custom attributes for each location.
To mark a product as out of stock or no longer available at a specific location, the removeLocalInventories method is used to remove fulfillment and inventory from a product for a particular placeId.
Inventory update methods
Changes to a product's inventory information may occur much more frequently than changes to its catalog information. As such, a specialized set of methods are provided to handle large volumes of inventory-specific updates. These methods are asynchronous because of downstream optimizations that support hundreds of concurrent updates per product, without sacrificing performance.
Incremental updates
Follow the local inventory updates guide to issue incremental inventory updates. The newer API methods provide more fine-grained control for per-place inventory attributes.
fulfillment_info is often used to encode place-level fulfillment availability
for a Product. In some cases, fulfillment availability for some specific
places can change. You can decide to issue updates that describe this
change, instead of using the UpdateProduct method to respecify all the product's fulfillment information.
In such cases, the AddFulfillmentPlaces and
RemoveFulfillmentPlaces methods can be used to
incrementally update a product's fulfillment changes based on which place IDs
are added or removed for a given fulfillment type.
Java
To learn how to install and use the client library for Vertex AI Search for commerce, see Vertex AI Search for commerce client libraries. For more information, see the Vertex AI Search for commerce Java API reference documentation.
To authenticate to Vertex AI Search for commerce, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.
Proto
{ product: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123" type: "pickup-in-store" place_ids: "store0" place_ids: "store1" add_time: { seconds: 100 nanos: 100 } allow_missing: true }
This sample AddFulfillmentPlacesRequest adds fulfillment type
"pickup-in-store" to place IDs "store0" and "store1" for the specified
product. Because
AddFulfillmentPlacesRequest.allow_missing is set to true, even if the product
does not already exist, the updated inventory information will be stored for
when the product is eventually created. The update is time stamped with
AddFulfillmentPlacesRequest.add_time to prevent stale updates from overriding
the fulfillment status of these place IDs. These features are discussed in
greater detail in the following sections.
The behavior is identical for RemoveFulfillmentPlacesRequest and the schema is
very similar.
When fulfillment_types is updated by
AddLocalInventories and
RemoveLocalInventories, it reflects a mapping from
each place ID to a list of fulfillment types it supports. When
fulfillment_info is updated by
AddFulfillmentPlaces and
RemoveFulfillmentPlaces, it reflects a mapping
from each specific fulfillment type to a list of place IDs that supports each
type. Both API types are modifying the same underlying fulfillment
information, and the effect of both types of APIs is reflected by
Product.fulfillment_info.
Non-incremental updates
The price_info, availability, and available_quantity methods can't be incrementally
updated, because they represent product-level inventory, not place-level information. It can also be good to issue non-incremental
updates to fulfillment_info. Instead of only incremental changes, SetInventory is recommended.
The setInventory method is the preferred way to update price, availability, and quantity at the product level when many, frequent updates required. The setInventory method is asynchronous, so the updates might not happen immediately. The default quota (300,000 requests per minute) supports much more requests than UpdateProduct.
Additionally, the setInventory method is used for local fulfillment updates when fulfillmentInfo is included in the request, but it can't update the localInventories fields. For those attributes, use the addLocalInventories and removeLocalInventories methods.
Local inventory is saved at the store-level, independent of the catalog. For customers with online and offline inventory, the main product catalog can be used for online or a specific placeId (-1 or online for example) could be used to represent online inventory. However, use the main catalog for online inventory because the product inventory fields should be populated with valid priceInfo and availability values. If a separate inventory placeId is used for online, then the main catalog price and availability information should also be kept up to date. For more on local inventory updates, see Update local inventory.
Java
To learn how to install and use the client library for Vertex AI Search for commerce, see Vertex AI Search for commerce client libraries. For more information, see the Vertex AI Search for commerce Java API reference documentation.
To authenticate to Vertex AI Search for commerce, set up Application Default Credentials. For more information, see Set up authentication for a local development environment.
Proto
{ product: { name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123" availability: IN_STOCK fulfillment_info: { type: "pickup-in-store" place_ids: "store0" place_ids: "store1" place_ids: "store2" place_ids: "store3" } fulfillment_info: { type: "same-day-delivery" } } set_time: { seconds: 100 nanos: 100 } set_mask: { paths: "availability" paths: "fulfillment_info" } allow_missing: true }
In this particular request, the SetInventoryRequest.product.fulfillment_info
fields are complete descriptions of each fulfillment type's eligible place IDs,
as opposed to incremental specifications. The update to "same-day-delivery"
indicates that no place IDs are eligible for this fulfillment type for this
product. All other fulfillment types are not updated in this request. Thus, this method can be used to replace the place IDs for only a subset of fulfillment types while leaving the other types untouched.
By default,SetInventory will update all inventory fields if
SetInventory.set_mask is unset or empty. If the mask is not empty or if an
inventory field is not explicitly listed in SetInventoryRequest.set_mask, then
any specified value for that inventory field will be ignored in the update
request.
As with incremental updates, the SetInventoryRequest.set_time field can be
used to set an update time that will be against the last recorded update time of
all updated inventory fields.
Timestamp protections for inventory updates
There are several different paths to update a product's inventory fields, and to protect against out-of-order updates, each inventory field is associated with a latest update time.
The latest update time is recorded for price_info, availability,
available_quantity, and each pair of (fulfillment_info.place_ids,
fulfillment_info.type).
The AddFulfillmentPlaces,
RemoveFulfillmentPlaces, and
SetInventory methods allow the caller to specify an update
time for when the request is issued. This update time is compared against the
latest update time recorded for the relevant inventory fields, and the update is
committed if and only if the update time is strictly after the latest update
time.
For example, suppose place ID "store1" has fulfillment type "pickup-in-
store" enabled, with the last recorded update time set to time T. If
RemoveFulfillmentPlacesRequest.type = "pickup-in-store" and
RemoveFulfillmentPlacesRequest.place_ids contains "store1", the request will
clear "pickup-in-store" from "store1" if and only if the
RemoveFulfillmentPlacesRequest.remove_time is later than time T. The same is
true for AddFulfillmentPlacesRequests.
SetInventory operates in a similar way for updating price_info,
availability, and available_quantity. When updating fulfillment_info, a
SetInventoryRequest is implicitly asking to add all specified place IDs for a
given fulfillment type and remove all unspecified existing place IDs.
When the SetInventoryRequest is processed, the fulfillment_info update
is implicitly converted into an AddFulfillmentPlacesRequest and
RemoveFulfillmentPlacesRequest for each specified fulfillment type. This means
that if any existing place "store1" with fulfillment "pickup-in-store" has a
last update time T that is more recent than SetInventoryRequest.set_time,
then the implicit add or remove on "store1" and "pickup-in-store" won't be
applied.
Preload attributes
setInventory is asynchronous, meaning that no taxonomic or referencial controls are enforced when adding or modifying inventory fields. This method doesn't require the product referenced in the request to already exist.
This enables customers to implement preloading patterns, whereby the management of inventory fields can be decoupled from the main catalog or product import process. For example, users can import the availability or price context before the associated product is imported.
Each of the inventory update methods allows the caller to set allow_missing in
the request. When allow_missing is set to true, an inventory update to a
nonexistent Product will be processed as if the Product exists according to
the method specification(s). The inventory information will be retained for a
maximum of two days if the corresponding Product is not created using
CreateProduct within this timeframe.
Java
When to use the Product methods
While it is possible to update inventory fields with the Product CRUD methods, the caller should be explicitly aware of the effects on existing or pre-existing inventory information.
These are synchronous methods, which means the downstream optimizations used for inventory methods don't apply, and it can become expensive to rely on these methods for frequent inventory updates. Wherever possible, prefer to use the aforementioned inventory update methods.
CreateProduct
When CreateProduct is invoked with any inventory fields set,
the provided values in the CreateProductRequest.product will override any
preloaded values for those respective fields. If no inventory fields are set,
then any pre-existing inventory information will be automatically used.
Furthermore, the latest update time for the overridden inventory fields will be reset to the time of the method call.
CreateProduct with preloaded inventory
PROTO
{ parent: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch" product_id: "p123" product: { name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123" title: "some product" type: VARIANT } }
In this example, the created product does not have any inventory fields set,
which means any preloaded inventory information will be automatically used if
updated using the inventory update methods. This can be helpful when inventory
updates are decoupled from catalog updates and you want to have a newly
created Product synchronize with any pre-existing inventory information.
CreateProduct with explicit inventory
PROTO
{ parent: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch" product_id: "p123" product: { name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123" title: "some product" type: VARIANT availability: OUT_OF_STOCK fulfillment_info: { type: "pickup-in-store" } fulfillment_info: { type: "same-day-delivery" } } }
In this example, a Product is created with explicitly set inventory fields.
These fields will override any pre-existing values, ignoring the latest update
time for the corresponding fields. Thus, the newly created Product will have availability set to OUT_OF_STOCK, and no place IDs will
support fulfillment types "pickup-in-store" and "same-day-delivery".
CreateProduct with inventory information can be helpful if you are not
sure if all the preloaded inventory information is accurate, and prefer to
explicitly set the inventory at creation time of Product to fully synchronize
the catalog and inventory.
UpdateProduct
The UpdateProduct method can be used to update specific attributes on an existing catalog item. This can be done for single or multiple fields at the same time, and for individual products or using the import method multiple products. If you use the import method without the mask it does an overwrite.
UpdateProduct is often used for real time price & availability updates, but can be used to update any fields without having to submit all data for a product again. (in contrast to the createMethod or the importProducts.
The main benefit of using UpdateProduct is that it is a synchronous request. Updates to the index (and search or recommendations) is nearly instantaneous. However, UpdateProduct isn't intended to be used for very frequent updates. The default quota is 12,000 product write requests per minute. Usually, you'll want to use this method only when an item's price changes or if the stock state changes (not for each quantity decrease).
UpdateProduct can only modify the product-level attributes. It can't be used to modify any of the local inventory attributes for localInventories or fulfillmentInfo.
When making a call with UpdateProduct or ImportProducts, it is important to specify the updateMask parameter. updateMask contains a list of the fields to update. Only fields specified in the updateMask will be updated, even if more fields are passed in the request body. If no updateMask is present for an update or import request, all fields are updated to exactly what is submitted in the request body.
When UpdateProduct is invoked and the field mask
UpdateProductRequest.update_mask contains any inventory fields, the provided
values in the UpdateProductRequest.product will override any preloaded values
for those respective fields.
Furthermore, the latest update time for the overridden inventory fields will be reset to the time of the method call.
PROTO
{ product: { name: "projects/123/locations/global/catalogs/default_catalog/branches/default_branch/products/p123" availability: IN_STOCK fulfillment_info: { type: "pickup-in-store" place_ids: "store0" place_ids: "store1" place_ids: "store2" place_ids: "store3" } fulfillment_info: { type: "same-day-delivery" } } update_mask: { paths: "availability" paths: "fulfillment_info" } }
This example is very similar to the SetInventory example, except the update applies, regardless of each inventory field's latest update time.
UpdateProductfor inventory can be helpful when a full sync on inventory information is needed while ignoring timestamp protections.By setting
UpdateProductRequest.allow_missingtotrueto perform aProductupsert, you can preload inventory information usingUpdateProduct. The method requires setting specific catalog fields, likeUpdateProductRequest.product.title. So use the inventory update methods for preloading use-cases.
DeleteProduct
When DeleteProduct is invoked, all existing inventory
information for the product specified in DeleteProductRequest.name will be
deleted, including all records of the latest update time for each inventory
field.
Considerations if you replace product-level attributes with inventory-level ones
Take note of the following considerations and limitations associated with each approach:
| Feature | Product-level inventory | Store-level (local) inventory |
|---|---|---|
| Search filter & boost controls | Yes | Yes |
Filter and facet key format specified in facetSpec |
Yes | No |
| Available for search facets | Yes | No |
| Returned in search response | Yes | Yes (using variantRollupKeys) |
| Recommendations AI v2 filters and boost controls | Yes | No |
| Feature | Product-level Inventory | Store-level (Local) Inventory |
|---|---|---|
| Search filter and boost controls | ||
Filter and facet key format specified in facetSpec |
||
| Available for search facets | ||
| Returned in search response | (using variantRollupKeys) |
|
| Recommendations AI v2 filters and boost controls |
There is some overlap in the functionality of the different methods of updating product availability, fulfillment, and local price:
| Feature | UpdateProduct |
setInventory |
addLocalInventories |
|---|---|---|---|
| Realtime updates | |||
| Update any product fields | |||
| Update product price | |||
| Update product availability | |||
Update fulfillmentInfo |
|||
Update localInventories (local prices) |
|||
| Timestamp Sequencing |
Examples
This section demonstrates how to update product inventory using the UpdateProduct and setInventory methods in curl commands.
UpdateProductuses the REST API's HTTP PATCH method for synchronous, real-time updates of product-level fields like price and availability, and can also be used for batch updates by using theimportmethod with anupdateMask.The asynchronous
setInventorymethod is shown for updating product-level inventory fields (price, availability, quantity) and local fulfillment details usingfulfillmentInfo, but it can't modify local prices or attributes stored inlocalInventories.
Use UpdateProduct to update product price and availability
When using the REST API, UpdateProduct uses the HTTP PATCH method. The same endpoint URL as CreateProduct, GetProduct, DeleteProduct uses the HTTP PUT, GET, and DELETE methods, respectively. Expand the following links to view the respective curl samples.
Use setInventory to update product price and availability
setInventory only supports the following fields:
availabilityavailableQuantitypriceInfo
Expand the following links to view the respective curl samples.
And for local inventory, placeIds and fulfillment types can be passed in fulfillmentInfo, as this curl sample demonstrates:
Tutorials
Use these tutorials to guide you through how to use setInventory or to add or remove fulfillments.
Set inventory tutorial
This tutorial shows how to push inventory updates using the
SetInventory method instead of updating the entire product.
To follow step-by-step guidance for this task directly in the Cloud Shell Editor, click Guide me:
Add fulfillment tutorial
We recommend using the AddLocalInventories method instead of AddFulfillmentPlaces. AddLocalInventories achieves the same results but provides more fine-grained control over ingesting local inventory data. For more information, see the AddLocalInventories documentation.
This tutorial shows how to update product fulfillment information using the
AddFulfillmentPlaces
method. In this way, search can show updates where products are available and
orders can be fulfilled. For example, a shopper is looking for blue jeans in a
shop but they're out of stock. The moment the jeans are in stock again at this
shop or any other shop, the shopper sees the updates and can proceed with their
order.
To follow step-by-step guidance for this task directly in the Cloud Shell Editor, click Guide me:
Remove fulfillment tutorial
We recommend using the RemoveLocalInventories method instead of RemoveFulfillmentPlaces. RmoveLocalInventories achieves the same results but provides more fine-grained control over ingesting local inventory data. For more information, see the RemoveLocalInventories documentation.
This tutorial shows how to update product fulfillment information using
the RemoveFulfillmentPlaces method. In this way,
Vertex AI Search for commerce can show updates where products aren't available and orders
can't be fulfilled. In this way, search can show updates where products aren't
available and orders can't be fulfilled. For example, a shopper is looking for
blue jeans in a shop. If the jeans become out of stock in this shop, the shopper
sees this and can't proceed with their order.
To follow step-by-step guidance for this task directly in the Cloud Shell Editor, click Guide me: