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.availability -
Product.availableQuantity -
Product.priceInfo -
Product.fulfillmentInfo -
Product.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:
-
availability -
availableQuantity -
priceInfo
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 :

