Stay organized with collectionsSave and categorize content based on your preferences.
TheProductssub-API lets you manage the entire lifecycle of your products in
Merchant Center. You can use it to upload new products, update existing ones,
retrieve product information, and delete products you no longer sell.
Special considerations
Products can only be inserted,updated or deleted if they belong todata
sourcesof typeAPI. You cannot insert or update products within data sources that
use file-based uploads.
To keep your products relevant and prevent expiration , you should update or
refresh them with a regular cadence (at least every 30 days).
Prerequisites
Before you can add or manage products using the API, you must have at least one
data source configured in your Merchant Center account.
To create a data source, use thedataSources.createmethod from the Data Sources sub-API. For detailed instructions, see theManage
API data sources for product
uploadsguide. After creating a
data source, take note of itsname(for example,accounts/12345/dataSources/67890), as you'll need it for product-related
creation, update, or deletion requests.
Add a product
To add a new product to your Merchant Center account, you need to insert aProductInputresource into a primary data source. This action creates the
product and starts processing. The fields within theproductAttributesobject
must conform to theProduct data
specification.
Use theproductInputs.insertmethod and provide thenameof your primary data source as thedataSourceparameter.
This example inserts a new product for an online store into a primary data
source.
POST https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{"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","imageLink":"https://www.example.com/img/SKU12345.jpg","availability":"IN_STOCK","price":{"amountMicros":"15990000",// 15.99 USD"currencyCode":"USD"},"condition":"NEW","gtins":["9780007350896","93433295494587"]}}
A successful call returns the newly createdProductInputresource. Thenamefield contains the unique identifier for this product input, and theproductfield contains the name of the final, processed product you can later use to
retrieve it.
{"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","imageLink":"https://www.example.com/img/SKU12345.jpg","availability":"IN_STOCK","price":{"amountMicros":"15990000","currencyCode":"USD"},"condition":"NEW","gtins":["9780007350896"]}}
The following code samples show how to add a product.
Java
importcom.google.api.gax.core.FixedCredentialsProvider;importcom.google.auth.oauth2.GoogleCredentials;importcom.google.shopping.merchant.products.v1.Availability;importcom.google.shopping.merchant.products.v1.Condition;importcom.google.shopping.merchant.products.v1.InsertProductInputRequest;importcom.google.shopping.merchant.products.v1.ProductAttributes;importcom.google.shopping.merchant.products.v1.ProductInput;importcom.google.shopping.merchant.products.v1.ProductInputsServiceClient;importcom.google.shopping.merchant.products.v1.ProductInputsServiceSettings;importcom.google.shopping.merchant.products.v1.Shipping;importcom.google.shopping.type.Price;importshopping.merchant.samples.utils.Authenticator;importshopping.merchant.samples.utils.Config;/** This class demonstrates how to insert a product input */publicclassInsertProductInputSample{privatestaticStringgetParent(StringaccountId){returnString.format("accounts/%s",accountId);}publicstaticvoidinsertProductInput(Configconfig,StringdataSource)throwsException{// Obtains OAuth token based on the user's configuration.GoogleCredentialscredential=newAuthenticator().authenticate();// Creates service settings using the credentials retrieved above.ProductInputsServiceSettingsproductInputsServiceSettings=ProductInputsServiceSettings.newBuilder().setCredentialsProvider(FixedCredentialsProvider.create(credential)).build();// Creates parent to identify where to insert the product.Stringparent=getParent(config.getAccountId().toString());// Calls the API and catches and prints any network failures/errors.try(ProductInputsServiceClientproductInputsServiceClient=ProductInputsServiceClient.create(productInputsServiceSettings)){// Price to be used for shipping ($33.45).Priceprice=Price.newBuilder().setAmountMicros(33_450_000).setCurrencyCode("USD").build();Shippingshipping=Shipping.newBuilder().setPrice(price).setCountry("GB").setService("1st class post").build();Shippingshipping2=Shipping.newBuilder().setPrice(price).setCountry("FR").setService("1st class post").build();ProductAttributesattributes=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).setGoogleProductCategory("Media > Books").addGtins("9780007350896").addShipping(shipping).addShipping(shipping2).build();// The datasource can be either a primary or supplemental datasource.InsertProductInputRequestrequest=InsertProductInputRequest.newBuilder().setParent(parent)// You can only insert products into datasource types of Input "API" and "FILE", and// of Type "Primary" or "Supplemental."// This field takes the `name` field of the datasource..setDataSource(dataSource)// If this product is already owned by another datasource, when re-inserting, the// new datasource will take ownership of the product..setProductInput(ProductInput.newBuilder().setContentLanguage("en").setFeedLabel("label").setOfferId("sku123").setProductAttributes(attributes).build()).build();System.out.println("Sending insert ProductInput request");ProductInputresponse=productInputsServiceClient.insertProductInput(request);System.out.println("Inserted 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("Inserted Product Name below");System.out.println(response.getProduct());}catch(Exceptione){System.out.println(e);}}publicstaticvoidmain(String[]args)throwsException{Configconfig=Config.load();// Identifies the data source that will own the product input.StringdataSource="accounts/"+config.getAccountId()+"/dataSources/{INSERT_DATASOURCE_ID}";insertProductInput(config,dataSource);}}
use Google\ApiCore\ApiException;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\InsertProductInputRequest;use Google\Shopping\Merchant\Products\V1\ProductInput;use Google\Shopping\Merchant\Products\V1\Client\ProductInputsServiceClient;use Google\Shopping\Merchant\Products\V1\Shipping;use Google\Shopping\Type\Price;/*** Uploads a product input to your Merchant Center account.*/class InsertProductInput{// ENSURE you fill in the datasource ID for the sample to work.private const DATASOURCE = 'INSERT_DATASOURCE_ID';/*** A helper function to create the parent string.** @param array $accountId* The account that owns the product.** @return string The parent has the format: `accounts/{account_id}`*/private static function getParent($accountId){return sprintf("accounts/%s", $accountId);}/*** Uploads a product input to your Merchant Center account. If an input* with the same feedLabel, contentLanguage, offerId, and dataSource* already exists, this method replaces that entry.** After inserting, updating, or deleting a product input, it may take several* minutes before the processed product can be retrieved.** @param array $config* The configuration data used for authentication and getting the acccount* ID.* @param string $dataSource* The primary or supplemental product data source name. If the* product already exists and data source provided is different, then the* product will be moved to a new data source.* Format: `accounts/{account}/dataSources/{datasource}`.** @return void*/public static function insertProductInputSample($config, $dataSource): 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 client.$productInputsServiceClient = new ProductInputsServiceClient($options);// Creates parent to identify where to insert the product.$parent = self::getParent($config['accountId']);// Calls the API and catches and prints any network failures/errors.try {// Price to be used for shipping ($33.45).$price = new Price(['amount_micros' => 33450000,'currency_code' => 'USD']);$shipping = new Shipping(['price' => $price,'country' => 'GB','service' => '1st class post']);$shipping2 = new Shipping(['price' => $price,'country' => 'FR','service' => '1st class post']);// Creates the attributes of the product.$attributes = new ProductAttributes(['title' => 'A Tale of Two Cities','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,'google_product_category' => 'Media > Books','gtins' => ['9780007350896'],'shipping' => [$shipping, $shipping2]]);// Creates the productInput with the fundamental identifiers.$productInput = new ProductInput(['content_language' => 'en','feed_label' => 'label','offer_id' => 'sku123ABCD','product_attributes' => $attributes]);// Prepares the request message.$request = new InsertProductInputRequest(['parent' => $parent,'data_source' => $dataSource,'product_input' => $productInput]);print "Sending insert ProductInput request\n";$response = $productInputsServiceClient->insertProductInput($request);print "Inserted ProductInput Name below\n";print $response->getName() . "\n";print "Inserted Product Name below\n";print $response->getProduct() . "\n";} catch (ApiException $e) {print $e->getMessage();}}/*** Helper to execute the sample.** @return void*/public function callSample(): void{$config = Config::generateConfig();// Identifies the data source that will own the product input.$dataSource = sprintf("accounts/%s/dataSources/%s",$config['accountId'],self::DATASOURCE);// Makes the call to insert a product to the MC account.self::insertProductInputSample($config, $dataSource);}}// Run the script$sample = new InsertProductInput();$sample->callSample();
fromexamples.authenticationimportconfigurationfromexamples.authenticationimportgenerate_user_credentialsfromgoogle.shoppingimportmerchant_products_v1fromgoogle.shopping.merchant_products_v1importAvailabilityfromgoogle.shopping.merchant_products_v1importConditionfromgoogle.shopping.typeimportPrice_ACCOUNT=configuration.Configuration().read_merchant_info()_PARENT=f"accounts/{_ACCOUNT}"# You can only insert products into datasource types of Input "API" and# "FILE", and of Type "Primary" or "Supplemental."_DATA_SOURCE="[INSERT_DATA_SOURCE_HERE]"_DATA_SOURCE_NAME=f"accounts/{_ACCOUNT}/dataSources/{_DATA_SOURCE}"defcreate_product_input():"""Creates a `ProductInput` resource."""# Creates a shipping settingprice=Price()price.amount_micros=33_450_000price.currency_code="GBP"shipping_option_1=merchant_products_v1.Shipping()shipping_option_1.price=priceshipping_option_1.country="GB"shipping_option_1.service="1st class post"price2=Price()price2.amount_micros=33_450_000price2.currency_code="EUR"shipping_option_2=merchant_products_v1.Shipping()shipping_option_2.price=price2shipping_option_2.country="FR"shipping_option_2.service="2nd class post"# Sets product attributes. Make sure to replace these values with your own.attributes=merchant_products_v1.ProductAttributes()attributes.title="A Tale of Two Cities"attributes.description="A classic novel about the French Revolution"attributes.link="https://exampleWebsite.com/tale-of-two-cities.html"attributes.image_link="https://exampleWebsite.com/tale-of-two-cities.jpg"attributes.price=priceattributes.availability=Availability.IN_STOCKattributes.condition=Condition.NEWattributes.google_product_category="Media > Books"attributes.gtins=["9780007350896"]attributes.shipping=[shipping_option_1,shipping_option_2]returnmerchant_products_v1.ProductInput(content_language="en",feed_label="GB",offer_id="sku123",product_attributes=attributes,)definsert_product_input():"""Inserts the specified `ProductInput` resource."""# Gets OAuth Credentials.credentials=generate_user_credentials.main()# Creates a client.client=merchant_products_v1.ProductInputsServiceClient(credentials=credentials)# Creates the request.request=merchant_products_v1.InsertProductInputRequest(parent=_PARENT,# If this product is already owned by another datasource, when# re-inserting, the new datasource will take ownership of the product.product_input=create_product_input(),data_source=_DATA_SOURCE_NAME,)# Makes the request and catches and prints any error messages.try:response=client.insert_product_input(request=request)# 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`print(f"Input successful:{response}")exceptRuntimeErrorase:print("Input failed")print(e)# After the product is inserted, the product ID will be returned in the# response. We recommend that you check the Merchant Center to ensure that# the product is approved and visible to users before using the product ID# in any downstream processes.if__name__=="__main__":insert_product_input()
/***Insertsaproductintotheproductslist.LogstheAPIresponse.*/functionproductInsert(){//IMPORTANT://EnabletheMerchantAPIProductssub-APIAdvancedServiceandcallit//"MerchantApiProducts"//ReplacethiswithyourMerchantCenterID.constaccountId='INSERT_MERCHANT_ID';//ReplacethiswiththeDataSourceIDyouwanttouse.constdataSourceId='INSERT_DATASOURCE_ID';//Constructtheparentnameconstparent='accounts/'+accountId;//ConstructtheDataSourcenameconstdataSource=parent+'/dataSources/'+dataSourceId;//CreateaproductresourceandinsertitconstproductResource={'offerId':'fromAppsScript','contentLanguage':'en','feedLabel':'US','productAttributes':{'title':'A Tale of Two Cities','description':'A classic novel about the French Revolution','link':'http://my-book-shop.com/tale-of-two-cities.html','imageLink':'http://my-book-shop.com/tale-of-two-cities.jpg','availability':'in stock','condition':'new','googleProductCategory':'Media > Books','gtin':'[9780007350896]','price':{'amountMicros':'2500000','currencyCode':'USD'},}};try{console.log('Sending insert ProductInput request');//CalltheProductInputs.insertAPImethod.response=MerchantApiProducts.Accounts.ProductInputs.insert(productResource,parent,{dataSource});//RESTfulinsertreturnstheJSONobjectasaresponse.console.log('Inserted ProductInput below');console.log(response);}catch(e){console.log('ERROR!');console.log(e);}}
curl -X POST \"https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}" \-H "Authorization: Bearer <API_TOKEN>" \-H "Content-Type: application/json" \-d '{"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","imageLink": "https://www.example.com/img/SKU12345.jpg","availability": "IN_STOCK","price": {"amountMicros": "15990000","currencyCode": "USD"},"condition": "NEW","gtins": ["9780007350896"]}}'
Add or update product information with a supplemental data source
Use a supplemental data source to provide additional or overriding data for
products that already exist in a primary data source. This is useful for adding
information like promotions, custom labels, or overriding specific product data
without modifying the original product input.
To do this, use theproductInputs.insertmethod, but specify thenameof your supplemental data source in thedataSourceparameter. Verify thatofferId,contentLanguage, andfeedLabelmatch an existing product.
This example adds a custom label to an existing product using a supplemental
data source.
POST https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{SUPPLEMENTAL_DATASOURCE_ID}
After this call, the finalProductwill havecustomLabel0set toclearance-sale, assuming the supplemental data source has a higher priority
than the primary data source in your feed rules as defined by thedefault_rule.
Add products asynchronously
To upload a large number of products efficiently, you can send multiple insert
requests concurrently. Instead of waiting for a response to each request before
sending the next, you can send them asynchronously and handle the responses as
they arrive. This approach can significantly improve your data upload
throughput.
The following code samples show how to insert products asynchronously. To learn
about performing multiple requests at once usingcurl, seeSend multiple
requests at
once.
Java
importcom.google.api.core.ApiFuture;importcom.google.api.core.ApiFutureCallback;importcom.google.api.core.ApiFutures;importcom.google.api.gax.core.FixedCredentialsProvider;importcom.google.auth.oauth2.GoogleCredentials;importcom.google.common.util.concurrent.MoreExecutors;importcom.google.shopping.merchant.products.v1.Availability;importcom.google.shopping.merchant.products.v1.Condition;importcom.google.shopping.merchant.products.v1.InsertProductInputRequest;importcom.google.shopping.merchant.products.v1.ProductAttributes;importcom.google.shopping.merchant.products.v1.ProductInput;importcom.google.shopping.merchant.products.v1.ProductInputsServiceClient;importcom.google.shopping.merchant.products.v1.ProductInputsServiceSettings;importcom.google.shopping.merchant.products.v1.Shipping;importcom.google.shopping.type.Price;importjava.util.ArrayList;importjava.util.List;importjava.util.Random;importjava.util.stream.Collectors;importshopping.merchant.samples.utils.Authenticator;importshopping.merchant.samples.utils.Config;/** This class demonstrates how to insert a product input */publicclassInsertProductInputAsyncSample{privatestaticStringgetParent(StringaccountId){returnString.format("accounts/%s",accountId);}privatestaticStringgenerateRandomString(){Stringcharacters="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";Randomrandom=newRandom();StringBuildersb=newStringBuilder(8);for(inti=0;i<8;i++){sb.append(characters.charAt(random.nextInt(characters.length())));}returnsb.toString();}privatestaticProductInputcreateRandomProduct(){Priceprice=Price.newBuilder().setAmountMicros(33_450_000).setCurrencyCode("USD").build();Shippingshipping=Shipping.newBuilder().setPrice(price).setCountry("GB").setService("1st class post").build();Shippingshipping2=Shipping.newBuilder().setPrice(price).setCountry("FR").setService("1st class post").build();ProductAttributesattributes=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).setGoogleProductCategory("Media > Books").addGtins("9780007350896").addShipping(shipping).addShipping(shipping2).build();returnProductInput.newBuilder().setContentLanguage("en").setFeedLabel("CH").setOfferId(generateRandomString()).setProductAttributes(attributes).build();}publicstaticvoidasyncInsertProductInput(Configconfig,StringdataSource)throwsException{// Obtains OAuth token based on the user's configuration.GoogleCredentialscredential=newAuthenticator().authenticate();// Creates service settings using the credentials retrieved above.ProductInputsServiceSettingsproductInputsServiceSettings=ProductInputsServiceSettings.newBuilder().setCredentialsProvider(FixedCredentialsProvider.create(credential)).build();// Creates parent to identify where to insert the product.Stringparent=getParent(config.getAccountId().toString());// Calls the API and catches and prints any network failures/errors.try(ProductInputsServiceClientproductInputsServiceClient=ProductInputsServiceClient.create(productInputsServiceSettings)){// Creates five insert product input requests with random product IDs.List<InsertProductInputRequest>requests=newArrayList<>(5);for(inti=0;i<5;i++){InsertProductInputRequestrequest=InsertProductInputRequest.newBuilder().setParent(parent)// You can only insert products into datasource types of Input "API", and of Type// "Primary" or "Supplemental."// This field takes the `name` field of the datasource..setDataSource(dataSource)// If this product is already owned by another datasource, when re-inserting, the// new datasource will take ownership of the product..setProductInput(createRandomProduct()).build();requests.add(request);}System.out.println("Sending insert product input requests");List<ApiFuture<ProductInput>>futures=requests.stream().map(request->productInputsServiceClient.insertProductInputCallable().futureCall(request)).collect(Collectors.toList());// Creates callback to handle the responses when all are ready.ApiFuture<List<ProductInput>>responses=ApiFutures.allAsList(futures);ApiFutures.addCallback(responses,newApiFutureCallback<List<ProductInput>>(){@OverridepublicvoidonSuccess(List<ProductInput>results){System.out.println("Inserted products below");System.out.println(results);}@OverridepublicvoidonFailure(Throwablethrowable){System.out.println(throwable);}},MoreExecutors.directExecutor());}catch(Exceptione){System.out.println(e);}}publicstaticvoidmain(String[]args)throwsException{Configconfig=Config.load();// Identifies the data source that will own the product input.StringdataSource="accounts/"+config.getAccountId()+"/dataSources/{datasourceId}";asyncInsertProductInput(config,dataSource);}}
importasyncioimportfunctoolsimportrandomimportstringfromexamples.authenticationimportconfigurationfromexamples.authenticationimportgenerate_user_credentialsfromgoogle.shopping.merchant_products_v1importAvailabilityfromgoogle.shopping.merchant_products_v1importConditionfromgoogle.shopping.merchant_products_v1importInsertProductInputRequestfromgoogle.shopping.merchant_products_v1importProductAttributesfromgoogle.shopping.merchant_products_v1importProductInputfromgoogle.shopping.merchant_products_v1importProductInputsServiceAsyncClientfromgoogle.shopping.merchant_products_v1importShippingfromgoogle.shopping.typeimportPrice# Read merchant account information from the configuration file._ACCOUNT_ID=configuration.Configuration().read_merchant_info()# The parent account for the product input.# Format: accounts/{account}_PARENT=f"accounts/{_ACCOUNT_ID}"def_generate_random_string(length:int=8)->str:"""Generates a random string of a given length."""characters=string.ascii_letters+string.digitsreturn"".join(random.choice(characters)for_inrange(length))def_create_random_product()->ProductInput:"""Creates a ProductInput with random elements and predefined attributes."""price=Price(amount_micros=33450000,currency_code="USD")shipping1=Shipping(price=price,country="GB",service="1st class post")shipping2=Shipping(price=price,country="FR",service="1st class post")attributes=ProductAttributes(title="Async - A Tale of Two Cities",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.NEW,google_product_category="Media > Books",gtins=["9780007350896"],shipping=[shipping1,shipping2],)returnProductInput(content_language="en",feed_label="US",offer_id=_generate_random_string(),product_attributes=attributes,)defprint_product_input(i,task):print("Inserted ProductInput number: ",i)# task.result() contains the response from async_insert_product_inputprint(task.result())asyncdefasync_insert_product_input(client:ProductInputsServiceAsyncClient,request:InsertProductInputRequest):"""Inserts product inputs.Args:client: The ProductInputsServiceAsyncClient to use.request: The InsertProductInputRequest to send.Returns:The response from the insert_produc_input request."""print("Sending insert product input requests")try:response=awaitclient.insert_product_input(request=request)# The response is an async corouting inserting the ProductInput.returnresponseexceptRuntimeErrorase:# Catch and print any exceptions that occur during the API calls.print(e)asyncdefmain():# The ID of the data source that will own the product input.# This is a placeholder and should be replaced with an actual data source ID.datasource_id="<INSERT_DATA_SOURCE_ID_HERE>"data_source_name=f"accounts/{_ACCOUNT_ID}/dataSources/{datasource_id}"# Gets OAuth Credentials.credentials=generate_user_credentials.main()# Creates a ProductInputsServiceClient.client=ProductInputsServiceAsyncClient(credentials=credentials)tasks=[]foriinrange(5):product_input=_create_random_product()request=InsertProductInputRequest(parent=_PARENT,data_source=data_source_name,product_input=product_input,)# Create the async taskinsert_product_task=asyncio.create_task(async_insert_product_input(client,request))# Add the callbackcallback_function=functools.partial(print_product_input,i)insert_product_task.add_done_callback(callback_function)# Add the task to our listtasks.append(insert_product_task)# Await all tasks to complete concurrently# The print_product_input callback will be called for each as it finishesawaitasyncio.gather(*tasks)if__name__=="__main__":asyncio.run(main())
You can set country targeting for individual products to override the settings
from the data source, or to target products when the data source has no
countries defined.
Target countries with theshippingattribute
If your data source doesn't have specific countries defined, you can target
countries for a product by providing theshippingfield withinproductAttributes. This field lets you specify shipping costs and rules for
different countries, implicitly targeting them for serving.
This example targets a product to the US and Canada by providing two separateshippingentries.
POST https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
If your data source already targets multiple countries, you can exclude a
product from showing in a subset of those countries or from specific
destinations.
Use theshoppingAdsExcludedCountriesattribute to prevent a product from
appearing in Shopping ads in specific countries.
Use theexcludedDestinationsattribute to prevent a product from appearing
within specificMarketing
Methods, such asFreeListings.
This example assumes the data source targets the US, Canada, and Mexico. The
request excludes the product from Shopping ads in Mexico and from the Free
Listings destination entirely.
POST https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{"offerId":"SKU_EXCLUDE_TARGET","contentLanguage":"en","feedLabel":"NA","productAttributes":{"title":"North America T-Shirt","link":"https://www.example.com/p/SKU_EXCLUDE_TARGET","imageLink":"https://www.example.com/img/SKU_EXCLUDE_TARGET.jpg","availability":"IN_STOCK","price":{"amountMicros":"19990000","currencyCode":"USD"},"shoppingAdsExcludedCountries":["MX"],"excludedDestinations":["FREE_LISTINGS"]}}
Get product information
To retrieve the final processed state of a product, use theproducts.getmethod. This method returns theProductresource, which includes allproductAttributesafter feed rules and supplemental data sources have been
applied, along with its current validation status.
There can be a delay of a few minutes between when you insert or update aProductInputand when the finalProductis available to retrieve.
GET https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/products/en~US~SKU12345
A successful request returns theProductresource.
{"name":"accounts/{ACCOUNT_ID}/products/en~US~SKU12345","offerId":"SKU12345","contentLanguage":"en","feedLabel":"US","dataSource":"accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}","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","imageLink":"https://www.example.com/img/SKU12345.jpg","availability":"IN_STOCK","price":{"amountMicros":"15990000","currencyCode":"USD"},"condition":"NEW","gtins":["9780007350896"]},"productStatus":{"destinationStatuses":[{"reportingContext":"SHOPPING_ADS","approvedCountries":["US"]}],"creationDate":"2024-05-20T10:00:00Z","lastUpdateDate":"2024-05-20T10:05:00Z","googleExpirationDate":"2024-06-19T10:05:00Z"}}
The following code samples show how to get a product.
Java
importcom.google.api.gax.core.FixedCredentialsProvider;importcom.google.auth.oauth2.GoogleCredentials;importcom.google.shopping.merchant.products.v1.GetProductRequest;importcom.google.shopping.merchant.products.v1.Product;importcom.google.shopping.merchant.products.v1.ProductsServiceClient;importcom.google.shopping.merchant.products.v1.ProductsServiceSettings;importshopping.merchant.samples.utils.Authenticator;importshopping.merchant.samples.utils.Config;/** This class demonstrates how to get a single product for a given Merchant Center account */publicclassGetProductSample{publicstaticvoidgetProduct(Configconfig,Stringproduct)throwsException{// Obtains OAuth token based on the user's configuration.GoogleCredentialscredential=newAuthenticator().authenticate();// Creates service settings using the credentials retrieved above.ProductsServiceSettingsproductsServiceSettings=ProductsServiceSettings.newBuilder().setCredentialsProvider(FixedCredentialsProvider.create(credential)).build();// Calls the API and catches and prints any network failures/errors.try(ProductsServiceClientproductsServiceClient=ProductsServiceClient.create(productsServiceSettings)){// The name has the format: accounts/{account}/products/{productId}GetProductRequestrequest=GetProductRequest.newBuilder().setName(product).build();System.out.println("Sending get product request:");Productresponse=productsServiceClient.getProduct(request);System.out.println("Retrieved Product below");System.out.println(response);}catch(Exceptione){System.out.println(e);}}publicstaticvoidmain(String[]args)throwsException{Configconfig=Config.load();// The name of the `product`, returned after a `Product.insert` request. We recommend// having stored this value in your database to use for all future requests.Stringproduct="accounts/{datasource}/products/{productId}";getProduct(config,product);}}
use Google\ApiCore\ApiException;use Google\Shopping\Merchant\Products\V1\GetProductRequest;use Google\Shopping\Merchant\Products\V1\Product;use Google\Shopping\Merchant\Products\V1\Client\ProductsServiceClient;/*** This class demonstrates how to get a single product for a given Merchant Center* account.*/class GetProduct{// ENSURE you fill in the product ID for the sample to work.private const PRODUCT = 'INSERT_PRODUCT_ID_HERE';/*** Gets a product from your Merchant Center account.** @param array $config* The configuration data used for authentication and getting the acccount* ID.* @param string $product* The product ID to get.* Format: `accounts/{account}/products/{productId}`.** @return void*/public static function getProductSample($config, $product) : 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 client.$productsServiceClient = new ProductsServiceClient($options);try {// Creates the request.$request = new GetProductRequest(['name' => $product]);// Sends the request.echo "Sending get Product request\n";$response = $productsServiceClient->getProduct($request);// Outputs the response.echo "Retrieved Product below\n";print_r($response);} catch (Exception $e) {echo $e->getMessage();}}/*** Helper to execute the sample.** @return void*/public function callSample(): void{$config = Config::generateConfig();// Identifies the product to retrieve.// The name has the format: accounts/{account}/products/{productId}.$product = ProductsServiceClient::productName($config['accountId'],self::PRODUCT);self::getProductSample($config, $product);}}$sample = new GetProduct();$sample->callSample();
fromexamples.authenticationimportconfigurationfromexamples.authenticationimportgenerate_user_credentialsfromgoogle.shoppingimportmerchant_products_v1_ACCOUNT=configuration.Configuration().read_merchant_info()# ENSURE you fill in the product ID for the sample to# work.# In the format of `contentLanguage~feedLabel~offerId`_PRODUCT="[INSERT_PRODUCT_HERE]"_NAME=f"accounts/{_ACCOUNT}/products/{_PRODUCT}"defget_product():"""Gets the specified `Product` resource."""# Gets OAuth Credentials.credentials=generate_user_credentials.main()# Creates a client.client=merchant_products_v1.ProductsServiceClient(credentials=credentials)# Creates the request.request=merchant_products_v1.GetProductRequest(name=_NAME)# Makes the request and catches and prints any error messages.try:response=client.get_product(request=request)print(f"Get successful:{response}")exceptRuntimeErrorase:print("Get failed")print(e)if__name__=="__main__":get_product()
/***GetaspecificproductforagivenMerchantCenteraccount.*/functiongetProduct(){//IMPORTANT://EnabletheMerchantAPIProductssub-APIAdvancedServiceandcallit//"MerchantApiProducts"//ReplacethiswithyourMerchantCenterID.constaccountId='<MERCHANT_CENTER_ID>';//TheIDoftheproducttoretrieve.//ThisIDisassignedbyGoogleandtypicallyfollowstheformat://channel~contentLanguage~feedLabel~offerId//ReplacewithanactualproductIDfromyourMerchantCenteraccount.constproductId='<PRODUCT_ID>';//Constructtheparentnameconstparent='accounts/'+accountId;//Constructtheproductresourcenameconstname=parent+"/products/"+productId;try{console.log('Sending get Product request');//CalltheProducts.getAPImethod.product=MerchantApiProducts.Accounts.Products.get(name);console.log(product);}catch(e){console.log('ERROR!');console.log(e);}}
curl -X GET \"https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/products/en~US~SKU12345" \-H "Authorization: Bearer <API_TOKEN>"
Delete a product from a data source
To delete a product input from a specific data source, use theproductInputs.deletemethod.
If you delete from aprimary data source, the entire product including
its supplementalProductInputsis removed from Merchant Center.
If you delete from asupplemental data source, only the attributes from
that data source are removed from the product. The product itself remains,
sourced from the primary and any other supplemental data sources.
You must specify thedataSourcefrom which you are deleting the product input.
The following code samples show how to delete a product.
Java
importcom.google.api.gax.core.FixedCredentialsProvider;importcom.google.auth.oauth2.GoogleCredentials;importcom.google.shopping.merchant.products.v1.DeleteProductInputRequest;importcom.google.shopping.merchant.products.v1.ProductInputName;importcom.google.shopping.merchant.products.v1.ProductInputsServiceClient;importcom.google.shopping.merchant.products.v1.ProductInputsServiceSettings;importshopping.merchant.samples.utils.Authenticator;importshopping.merchant.samples.utils.Config;/** This class demonstrates how to delete a product for a given Merchant Center account */publicclassDeleteProductInputSample{publicstaticvoiddeleteProductInput(Configconfig,StringproductId,StringdataSource)throwsException{// Obtains OAuth token based on the user's configuration.GoogleCredentialscredential=newAuthenticator().authenticate();// Creates service settings using the credentials retrieved above.ProductInputsServiceSettingsproductInputsServiceSettings=ProductInputsServiceSettings.newBuilder().setCredentialsProvider(FixedCredentialsProvider.create(credential)).build();// Creates product name to identify product.Stringname=ProductInputName.newBuilder().setAccount(config.getAccountId().toString()).setProductinput(productId).build().toString();// Calls the API and catches and prints any network failures/errors.try(ProductInputsServiceClientproductInputsServiceClient=ProductInputsServiceClient.create(productInputsServiceSettings)){DeleteProductInputRequestrequest=DeleteProductInputRequest.newBuilder().setName(name).setDataSource(dataSource).build();System.out.println("Sending deleteProductInput request");productInputsServiceClient.deleteProductInput(request);// no response returned on successSystem.out.println("Delete successful, note that it may take a few minutes for the delete to update in"+" the system. If you make a products.get or products.list request before a few"+" minutes have passed, the old product data may be returned.");}catch(Exceptione){System.out.println(e);}}publicstaticvoidmain(String[]args)throwsException{Configconfig=Config.load();// An ID assigned to a product by Google. In the format// contentLanguage~feedLabel~offerIdStringproductId="online~en~label~sku123";// The name of the dataSource from which to delete the product. If it is a primary feed, this// will delete the product completely. If it's a supplemental feed, it will only delete the// product information from that feed, but the product will still be available from the primary// feed.StringdataSource="accounts/{account}/dataSources/{dataSource}";deleteProductInput(config,productId,dataSource);}}
use Google\ApiCore\ApiException;use Google\Auth\CredentialsLoader;use Google\Shopping\Merchant\Products\V1\Client\ProductInputsServiceClient;use Google\Shopping\Merchant\Products\V1\DeleteProductInputRequest;use Google\Shopping\Merchant\Products\V1\ProductInputName;/*** This class demonstrates how to delete a productinput for a given Merchant Center* account.*/class DeleteProductInput{// ENSURE you fill in the product and datasource ID for the sample to work.// An ID assigned to a product by Google:// In the format `contentLanguage~feedLabel~offerId`private const PRODUCT = 'INSERT_PRODUCT_ID_HERE';private const DATASOURCE = 'INSERT_DATASOURCE_ID_HERE';/*** Deletes a product input to your Merchant Center account.** @param array $config* The configuration data used for authentication and getting the* acccount ID.* @param string $product* The product ID to delete.* Format: `accounts/{account}/products/{productId}`.* @param string $dataSource* The primary or supplemental product data source name that owns the* product.* Format: `accounts/{account}/dataSources/{datasource}`.** @return void*/public static function deleteProductInputSample($config, $product, $dataSource): void {// Obtains OAuth token based on the user's configuration.$credentials = Authentication::useServiceAccountOrTokenFile();// Creates service settings using the credentials retrieved above.$options = ['credentials' => $credentials];$productInputsServiceClient = new ProductInputsServiceClient($options);// Calls the API and catches and prints any network failures/errors.try {$request = new DeleteProductInputRequest(['name' => $product,'data_source' => $dataSource]);echo "Sending deleteProductInput request\n";$productInputsServiceClient->deleteProductInput($request);echo "Delete successful, note that it may take a few minutes for the ". "delete to update in the system. If you make a products.get or ". "products.list request before a few minutes have passed, the old ". "product data may be returned.\n";} catch (ApiException $e) {echo "An error has occurred: \n";echo $e->getMessage() . "\n";}}/*** Helper to execute the sample.** @return void*/public function callSample(): void{$config = Config::generateConfig();// The productID variable is defined at the top of the file.$product = ProductInputsServiceClient::productInputName($config['accountId'],self::PRODUCT);// The name of the dataSource from which to delete the product.$dataSource = sprintf('accounts/%s/dataSources/%s',$config['accountId'],self::DATASOURCE);self::deleteProductInputSample($config, $product, $dataSource);}}// Run the script.$sample = new DeleteProductInput();$sample->callSample();
fromexamples.authenticationimportconfigurationfromexamples.authenticationimportgenerate_user_credentialsfromgoogle.shoppingimportmerchant_products_v1_ACCOUNT=configuration.Configuration().read_merchant_info()# ENSURE you fill in the product ID and data source for the# sample to work.# In the format of `contentLanguage~feedLabel~offerId`_PRODUCT="[INSERT_PRODUCT_HERE]"_DATA_SOURCE="[INSERT_DATA_SOURCE_HERE]"_NAME=f"accounts/{_ACCOUNT}/productInputs/{_PRODUCT}"_DATA_SOURCE_NAME=f"accounts/{_ACCOUNT}/dataSources/{_DATA_SOURCE}"defdelete_product_input():"""Deletes the specified `ProductInput` resource."""# Gets OAuth Credentials.credentials=generate_user_credentials.main()# Creates a client.client=merchant_products_v1.ProductInputsServiceClient(credentials=credentials)# Creates the request.request=merchant_products_v1.DeleteProductInputRequest(name=_NAME,data_source=_DATA_SOURCE_NAME)# Makes the request and catch and print any error messages.try:client.delete_product_input(request=request)print("Deletion successful")exceptRuntimeErrorase:print("Deletion failed")print(e)if__name__=="__main__":delete_product_input()
[[["Easy to understand","easyToUnderstand","thumb-up"],["Solved my problem","solvedMyProblem","thumb-up"],["Other","otherUp","thumb-up"]],[["Missing the information I need","missingTheInformationINeed","thumb-down"],["Too complicated / too many steps","tooComplicatedTooManySteps","thumb-down"],["Out of date","outOfDate","thumb-down"],["Samples / code issue","samplesCodeIssue","thumb-down"],["Other","otherDown","thumb-down"]],["Last updated 2025-08-11 UTC."],[],[],null,[]]