The Products sub-API lets you make partial updates to your existing products. This is ideal for frequently changing data, such as price and availability, as it avoids the need to resubmit the entire product for a small change. However, you should regularly reinsert products to make sure all product data is in sync.
This guide covers how to use the productinputs.patch
method to update your
products.
Prerequisites
Before you can update a product, you need the following:
- An existing product to update. To learn how to create products, see the Add and manage products guide.
- The
name
of the data source that the product input belongs to (for example,accounts/12345/dataSources/67890
). To learn how to find this, see the Manage API data sources for product uploads guide.
Update specific product details
To change a few details of a product, like its price or availability, without
resubmitting all its information, use the productInputs.patch
method.
You can specify which fields you're changing in the updateMask
parameter. The updateMask
is a comma-separated list of the fields you want to update. The patch
method behaves as follows:
- Fields in
updateMask
and body:These fields are updated with the new values. - Fields in
updateMask
but not in body:These fields are deleted from the product input. - Fields not in
updateMask
:These fields are left unchanged. -
updateMask
parameter omitted:All fields provided in the request body are updated. Fields not provided in the request body are not deleted from the product input.
Here's an example of product data before an update:
{
"name"
:
"accounts/ {ACCOUNT_ID}
/productInputs/en~US~SKU12345"
,
"product"
:
"accounts/ {ACCOUNT_ID}
/products/en~US~SKU12345"
,
"offerId"
:
"SKU12345"
,
"contentLanguage"
:
"en"
,
"feedLabel"
:
"US"
,
"productAttributes"
:
{
"title"
:
"Classic Cotton T-Shirt"
,
"description"
:
"A comfortable, durable, and stylish t-shirt made from 100% cotton."
,
"link"
:
"https://www.example.com/p/SKU12345"
,
"availability"
:
"IN_STOCK"
,
"price"
:
{
"amountMicros"
:
"15990000"
,
"currencyCode"
:
"USD"
},
"condition"
:
"NEW"
,
"gtins"
:
[
"9780007350896"
],
"imageLink"
:
"https://www.example.com/image/SKU12345"
}
}
This example updates the title
and availability
of a product and deletes its imageLink
. The description
and price
are not in the updateMask
and will
remain unchanged.
PATCH https://merchantapi.googleapis.com/products/v1/accounts/ {ACCOUNT_ID}
/productInputs/en~US~SKU12345?updateMask=productAttributes.title,productAttributes.availability,productAttributes.imageLink&dataSource=accounts/ {ACCOUNT_ID}
/dataSources/ {DATASOURCE_ID}
{
"productAttributes"
:
{
"title"
:
"Classic Cotton T-Shirt - New Edition"
,
"availability"
:
"OUT_OF_STOCK"
,
"description"
:
"A comfortable T-shirt from premium cotton, newer edition."
,
"price"
:
{
"amountMicros"
:
"9990000"
,
"currencyCode"
:
"USD"
}
}
}
A successful call returns the updated ProductInput
resource. The title
and availability
are updated, and the imageLink
is removed because it was in the updateMask
but not in the request body. The description
and price
remain
unchanged as they were not listed in updateMask
.
{
"name"
:
"accounts/ {ACCOUNT_ID}
/productInputs/en~US~SKU12345"
,
"product"
:
"accounts/ {ACCOUNT_ID}
/products/en~US~SKU12345"
,
"offerId"
:
"SKU12345"
,
"contentLanguage"
:
"en"
,
"feedLabel"
:
"US"
,
"productAttributes"
:
{
"title"
:
"Classic Cotton T-Shirt - New Edition"
,
"description"
:
"A comfortable, durable, and stylish t-shirt made from 100% cotton."
,
"link"
:
"https://www.example.com/p/SKU12345"
,
"availability"
:
"OUT_OF_STOCK"
,
"price"
:
{
"amountMicros"
:
"15990000"
,
"currencyCode"
:
"USD"
},
"condition"
:
"NEW"
,
"gtins"
:
[
"9780007350896"
],
}
}
The following code samples show how to update a product.
Java
import
com.google.api.gax.core.FixedCredentialsProvider
;
import
com.google.auth.oauth2.GoogleCredentials
;
import
com.google.protobuf.FieldMask
;
import
com.google.shopping.merchant.datasources.v1.DataSourceName
;
import
com.google.shopping.merchant.products.v1.Availability
;
import
com.google.shopping.merchant.products.v1.Condition
;
import
com.google.shopping.merchant.products.v1.ProductAttributes
;
import
com.google.shopping.merchant.products.v1.ProductInput
;
import
com.google.shopping.merchant.products.v1.ProductInputName
;
import
com.google.shopping.merchant.products.v1.ProductInputsServiceClient
;
import
com.google.shopping.merchant.products.v1.ProductInputsServiceSettings
;
import
com.google.shopping.merchant.products.v1.UpdateProductInputRequest
;
import
com.google.shopping.type.CustomAttribute
;
import
shopping.merchant.samples.utils.Authenticator
;
import
shopping.merchant.samples.utils.Config
;
/** This class demonstrates how to update a product input */
public
class
UpdateProductInputSample
{
public
static
void
updateProductInput
(
Config
config
,
String
productId
,
String
dataSourceId
)
throws
Exception
{
// Obtains OAuth token based on the user's configuration.
GoogleCredentials
credential
=
new
Authenticator
().
authenticate
();
// Creates service settings using the credentials retrieved above.
ProductInputsServiceSettings
productInputsServiceSettings
=
ProductInputsServiceSettings
.
newBuilder
()
.
setCredentialsProvider
(
FixedCredentialsProvider
.
create
(
credential
))
.
build
();
// Creates product name to identify product.
String
name
=
ProductInputName
.
newBuilder
()
.
setAccount
(
config
.
getAccountId
().
toString
())
.
setProductinput
(
productId
)
.
build
()
.
toString
();
// Just productAttributes and customAttributes can be updated
FieldMask
fieldMask
=
FieldMask
.
newBuilder
()
.
addPaths
(
"product_attributes.title"
)
.
addPaths
(
"product_attributes.description"
)
.
addPaths
(
"product_attributes.link"
)
.
addPaths
(
"product_attributes.image_link"
)
.
addPaths
(
"product_attributes.availability"
)
.
addPaths
(
"product_attributes.condition"
)
.
addPaths
(
"product_attributes.gtins"
)
.
addPaths
(
"custom_attributes.mycustomattribute"
)
.
build
();
// Calls the API and catches and prints any network failures/errors.
try
(
ProductInputsServiceClient
productInputsServiceClient
=
ProductInputsServiceClient
.
create
(
productInputsServiceSettings
))
{
ProductAttributes
attributes
=
ProductAttributes
.
newBuilder
()
.
setTitle
(
"A Tale of Two Cities"
)
.
setDescription
(
"A classic novel about the French Revolution"
)
.
setLink
(
"https://exampleWebsite.com/tale-of-two-cities.html"
)
.
setImageLink
(
"https://exampleWebsite.com/tale-of-two-cities.jpg"
)
.
setAvailability
(
Availability
.
IN_STOCK
)
.
setCondition
(
Condition
.
NEW
)
.
addGtins
(
"9780007350896"
)
.
build
();
// The datasource can be either a primary or supplemental datasource.
String
dataSource
=
DataSourceName
.
newBuilder
()
.
setAccount
(
config
.
getAccountId
().
toString
())
.
setDatasource
(
dataSourceId
)
.
build
()
.
toString
();
UpdateProductInputRequest
request
=
UpdateProductInputRequest
.
newBuilder
()
.
setUpdateMask
(
fieldMask
)
// You can only update product attributes and custom_attributes
.
setDataSource
(
dataSource
)
.
setProductInput
(
ProductInput
.
newBuilder
()
.
setName
(
name
)
.
setProductAttributes
(
attributes
)
.
addCustomAttributes
(
CustomAttribute
.
newBuilder
()
.
setName
(
"mycustomattribute"
)
.
setValue
(
"Example value"
)
.
build
())
.
build
())
.
build
();
System
.
out
.
println
(
"Sending update ProductInput request"
);
ProductInput
response
=
productInputsServiceClient
.
updateProductInput
(
request
);
System
.
out
.
println
(
"Updated ProductInput Name below"
);
// The last part of the product name will be the product ID assigned to a product by Google.
// Product ID has the format `contentLanguage~feedLabel~offerId`
System
.
out
.
println
(
response
.
getName
());
System
.
out
.
println
(
"Updated Product below"
);
System
.
out
.
println
(
response
);
}
catch
(
Exception
e
)
{
System
.
out
.
println
(
e
);
}
}
public
static
void
main
(
String
[]
args
)
throws
Exception
{
Config
config
=
Config
.
load
();
// An ID assigned to a product by Google. In the format
// contentLanguage~feedLabel~offerId
String
productId
=
"en~label~sku123"
;
// Replace with your product ID.
// Identifies the data source that will own the product input.
String
dataSourceId
=
"{INSERT_DATASOURCE_ID}"
;
// Replace with your datasource ID.
updateProductInput
(
config
,
productId
,
dataSourceId
);
}
}
PHP
use Google\ApiCore\ApiException;
use Google\Protobuf\FieldMask;
use Google\Shopping\Merchant\Products\V1\Availability;
use Google\Shopping\Merchant\Products\V1\Condition;
use Google\Shopping\Merchant\Products\V1\ProductAttributes;
use Google\Shopping\Merchant\Products\V1\Client\ProductInputsServiceClient;
use Google\Shopping\Merchant\Products\V1\ProductInput;
use Google\Shopping\Merchant\Products\V1\UpdateProductInputRequest;
use Google\Shopping\Type\CustomAttribute;
/**
* This class demonstrates how to update a product input.
*/
class UpdateProductInputSample
{
// An ID assigned to a product by Google. In the format
// contentLanguage~feedLabel~offerId
// Please ensure this product ID exists for the update to succeed.
private const PRODUCT_ID = "online~en~label~sku123";
// Identifies the data source that will own the product input.
// Please ensure this data source ID exists.
private const DATASOURCE_ID = "<INSERT_DATASOURCE_ID>";
/**
* Helper function to construct the full product input resource name.
*
* @param string $accountId The merchant account ID.
* @param string $productInputId The product input ID (e.g., "online~en~label~sku123").
* @return string The full product input resource name.
*/
private static function getProductInputName(string $accountId, string $productInputId): string
{
return sprintf("accounts/%s/productInputs/%s", $accountId, $productInputId);
}
/**
* Helper function to construct the full data source resource name.
*
* @param string $accountId The merchant account ID.
* @param string $dataSourceId The data source ID.
* @return string The full data source resource name.
*/
private static function getDataSourceName(string $accountId, string $dataSourceId): string
{
return sprintf("accounts/%s/dataSources/%s", $accountId, $dataSourceId);
}
/**
* Updates an existing product input in your Merchant Center account.
*
* @param array $config The configuration array containing the account ID.
* @param string $productId The ID of the product input to update.
* @param string $dataSourceId The ID of the data source.
*/
public static function updateProductInput(
array $config,
string $productId,
string $dataSourceId
): void {
// Gets the OAuth credentials to make the request.
$credentials = Authentication::useServiceAccountOrTokenFile();
// Creates options config containing credentials for the client to use.
$options = ['credentials' => $credentials];
// Creates a ProductInputsServiceClient.
$productInputsServiceClient = new ProductInputsServiceClient($options);
// Construct the full resource name of the product input to be updated.
$name = self::getProductInputName($config['accountId'], $productId);
// Define the FieldMask to specify which fields to update.
// Only 'attributes' and 'custom_attributes' can be specified in the
// FieldMask for product input updates.
$fieldMask = new FieldMask([
'paths' => [
"product_attributes.title",
"product_attributes.description",
"product_attributes.link",
"product_attributes.image_link",
"product_attributes.availability",
"product_attributes.condition",
"product_attributes.gtin",
"custom_attributes.mycustomattribute" // Path for a specific custom attribute
]
]);
// Calls the API and handles any network failures or errors.
try {
// Define the new attributes for the product.
$attributes = new ProductAttributes([
'title' => 'A Tale of Two Cities 3',
'description' => 'A classic novel about the French Revolution',
'link' => 'https://exampleWebsite.com/tale-of-two-cities.html',
'image_link' => 'https://exampleWebsite.com/tale-of-two-cities.jpg',
'availability' => Availability::IN_STOCK,
'condition' => Condition::PBNEW,
'gtins' => ['9780007350896'] // GTIN is a repeated field.
]);
// Construct the full data source name.
// This specifies the data source context for the update.
$dataSource = self::getDataSourceName($config['accountId'], $dataSourceId);
// Create the ProductInput object with the desired updates.
// The 'name' field must match the product input being updated.
$productInput = new ProductInput([
'name' => $name,
'product_attributes' => $attributes,
'custom_attributes' => [ // Provide the list of custom attributes.
new CustomAttribute([
'name' => 'mycustomattribute',
'value' => 'Example value'
])
]
]);
// Create the UpdateProductInputRequest.
$request = new UpdateProductInputRequest([
'update_mask' => $fieldMask,
'data_source' => $dataSource,
'product_input' => $productInput
]);
print "Sending update ProductInput request\n";
// Make the API call to update the product input.
$response = $productInputsServiceClient->updateProductInput($request);
print "Updated ProductInput Name below\n";
// The name of the updated product input.
// The last part of the product name is the product ID (e.g., contentLanguage~feedLabel~offerId).
print $response->getName() . "\n";
print "Updated Product below\n";
// Print the full updated product input object.
print_r($response);
} catch (ApiException $e) {
printf("ApiException caught: %s\n", $e->getMessage());
}
}
/**
* Executes the UpdateProductInput sample.
*/
public function callSample(): void
{
$config = Config::generateConfig();
$productId = self::PRODUCT_ID;
$dataSourceId = self::DATASOURCE_ID;
self::updateProductInput($config, $productId, $dataSourceId);
}
}
// Run the script.
$sample = new UpdateProductInputSample();
$sample->callSample();