Products
하위 API를 사용하면 판매자 센터에서 제품의 전체 수명 주기를 관리할 수 있습니다. 이 도구를 사용하면 새 제품을 업로드하고, 기존 제품을 업데이트하고, 제품 정보를 검색하고, 더 이상 판매하지 않는 제품을 삭제할 수 있습니다.
특별 고려사항
- 제품은 유형이
API
인 데이터 소스에 속하는 경우에만 삽입,업데이트 또는 삭제할 수 있습니다. 파일 기반 업로드를 사용하는 데이터 소스 내에서는 제품을 삽입하거나 업데이트할 수 없습니다. - 제품의 관련성을 유지하고 만료를 방지하려면 정기적으로 (최소 30일마다) 제품을 업데이트하거나 새로고침해야 합니다.
기본 요건
API를 사용하여 제품을 추가하거나 관리하려면 판매자 센터 계정에 하나 이상의 데이터 소스가 구성되어 있어야 합니다.
데이터 소스를 만들려면 데이터 소스 하위 API의 dataSources.create
메서드를 사용합니다. 자세한 안내는 제품 업로드를 위한 API 데이터 소스 관리 가이드를 참고하세요. 데이터 소스를 만든 후 제품 관련 생성, 업데이트 또는 삭제 요청에 필요하므로 name
(예: accounts/12345/dataSources/67890
)를 기록해 둡니다.
제품 추가
판매자 센터 계정에 새 제품을 추가하려면 기본 데이터 소스에 ProductInput
리소스를 삽입해야 합니다. 이 작업은 제품을 만들고 처리를 시작합니다. productAttributes
객체 내의 필드는 제품 데이터 사양을 준수해야 합니다.
productInputs.insert
메서드를 사용하고 기본 데이터 소스의 name
을 dataSource
매개변수로 제공합니다.
이 예에서는 온라인 상점의 새 제품을 기본 데이터 소스에 삽입합니다.
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"]
}
}
호출이 성공하면 새로 생성된 ProductInput
리소스가 반환됩니다. name
필드에는 이 제품 입력의 고유 식별자가 포함되고 product
필드에는 나중에 검색하는 데 사용할 수 있는 최종 처리된 제품의 이름이 포함됩니다.
{
"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"
]
}
}
다음 코드 샘플은 제품을 추가하는 방법을 보여줍니다.
자바
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.products.v1.Availability;
import com.google.shopping.merchant.products.v1.Condition;
import com.google.shopping.merchant.products.v1.InsertProductInputRequest;
import com.google.shopping.merchant.products.v1.ProductAttributes;
import com.google.shopping.merchant.products.v1.ProductInput;
import com.google.shopping.merchant.products.v1.ProductInputsServiceClient;
import com.google.shopping.merchant.products.v1.ProductInputsServiceSettings;
import com.google.shopping.merchant.products.v1.Shipping;
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();
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)
.setGoogleProductCategory("Media > Books")
.addGtins("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()
.setContentLanguage("en")
.setFeedLabel("label")
.setOfferId("sku123")
.setProductAttributes(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 `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);
}
}
PHP
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();
Python
from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.shopping import merchant_products_v1
from google.shopping.merchant_products_v1 import Availability
from google.shopping.merchant_products_v1 import Condition
from google.shopping.type import Price
_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}"
def create_product_input():
"""Creates a `ProductInput` resource."""
# Creates a shipping setting
price = Price()
price.amount_micros = 33_450_000
price.currency_code = "GBP"
shipping_option_1 = merchant_products_v1.Shipping()
shipping_option_1.price = price
shipping_option_1.country = "GB"
shipping_option_1.service = "1st class post"
price2 = Price()
price2.amount_micros = 33_450_000
price2.currency_code = "EUR"
shipping_option_2 = merchant_products_v1.Shipping()
shipping_option_2.price = price2
shipping_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 = price
attributes.availability = Availability.IN_STOCK
attributes.condition = Condition.NEW
attributes.google_product_category = "Media > Books"
attributes.gtins = ["9780007350896"]
attributes.shipping = [shipping_option_1, shipping_option_2]
return merchant_products_v1.ProductInput(
content_language="en",
feed_label="GB",
offer_id="sku123",
product_attributes=attributes,
)
def insert_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}")
except RuntimeError as e:
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()
Apps_Script
/**
* Inserts a product into the products list. Logs the API response.
*/
function productInsert() {
// IMPORTANT:
// Enable the Merchant API Products sub-API Advanced Service and call it
// "MerchantApiProducts"
// Replace this with your Merchant Center ID.
const accountId = 'INSERT_MERCHANT_ID';
// Replace this with the Data Source ID you want to use.
const dataSourceId = 'INSERT_DATASOURCE_ID';
// Construct the parent name
const parent = 'accounts/' + accountId;
// Construct the Data Source name
const dataSource = parent + '/dataSources/' + dataSourceId;
// Create a product resource and insert it
const productResource = {
'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');
// Call the ProductInputs.insert API method.
response = MerchantApiProducts.Accounts.ProductInputs.insert(
productResource, parent, {dataSource});
// RESTful insert returns the JSON object as a response.
console.log('Inserted ProductInput below');
console.log(response);
} catch (e) {
console.log('ERROR!');
console.log(e);
}
}
cURL
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"]
}
}'
보조 데이터 소스를 사용하여 제품 정보 추가 또는 업데이트
보조 데이터 소스를 사용하여 기본 데이터 소스에 이미 있는 제품에 대한 추가 데이터 또는 재정의 데이터를 제공합니다. 이는 원래 제품 입력을 수정하지 않고 프로모션, 맞춤 라벨과 같은 정보를 추가하거나 특정 제품 데이터를 재정의하는 데 유용합니다.
이렇게 하려면 productInputs.insert
메서드를 사용하되 dataSource
매개변수에 보조 데이터 소스의 name
를 지정합니다. offerId
, contentLanguage
, feedLabel
이 기존 제품과 일치하는지 확인합니다.
이 예에서는 보조 데이터 소스를 사용하여 기존 제품에 맞춤 라벨을 추가합니다.
POST https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{SUPPLEMENTAL_DATASOURCE_ID}
{
"offerId": "SKU12345",
"contentLanguage": "en",
"feedLabel": "US",
"productAttributes": {
"customLabel0": "clearance-sale"
}
}
이 호출 후 최종 Product
에는 customLabel0
이 clearance-sale
로 설정됩니다. 이는 보조 데이터 소스가 default_rule
에 의해 정의된 피드 규칙에서 기본 데이터 소스보다 우선순위가 높다고 가정하기 때문입니다.
비동기식으로 제품 추가
많은 수의 제품을 효율적으로 업로드하려면 여러 삽입 요청을 동시에 보내면 됩니다. 각 요청에 대한 응답을 기다린 후 다음 요청을 보내는 대신 비동기식으로 요청을 보내고 응답이 도착하면 처리할 수 있습니다. 이 방법을 사용하면 데이터 업로드 처리량을 크게 개선할 수 있습니다.
다음 코드 샘플은 비동기적으로 제품을 삽입하는 방법을 보여줍니다. curl
를 사용하여 한 번에 여러 요청을 실행하는 방법을 알아보려면 한 번에 여러 요청 보내기를 참고하세요.
자바
import com.google.api.core.ApiFuture;
import com.google.api.core.ApiFutureCallback;
import com.google.api.core.ApiFutures;
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.util.concurrent.MoreExecutors;
import com.google.shopping.merchant.products.v1.Availability;
import com.google.shopping.merchant.products.v1.Condition;
import com.google.shopping.merchant.products.v1.InsertProductInputRequest;
import com.google.shopping.merchant.products.v1.ProductAttributes;
import com.google.shopping.merchant.products.v1.ProductInput;
import com.google.shopping.merchant.products.v1.ProductInputsServiceClient;
import com.google.shopping.merchant.products.v1.ProductInputsServiceSettings;
import com.google.shopping.merchant.products.v1.Shipping;
import com.google.shopping.type.Price;
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.stream.Collectors;
import shopping.merchant.samples.utils.Authenticator;
import shopping.merchant.samples.utils.Config;
/** This class demonstrates how to insert a product input */
public class InsertProductInputAsyncSample {
private static String getParent(String accountId) {
return String.format("accounts/%s", accountId);
}
private static String generateRandomString() {
String characters = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
Random random = new Random();
StringBuilder sb = new StringBuilder(8);
for (int i = 0; i < 8; i++) {
sb.append(characters.charAt(random.nextInt(characters.length())));
}
return sb.toString();
}
private static ProductInput createRandomProduct() {
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();
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)
.setGoogleProductCategory("Media > Books")
.addGtins("9780007350896")
.addShipping(shipping)
.addShipping(shipping2)
.build();
return ProductInput.newBuilder()
.setContentLanguage("en")
.setFeedLabel("CH")
.setOfferId(generateRandomString())
.setProductAttributes(attributes)
.build();
}
public static void asyncInsertProductInput(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)) {
// Creates five insert product input requests with random product IDs.
List<InsertProductInputRequest> requests = new ArrayList<>(5);
for (int i = 0; i < 5; i++) {
InsertProductInputRequest request =
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,
new ApiFutureCallback<List<ProductInput>>() {
@Override
public void onSuccess(List<ProductInput> results) {
System.out.println("Inserted products below");
System.out.println(results);
}
@Override
public void onFailure(Throwable throwable) {
System.out.println(throwable);
}
},
MoreExecutors.directExecutor());
} 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/{datasourceId}";
asyncInsertProductInput(config, dataSource);
}
}
Python
import asyncio
import functools
import random
import string
from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.shopping.merchant_products_v1 import Availability
from google.shopping.merchant_products_v1 import Condition
from google.shopping.merchant_products_v1 import InsertProductInputRequest
from google.shopping.merchant_products_v1 import ProductAttributes
from google.shopping.merchant_products_v1 import ProductInput
from google.shopping.merchant_products_v1 import ProductInputsServiceAsyncClient
from google.shopping.merchant_products_v1 import Shipping
from google.shopping.type import Price
# 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.digits
return "".join(random.choice(characters) for _ in range(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],
)
return ProductInput(
content_language="en",
feed_label="US",
offer_id=_generate_random_string(),
product_attributes=attributes,
)
def print_product_input(i, task):
print("Inserted ProductInput number: ", i)
# task.result() contains the response from async_insert_product_input
print(task.result())
async def async_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 = await client.insert_product_input(request=request)
# The response is an async corouting inserting the ProductInput.
return response
except RuntimeError as e:
# Catch and print any exceptions that occur during the API calls.
print(e)
async def main():
# 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 = []
for i in range(5):
product_input = _create_random_product()
request = InsertProductInputRequest(
parent=_PARENT,
data_source=data_source_name,
product_input=product_input,
)
# Create the async task
insert_product_task = asyncio.create_task(
async_insert_product_input(client, request)
)
# Add the callback
callback_function = functools.partial(print_product_input, i)
insert_product_task.add_done_callback(callback_function)
# Add the task to our list
tasks.append(insert_product_task)
# Await all tasks to complete concurrently
# The print_product_input callback will be called for each as it finishes
await asyncio.gather(*tasks)
if __name__ == "__main__":
asyncio.run(main())
특정 국가를 타겟팅하는 제품 추가
개별 제품의 국가 타겟팅을 설정하여 데이터 소스의 설정을 재정의하거나 데이터 소스에 정의된 국가가 없는 경우 제품을 타겟팅할 수 있습니다.
shipping
속성이 있는 대상 국가
데이터 소스에 특정 국가가 정의되어 있지 않은 경우 productAttributes
내에 shipping
필드를 제공하여 제품의 타겟팅 국가를 지정할 수 있습니다. 이 필드를 사용하면 여러 국가의 배송비와 규칙을 지정하여 게재를 위해 암시적으로 타겟팅할 수 있습니다.
이 예에서는 별도의 shipping
항목 두 개를 제공하여 미국과 캐나다를 대상으로 제품을 타겟팅합니다.
POST https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs:insert?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
{
"offerId": "SKU_SHIP_TARGET",
"contentLanguage": "en",
"feedLabel": "GLOBAL",
"productAttributes": {
"title": "Global T-Shirt",
"link": "https://www.example.com/p/SKU_SHIP_TARGET",
"imageLink": "https://www.example.com/img/SKU_SHIP_TARGET.jpg",
"availability": "IN_STOCK",
"price": {
"amountMicros": "25990000",
"currencyCode": "USD"
},
"shipping": [
{
"country": "US",
"price": {
"amountMicros": "5990000",
"currencyCode": "USD"
}
},
{
"country": "CA",
"price": {
"amountMicros": "10990000",
"currencyCode": "CAD"
}
}
]
}
}
국가 및 대상 유형 제외
데이터 소스가 이미 여러 국가를 타겟팅하는 경우 해당 국가의 일부 또는 특정 대상에서 제품이 표시되지 않도록 제외할 수 있습니다.
shoppingAdsExcludedCountries
속성을 사용하여 특정 국가의 쇼핑 광고에 제품이 표시되지 않도록 합니다.excludedDestinations
속성을 사용하여 제품이FreeListings
과 같은 특정 마케팅 방법 내에 표시되지 않도록 합니다.
이 예에서는 데이터 소스가 미국, 캐나다, 멕시코를 타겟팅한다고 가정합니다. 이 요청은 멕시코의 쇼핑 광고와 무료 등록정보 대상 유형에서 제품을 완전히 제외합니다.
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"]
}
}
제품 정보 가져오기
제품의 최종 처리된 상태를 가져오려면 products.get
메서드를 사용합니다. 이 메서드는 피드 규칙과 보조 데이터 소스가 적용된 후의 모든 productAttributes
와 현재 유효성 검사 상태를 포함하는 Product
리소스를 반환합니다.
ProductInput
를 삽입하거나 업데이트한 시점과 최종 Product
를 검색할 수 있는 시점 사이에 몇 분 정도 지연이 발생할 수 있습니다.
GET https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/products/en~US~SKU12345
요청에 성공하면 Product
리소스가 반환됩니다.
{
"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"
}
}
다음 코드 샘플은 제품을 가져오는 방법을 보여줍니다.
자바
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.products.v1.GetProductRequest;
import com.google.shopping.merchant.products.v1.Product;
import com.google.shopping.merchant.products.v1.ProductsServiceClient;
import com.google.shopping.merchant.products.v1.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);
}
}
PHP
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();
Python
from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.shopping import merchant_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}"
def get_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}")
except RuntimeError as e:
print("Get failed")
print(e)
if __name__ == "__main__":
get_product()
Apps_Script
/**
* Get a specific product for a given Merchant Center account.
*/
function getProduct() {
// IMPORTANT:
// Enable the Merchant API Products sub-API Advanced Service and call it
// "MerchantApiProducts"
// Replace this with your Merchant Center ID.
const accountId = '<MERCHANT_CENTER_ID>';
// The ID of the product to retrieve.
// 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.
const productId = '<PRODUCT_ID>';
// Construct the parent name
const parent = 'accounts/' + accountId;
// Construct the product resource name
const name = parent + "/products/" + productId;
try {
console.log('Sending get Product request');
// Call the Products.get API method.
product = MerchantApiProducts.Accounts.Products.get(name);
console.log(product);
} catch (e) {
console.log('ERROR!');
console.log(e);
}
}
cURL
curl -X GET \
"https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/products/en~US~SKU12345" \
-H "Authorization: Bearer <API_TOKEN>"
데이터 소스에서 제품 삭제하기
특정 데이터 소스에서 제품 입력을 삭제하려면 productInputs.delete
메서드를 사용합니다.
- 기본 데이터 소스에서 삭제하면 보조
ProductInputs
를 포함한 전체 제품이 판매자 센터에서 삭제됩니다. - 보조 데이터 소스에서 삭제하면 해당 데이터 소스의 속성만 제품에서 삭제됩니다. 제품 자체는 기본 데이터 소스 및 기타 보조 데이터 소스에서 가져온 상태로 유지됩니다.
제품 입력을 삭제할 dataSource
를 지정해야 합니다.
DELETE https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}
호출이 성공하면 빈 응답이 반환됩니다.
다음 코드 샘플은 제품을 삭제하는 방법을 보여줍니다.
자바
import com.google.api.gax.core.FixedCredentialsProvider;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.shopping.merchant.products.v1.DeleteProductInputRequest;
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 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
// 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);
}
}
PHP
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();
Python
from examples.authentication import configuration
from examples.authentication import generate_user_credentials
from google.shopping import merchant_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}"
def delete_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")
except RuntimeError as e:
print("Deletion failed")
print(e)
if __name__ == "__main__":
delete_product_input()
cURL
curl -X DELETE \
"https://merchantapi.googleapis.com/products/v1/accounts/{ACCOUNT_ID}/productInputs/en~US~SKU12345?dataSource=accounts/{ACCOUNT_ID}/dataSources/{DATASOURCE_ID}" \
-H "Authorization: Bearer <API_TOKEN>"