Merchant API Code Sample to Update Product Input
Java
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shopping.merchant.samples.products.v1beta;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.protobuf.FieldMask;
import com.google.shopping.merchant.datasources.v1beta.DataSourceName;
import com.google.shopping.merchant.products.v1beta.Attributes;
import com.google.shopping.merchant.products.v1beta.ProductInput;
import com.google.shopping.merchant.products.v1beta.ProductInputName;
import com.google.shopping.merchant.products.v1beta.ProductInputsServiceClient;
import com.google.shopping.merchant.products.v1beta.ProductInputsServiceSettings;
import com.google.shopping.merchant.products.v1beta.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 attributes and customAttributes can be updated
FieldMask fieldMask =
FieldMask.newBuilder()
.addPaths("attributes.title")
.addPaths("attributes.description")
.addPaths("attributes.link")
.addPaths("attributes.image_link")
.addPaths("attributes.availability")
.addPaths("attributes.condition")
.addPaths("attributes.gtin")
.addPaths("custom_attributes.mycustomattribute")
.build();
// Calls the API and catches and prints any network failures/errors.
try (ProductInputsServiceClient productInputsServiceClient =
ProductInputsServiceClient.create(productInputsServiceSettings)) {
Attributes attributes =
Attributes.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("in stock")
.setCondition("new")
.addGtin("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)
.setAttributes(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 `channel~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
// channel~contentLanguage~feedLabel~offerId
String productId = "online~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);
}
}
Node.js
// Copyright 2025 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
'use strict';
// This sample demonstrates how to update a ProductInput for a given merchant.
const fs = require('fs');
const authUtils = require('../../authentication/authenticate.js');
const {
ProductInputsServiceClient,
} = require('@google-shopping/products').v1beta;
/**
* Performs the actual API call to update the product input.
*
* @param {!object} authClient - An authenticated Google Auth client.
* @param {string} accountId - The ID of the merchant account.
* @param {string} productId - The ID of the product to update.
* @param {string} dataSourceId - The ID of the data source.
*/
async function callUpdateProductInput(
authClient, accountId, productId, dataSourceId) {
// Create a new ProductInputsServiceClient with the authenticated client.
const productInputsServiceClient = new ProductInputsServiceClient({
authClient: authClient,
});
// Construct the full name of the product input resource.
// Format: accounts/{account}/productinputs/{productinput}
const name = `accounts/${accountId}/productInputs/${productId}`;
// Define the FieldMask to specify which fields of the product input to
// update. According to the API, only 'attributes' and 'customAttributes' can
// be updated this way.
const fieldMask = {
paths: [
'attributes.title', 'attributes.description', 'attributes.link',
'attributes.image_link', 'attributes.availability',
'attributes.condition', 'attributes.gtin',
'custom_attributes.mycustomattribute', // This path targets a custom
// attribute by its name.
],
};
// Prepare the new attributes for the product.
const attributes = {
title: 'A Tale of Two Cities',
description: 'A classic novel about the French Revolution',
link: 'https://exampleWebsite.com/tale-of-two-cities.html',
imageLink: 'https://exampleWebsite.com/tale-of-two-cities.jpg',
availability: 'in stock',
condition: 'new',
gtin: [
'9780007350896'
], // GTIN is a repeated field, so it's provided as an array.
};
// Construct the full name of the data source resource.
// The datasource can be either a primary or supplemental datasource.
// Format: accounts/{account}/dataSources/{datasource}
const dataSource = `accounts/${accountId}/dataSources/${dataSourceId}`;
// Prepare the ProductInput object with the new data.
const productInput = {
name: name, // The resource name of the product input being updated.
attributes: attributes,
customAttributes: [
{
name: 'mycustomattribute',
value: 'Example value',
},
],
};
// Construct the update request object.
const request = {
productInput: productInput,
updateMask: fieldMask,
dataSource: dataSource,
};
console.log('Sending update ProductInput request');
// Make the API call to update the product input.
// The response is an array, with the first element being the updated
// ProductInput object.
const [response] =
await productInputsServiceClient.updateProductInput(request);
console.log('Updated ProductInput Name below');
// The response contains the updated ProductInput. Its 'name' field is the
// full resource name, which includes the Google-assigned product ID (format:
// channel~contentLanguage~feedLabel~offerId).
console.log(response.name);
console.log('Updated Product below');
console.log(response); // Log the full response object.
}
/**
* Main function to orchestrate the product input update.
* It handles configuration, authentication, and calls the core update logic.
*/
async function main() {
// These are the IDs for the product and data source to be used in the update.
// The productId is an ID assigned by Google, typically in the format:
// channel~contentLanguage~feedLabel~offerId. Replace 'online~en~label~sku123'
// with your specific product ID.
const productId = 'online~en~label~sku123';
// The dataSourceId identifies the data source that will own the product
// input. Replace '{INSERT_DATASOURCE_ID}' with your actual data source ID.
const dataSourceId = '{INSERT_DATASOURCE_ID}';
try {
// Load application configuration, which includes the path to
// merchant-info.json.
const config = authUtils.getConfig();
// Read the Merchant Center account ID from the merchant-info.json file.
const merchantInfo =
JSON.parse(fs.readFileSync(config.merchantInfoFile, 'utf8'));
const accountId = merchantInfo.merchantId;
// Authenticate and get an OAuth2 client.
const authClient = await authUtils.getOrGenerateUserCredentials();
// Call the helper function to perform the product input update.
// Ensure accountId is a string as it's part of a resource name.
await callUpdateProductInput(
authClient, accountId.toString(), productId, dataSourceId);
} catch (error) {
console.error(error);
process.exitCode = 1;
}
}
main();
PHP
<?php
/**
* Copyright 2025 Google LLC
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* https://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
require_once __DIR__ . '/../../../vendor/autoload.php';
require_once __DIR__ . '/../../Authentication/Authentication.php';
require_once __DIR__ . '/../../Authentication/Config.php';
use Google\ApiCore\ApiException;
use Google\Protobuf\FieldMask;
use Google\Shopping\Merchant\Products\V1beta\Attributes;
use Google\Shopping\Merchant\Products\V1beta\Client\ProductInputsServiceClient;
use Google\Shopping\Merchant\Products\V1beta\ProductInput;
use Google\Shopping\Merchant\Products\V1beta\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
// channel~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' => [
"attributes.title",
"attributes.description",
"attributes.link",
"attributes.image_link",
"attributes.availability",
"attributes.condition",
"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 Attributes([
'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' => 'in stock',
'condition' => 'new',
'gtin' => ['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,
'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., channel~contentLanguage~feedLabel~offerId).
print $response->getName() . "\n";
print "Updated Product below\n";
// Print the full updated product input object.
print $response->serializeToJsonString(['prettyPrint' => true]) . "\n";
} 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();
Python
# -*- coding: utf-8 -*-
# Copyright 2025 Google LLC
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""A module to update a product input."""
from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.protobuf import field_mask_pb2
from google.shopping.merchant_products_v1beta import Attributes
from google.shopping.merchant_products_v1beta import ProductInput
from google.shopping.merchant_products_v1beta import ProductInputsServiceClient
from google.shopping.merchant_products_v1beta import UpdateProductInputRequest
from google.shopping.type import CustomAttribute
# Fetches the Merchant Center account ID from the authentication examples.
# This ID is needed to construct resource names for the API.
_ACCOUNT_ID = configuration.Configuration().read_merchant_info()
def update_product_input(account_id: str, product_id: str, data_source_id: str):
"""Updates an existing product input for a specific account.
Args:
account_id: The Merchant Center account ID.
product_id: The ID of the product input to update. This ID is assigned by
Google and has the format `channel~contentLanguage~feedLabel~offerId`.
data_source_id: The ID of the data source that owns the product input.
"""
# Obtains OAuth credentials for authentication.
credentials = generate_user_credentials.main()
# Creates a ProductInputsServiceClient instance.
client = ProductInputsServiceClient(credentials=credentials)
# Constructs the full resource name for the product input.
# Format: accounts/{account}/productInputs/{productinput}
name = f"accounts/{account_id}/productInputs/{product_id}"
# Defines the FieldMask to specify which fields of the product input
# are being updated. Only 'attributes' and 'custom_attributes' can be updated.
field_mask = field_mask_pb2.FieldMask(
paths=[
"attributes.title",
"attributes.description",
"attributes.link",
"attributes.image_link",
"attributes.availability",
"attributes.condition",
"attributes.gtin",
"custom_attributes.mycustomattribute",
]
)
# Prepares the new attribute values for the product.
attributes = Attributes(
title="A Tale of Two Cities updated",
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="in stock",
condition="new",
gtin=["9780007350896"], # GTIN is a repeated field.
)
# Constructs the full resource name for the data source.
# The data source can be primary or supplemental.
# Format: accounts/{account}/dataSources/{datasource}
data_source = f"accounts/{account_id}/dataSources/{data_source_id}"
# Prepares the ProductInput object with the updated information.
product_input_data = ProductInput(
name=name,
attributes=attributes,
custom_attributes=[
CustomAttribute(
name="mycustomattribute", value="Example value"
)
],
)
# Creates the UpdateProductInputRequest.
request = UpdateProductInputRequest(
update_mask=field_mask,
data_source=data_source,
product_input=product_input_data,
)
# Sends the update request to the API.
try:
print("Sending update ProductInput request")
response = client.update_product_input(request=request)
print("Updated ProductInput Name below")
# The response includes the name of the updated product input.
# The last part of the product name is the product ID assigned by Google.
print(response.name)
print("Updated Product below")
print(response)
except RuntimeError as e:
# Catches and prints any errors that occur during the API call.
print(e)
if __name__ == "__main__":
# The ID of the product to be updated.
# This ID is assigned by Google and typically follows the format:
# channel~contentLanguage~feedLabel~offerId
# Replace with an actual product ID from your Merchant Center account.
product_id_to_update = "online~en~label~sku123"
# The ID of the data source that will own the updated product input.
# Replace with an actual data source ID from your Merchant Center account.
data_source_id_for_update = "<INSERT_DATA_SOURCE_ID>"
update_product_input(
_ACCOUNT_ID, product_id_to_update, data_source_id_for_update
)