This page explains how you can upload and manage your products programmatically. Using the Merchant Products API, you can insert or update a product in a data source, retrieve a product from your account, and delete a product from a data source.
Merchant Products API contains two resources.
productInputs
represents the input parts of your products.products
represents the processed products that was constructed from your input parts.
productInputs
can be primary and supplementary, depending whether it is
uploaded to a
primary data source
or a
supplemental data source.
Each product
will be constructed from a single primary productInput
and any
number of supplemental productInputs
.
You can use the Merchant Products API to create an online or local store
catalogs, these are products which can appear on
multiple shopping destinations.
You can use the productInputs
resource once you have created your
Merchant Center account, set up your first
data source and are
ready to upload an initial set of products through the API.
Although merchants have the ability to upload products using a file called a PrimaryProductDataSource, there are several advantages of creating and deleting products using the Merchant API. These advantages include faster response time and the ability to update products in real time, without the need to manage large files. It may take up to several hours for product changes made by API calls to show in the Shopping database.
Prerequisites
If you don't have a data source, create a data source using the Merchant Data Sources API or the Merchant Center.
If you already have a data source that you created either using the Merchant Center UI or using the API, then you can use the Merchant Products API to add your products. If you are using the Content API for Shopping to add products, refer to the migration guide to understand how to get started with the Merchant Products API.
You are responsible for complying with the Shopping Ads and free listings policies. Shopping Ads reserves the right to enforce these policies and respond appropriately if we find content or behavior that violates these policies.
Resources
The products
resource lets you retrieve product information from the
Shopping database.
The
productInput
resource represents the input data you submit for a product. It also provides
methods that let you update, or delete product information one at a time, or
many at a time in batch mode. A
productInput
resource must have the following fields:
channel
: The channel of the product.offerId
: The unique identifier for the product.contentLanguage
: The two-letter ISO 639-1 language code for the product.feedLabel
: The label that lets you categorize and identify your products. The maximum allowed characters are 20 and the supported characters areA-Z
,0-9
, hyphen and underscore. The feed label must not include any spaces. For more information, see Using feed labels.
Upload a product input into your account
To upload a product input into your account, use the
accounts.productInputs.insert
method. You must pass the
unique identifier of the primary or supplemental data
source.
The following sample request shows how you can use the
accounts.productInputs.insert
method to upload a product input to your
merchant account. The request sets the shipping price and region, and custom
attributes like date of manufacture and size.
POST https://merchantapi.googleapis.com/products/v1beta/accounts/{ACCOUNT_ID} /productInputs:insert?dataSource={DATASOURCE}
{
"name": "{PRODUCT_TITLE} ",
"versionNumber": {VERSION_NUMBER} ,
"contentLanguage": "{CONTENT_LANGUAGE} ",
"feedLabel": "{FEED_LABEL} ",
"offerId": "{OFFER_ID} ",
"channel": "ONLINE",
"attributes": {
"availability": "in stock",
"imageLink": "{IMAGE_LINK} ",
"link": "{PRODUCT_LINK} ",
"brand": "{BRAND_NAME} ",
"price": {
"currencyCode": "{CURRENCY_CODE} ",
"amountMicros": {PRICE}
},
"color": "red",
"productWeight": {
"value": 320,
"unit": "g"
},
"adult": false,
"shipping": [
{
"country": "GB",
"price": {
"amountMicros": {SHIPPING_COST} ,
"currencyCode": "{CURRENCY_CODE_SHIPPING} "
},
"postalCode": "{SHIPPING_POSTALCODE} ",
"service": "",
"region": "{SHIPPING_REGION} ",
"maxHandlingTime": "{MAX_HANDLING_TIME} ",
"minHandlingTime": "{MIN_HANDLING_TIME} ",
"maxTransitTime": "{MAX_TRANSIT_TIME} ",
"minTransitTime": "{MIN_TRANSIT_TIME} "
}
],
"gender": "Female"
},
"customAttributes": [
{
"name": "size",
"value": "Large"
},
{
"name": "Date of Manufacturing",
"value": "2024-05-05"
}
]
}
Replace the following:
- {ACCOUNT_ID}: The unique identifier of your Merchant Center account.
- {DATASOURCE}: The unique identifier of the data
source. It should be in the format
accounts/
{ACCOUNT_ID}/dataSources/
{DATASOURCE_ID}. - {PRODUCT_TITLE}: The name of the product.
- {VERSION_NUMBER}: The version number of the product. Optional.
- {CONTENT_LANGUAGE}: The two-letter ISO 639-1 language code for the product. Required.
- {FEED_LABEL}: The label that lets you categorize
and identify your products. The maximum allowed characters are 20 and the
supported characters are
A-Z
,0-9
, hyphen and underscore. The feed label must not include any spaces. - {OFFER_ID}: The unique identifier of the product. Required.
- {IMAGE_LINK}: The link to the product's image on your website. Optional.
- {PRODUCT_LINK}: The link to the product on your website. Optional.
- {CURRENCY_CODE}: The currency of the price using three-letter acronyms according to ISO 4217. Optional.
- {PRICE}: The price of the product represented as a number in micros. Optional.
- {SHIPPING_COST}: The fixed shipping price represented as a number. Optional.
- {SHIPPING_POSTALCODE}: The postal code range where the shipping rate applies. Optional.
- {MAX_HANDLING_TIME}: The maximum handling time in business days between when the order is received and when it is shipped. Optional.
- {MIN_HANDLING_TIME}: The minimum handling time in business days between when the order is received and when it is shipped. The value 0 means that the order is delivered on the same day as it is received. Optional.
- {MAX_TRANSIT_TIME}: The maximum transit time in business days between when the order has been shipped and when it is delivered. Optional.
- {MIN_TRANSIT_TIME}: The minimum transit time in business days between when the order has been shipped and when it is delivered. The value 0 means that the order is delivered on the same day as it is shipped. Optional.
When the request runs successfully, you see the following response:
{
"name": "{PRODUCT_NAME} ",
"product": "{PRODUCT_ID} ",
"channel": "ONLINE",
"offerId": "{OFFER_ID} ",
"contentLanguage": "{CONTENT_LANGUAGE} ",
"feedLabel": "{FEED_LABEL} ",
"versionNumber": "{VERSION_NUMBER} ",
"attributes": {
"link": "{PRODUCT_LINK} ",
"imageLink": "{IMAGE_LINK} ",
"adult": false,
"availability": "in stock",
"brand": "{BRAND_NAME} ",
"color": "red",
"gender": "Female",
"price": {
"amountMicros": "{PRICE} ",
"currencyCode": "{CURRENCY_CODE} "
},
"shipping": [
{
"price": {
"amountMicros": "{SHIPPING_COST} ",
"currencyCode": "{CURRENCY_CODE} "
},
"country": "{SHIPPING_COUNTRY} ",
"region": "{SHIPPING_REGION} ",
"postalCode": "{SHIPPING_POSTALCODE} ",
"minHandlingTime": "{MIN_HANDLING_TIME} ",
"maxHandlingTime": "{MAX_HANDLING_TIME} ",
"minTransitTime": "{MIN_TRANSIT_TIME} ",
"maxTransitTime": "{MAX_TRANSIT_TIME} "
}
],
"productWeight": {
"value": 320,
"unit": "g"
}
},
"customAttributes": [
{
"name": "Size",
"value": "Large"
},
{
"name": "Date of Manufacturing",
"value": "2024-05-05"
}
]
}
To add a product to your Merchant Center account, you can use the
google.shopping.merchant.accounts.v1beta.InsertProductInputSample
method, as shown in the following sample.
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.products.v1beta.Attributes;
import com.google.shopping.merchant.products.v1beta.InsertProductInputRequest;
import com.google.shopping.merchant.products.v1beta.ProductInput;
import com.google.shopping.merchant.products.v1beta.ProductInputsServiceClient;
import com.google.shopping.merchant.products.v1beta.ProductInputsServiceSettings;
import com.google.shopping.merchant.products.v1beta.Shipping;
import com.google.shopping.type.Channel.ChannelEnum;
import com.google.shopping.type.Price;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;
/** This class demonstrates how to insert a product input */
public class InsertProductInputSample {
private static String getParent(String accountId) {
return String.format("accounts/%s", accountId);
}
public static void insertProductInput(Config config, String dataSource) 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 parent to identify where to insert the product.
String parent = getParent(config.getAccountId().toString());
// Calls the API and catches and prints any network failures/errors.
try (ProductInputsServiceClient productInputsServiceClient =
ProductInputsServiceClient.create(productInputsServiceSettings)) {
// Price to be used for shipping ($33.45).
Price price = Price.newBuilder().setAmountMicros(33_450_000).setCurrencyCode("USD").build();
Shipping shipping =
Shipping.newBuilder()
.setPrice(price)
.setCountry("GB")
.setService("1st class post")
.build();
Shipping shipping2 =
Shipping.newBuilder()
.setPrice(price)
.setCountry("FR")
.setService("1st class post")
.build();
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")
.setGoogleProductCategory("Media > Books")
.setGtin(0, "9780007350896")
.addShipping(shipping)
.addShipping(shipping2)
.build();
// The datasource can be either a primary or supplemental datasource.
InsertProductInputRequest request =
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()
.setChannel(ChannelEnum.ONLINE)
.setContentLanguage("en")
.setFeedLabel("label")
.setOfferId("sku123")
.setAttributes(attributes)
.build())
.build();
System.out.println("Sending insert ProductInput request");
ProductInput response = 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 `channel~contentLanguage~feedLabel~offerId`
System.out.println(response.getName());
System.out.println("Inserted Product Name below");
System.out.println(response.getProduct());
} catch (Exception e) {
System.out.println(e);
}
}
public static void main(String[] args) throws Exception {
Config config = Config.load();
// Identifies the data source that will own the product input.
String dataSource = "accounts/" + config.getAccountId() + "/dataSources/{INSERT_DATASOURCE_ID}";
insertProductInput(config, dataSource);
}
}
Retrieve a processed product from your account
To retrieve a processed product from your account, use the
accounts.products.get
method. It can take several minutes for
the processed product to appear after insertion.
GET https://merchantapi.googleapis.com/products/v1beta/accounts/{ACCOUNT_ID} /products/{PRODUCT_NAME}
Replace {PRODUCT_NAME} with the name of the product
input resource you want to delete. For example, online~en~US~sku123
.
You can get the resource name of the processed product from the product
field
in the
response of accounts.productInputs.insert
.
To retrieve a single product for a given Merchant Center account, you can use the
google.shopping.merchant.accounts.v1beta.GetProductRequest
method, as shown in the following sample.
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.products.v1beta.GetProductRequest;
import com.google.shopping.merchant.products.v1beta.Product;
import com.google.shopping.merchant.products.v1beta.ProductsServiceClient;
import com.google.shopping.merchant.products.v1beta.ProductsServiceSettings;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;
/** This class demonstrates how to get a single product for a given Merchant Center account */
public class GetProductSample {
public static void getProduct(Config config, String product) throws Exception {
// Obtains OAuth token based on the user's configuration.
GoogleCredentials credential = new Authenticator().authenticate();
// Creates service settings using the credentials retrieved above.
ProductsServiceSettings productsServiceSettings =
ProductsServiceSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credential))
.build();
// Calls the API and catches and prints any network failures/errors.
try (ProductsServiceClient productsServiceClient =
ProductsServiceClient.create(productsServiceSettings)) {
// The name has the format: accounts/{account}/products/{productId}
GetProductRequest request = GetProductRequest.newBuilder().setName(product).build();
System.out.println("Sending get product request:");
Product response = productsServiceClient.getProduct(request);
System.out.println("Retrieved 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();
// 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.
String product = "accounts/{datasource}/products/{productId}";
getProduct(config, product);
}
}
Delete a product input from your account
To delete a product input from your account, use the
accounts.productInputs.delete
method. You must pass the
unique identifier of the primary or supplemental data source that the product
belongs to for deleting a product using the Merchant Products API.
The following request shows how you can use the accounts.productInputs.delete
method to delete a product input:
DELETE https://merchantapi.googleapis.com/products/v1beta/accounts/{ACCOUNT_ID} /productInputs/{PRODUCT_NAME} ?dataSource=accounts/{ACCOUNT_ID} /dataSources/{DATASOURCE_ID}
Replace {PRODUCT_NAME} with the name of the product
input resource you want to delete. For example, online~en~US~sku123
.
To delete a product for a given Merchant Center account, you can use the
google.shopping.merchant.accounts.v1beta.DeleteProductInputRequest
method, as shown in the following sample.
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.products.v1beta.DeleteProductInputRequest;
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 shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;
/** This class demonstrates how to delete a product for a given Merchant Center account */
public class DeleteProductInputSample {
public static void deleteProductInput(Config config, String productId, String dataSource)
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();
// Calls the API and catches and prints any network failures/errors.
try (ProductInputsServiceClient productInputsServiceClient =
ProductInputsServiceClient.create(productInputsServiceSettings)) {
DeleteProductInputRequest request =
DeleteProductInputRequest.newBuilder().setName(name).setDataSource(dataSource).build();
System.out.println("Sending deleteProductInput request");
productInputsServiceClient.deleteProductInput(request); // no response returned on success
System.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 (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";
// 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.
String dataSource = "accounts/{account}/dataSources/{dataSource}";
deleteProductInput(config, productId, dataSource);
}
}
List products from your account
To list the processed products in your account, use the accounts.products.list
method, as shown in the following request.
GET https://merchantapi.googleapis.com/products/v1beta/accounts/{ACCOUNT_ID} /products
To list a product for a given Merchant Center account, you can use the
google.shopping.merchant.accounts.v1beta.ListProductsRequest
method, as shown in the following sample.
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.products.v1beta.ListProductsRequest;
import com.google.shopping.merchant.products.v1beta.Product;
import com.google.shopping.merchant.products.v1beta.ProductsServiceClient;
import com.google.shopping.merchant.products.v1beta.ProductsServiceClient.ListProductsPagedResponse;
import com.google.shopping.merchant.products.v1beta.ProductsServiceSettings;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;
/** This class demonstrates how to list all the products for a given merchant center account */
public class ListProductsSample {
private static String getParent(String accountId) {
return String.format("accounts/%s", accountId);
}
public static void listProducts(Config config) throws Exception {
// Obtains OAuth token based on the user's configuration.
GoogleCredentials credential = new Authenticator().authenticate();
// Creates service settings using the credentials retrieved above.
ProductsServiceSettings productsServiceSettings =
ProductsServiceSettings.newBuilder()
.setCredentialsProvider(FixedCredentialsProvider.create(credential))
.build();
// Creates parent to identify the account from which to list all products.
String parent = getParent(config.getAccountId().toString());
// Calls the API and catches and prints any network failures/errors.
try (ProductsServiceClient productsServiceClient =
ProductsServiceClient.create(productsServiceSettings)) {
// The parent has the format: accounts/{account}
ListProductsRequest request = ListProductsRequest.newBuilder().setParent(parent).build();
System.out.println("Sending list products request:");
ListProductsPagedResponse response = productsServiceClient.listProducts(request);
int count = 0;
// Iterates over all rows in all pages and prints the datasource in each row.
// Automatically uses the `nextPageToken` if returned to fetch all pages of data.
for (Product product : response.iterateAll()) {
System.out.println(product); // The product includes the `productStatus` field
// That shows approval and disapproval information.
count++;
}
System.out.print("The following count of products were returned: ");
System.out.println(count);
} catch (Exception e) {
System.out.println("An error has occured: ");
System.out.println(e);
}
}
public static void main(String[] args) throws Exception {
Config config = Config.load();
listProducts(config);
}
}