本指南介绍了从 Content API for Shopping 迁移到 Merchant API 以进行商家数据管理的过程。
您可以按照本指南将现有的 Content API for Shopping 实现迁移到 Merchant API。如需详细了解 Merchant API 及其子 API 的详细信息,请参阅 Merchant API 设计。
开始使用
如需开始使用 Merchant API,请将请求网址更改为以下格式:
https://merchantapi.googleapis.com/{SUB_API}/{VERSION}/{RESOURCE_NAME}:{METHOD}…
如需使用 Merchant API,您必须使用开发者注册方法关联您的 Merchant Center 账号和 Google Cloud 项目,具体操作如下:
POST https://merchantapi.googleapis.com/accounts/v1beta/accounts/{ACCOUNT_ID}/developerRegistration:registerGcp
{
developer_email:"example-email@example.com"
}
如需了解详情,请参阅快速入门指南和 Merchant API 参考文档。
请参阅 Merchant API(Beta 版)中的最新更新。
相对于 Content API for Shopping 的改进
借助 Merchant API,您可以自动执行并简化 Merchant Center 中的工作流程,并且与 Content API for Shopping 相比,它还提供增强的功能。
关键应用场景:
- 自动账号管理
- 自动化产品管理
- 自动化的产品目录管理系统
- 自定义报告
主要改进方面:
- 具有新功能的子 API,包括:
- 订单跟踪 支持商家订单跟踪历史记录,以便向客户提供精确的配送时间预估。其信号还支持免费快捷送货的增强型商品详情。
- 问题解决功能可让您以与 Merchant Center 界面中相同的方式访问诊断内容和支持操作。
- Product Studio(Alpha 版)利用生成式 AI 来生成和优化商品名及说明。 您需要签署此表单才能申请访问权限。
- 账号子 API 中的新资源。
OmnichannelSettings
管理全渠道投放的账号配置,例如非付费本地商品详情 (FLL) 和本地商品目录广告 (LIA)。LfpProviders
会连接到本地 Feed 合作伙伴计划 (LFP) 合作伙伴以获取商品目录数据。GbpAccounts
用于连接到 Google 商家资料账号,以获取本地实体店数据。OnlineReturnPolicy
可让您创建、删除和更新在线政策。
- 针对商品目录、商品数据和其他 API 的新方法,包括:
- Products 子 API 中的新方法。
- 借助
ProductsUpdate
,您可以更新单个商品,而无需提供ProductInput
所需的所有字段。
- 能够创建不仅是主要数据源,还有多种数据源,例如:
- 引入了商品评价和商家评价的上传功能
- 借助 Merchant API,您可以针对账号数据更改启用通知
具体变化:
- 每次 API 调用的
pageSize
上限从 250 行增加到 1,000 行。 - 修复了在创建
DataSources
后,商品插入、促销活动、商品评价和商家评价方面存在的延迟问题。
即将推出的功能:
- 弃用并将在未来移除
DataSources
和产品的渠道字段。 - 在报告子 API 下的
productView
表中,针对clickPotentialRank
推出了更新后的定义: * 基于clickPotential
的商品排名已归一化为介于 1 到 1000 之间的值。clickPotentialRank
较低的商品在满足搜索查询条件的商家商品中仍具有最高的点击潜力。这是一项非破坏性变更,可能会于 2025 年 7 月 1 日推出。
AccountRelationship
资源中的AccountIdAlias
可用于更好地管理复杂的账号结构。例如,购物平台会使用用户定义的别名,而不是商家的内部 ID(例如账号 ID)。
gRPC 支持
Merchant API 支持 gRPC 和 REST。您可以同时使用 gRPC(用于 Merchant API)和 REST(用于 Content API for Shopping)。
Merchant API 客户端库需要 gRPC。
如需了解详情,请参阅 gRPC 概览。
兼容性
本指南介绍了适用于整个 Merchant API 的一般性变更。
Merchant API 旨在与现有的 Content API for Shopping 功能协同运作。
例如,您可以将 Merchant Inventories API 与现有的 Content API for Shopping v2.1 products
实现搭配使用。您可以使用 Content API for Shopping 上传新的本地商品(您在实体店中销售的商品),然后使用 Merchant Inventories API LocalInventory
资源来管理该商品的实体店信息。
相对于 Content API 的改进
Merchant API 在以下方面优于 Content API:
- 具有新功能的子 API,可实现独特的集成
- 针对商品目录、商品数据和其他 API 的新方法
- 不仅可以创建主要数据源,还可以创建多个数据源,例如:
- 引入了商品评价和商家评价的上传功能
- 借助 Merchant API,您可以针对账号数据更改启用通知。
- 为 Accounts 资源引入了过滤功能
我们来更详细地了解一下这些变化。
版本控制和子 API
Merchant API 引入了版本控制和子 API 的概念。其模块化设计可让您专注于所需子 API,并更轻松地将未来迁移到新版本,从而提高易用性。版本控制将应用于您的请求网址。此策略与 Google Ads API 体验类似。
更强大的请求
Merchant API 网址请求需要更多参数才能调用 Merchant API。这包括资源、版本、名称(标识符)和方法(非标准方法)。如需详细了解此方面的信息,请参阅账号和产品标识符和示例。
标识符的 AIP 原则
虽然 Content API for Shopping 使用 ID 来标识资源(例如 merchantId
、productId
),但 Merchant API 使用 name
标识符来与 AIP 保持一致(请参阅 API 改进原则)。
{name}
标识符包含资源标识符及其父级(或可能包含多个父级),因此 {name}
等于 accounts/{account}/products/{product}
所有读取和写入调用都会返回 name
字段作为资源标识符。
{name}
还包括核销标识符 accounts/
和 products/
。
Merchant API 使用 {account}
来指代 Merchant Center ID,并使用 {product}
来指代商品标识码。
例如,实现一种 getName()
方法,用于从资源中检索 name
,并将输出存储为变量,而不是自行从商家和资源 ID 构建 name
。
以下示例展示了如何在调用中使用 name
字段:
POST https://merchantapi.googleapis.com/inventories/v1beta/{PARENT}/regionalInventories:insert
下表显示了 Content API for Shopping products.get
请求的变化:
Content API for Shopping | Merchant API |
---|---|
GET https://shoppingcontent.googleapis.com/content/v2.1/{merchantId}/products/{productId}
|
GET https://merchantapi.googleapis.com/products/v1beta/{name}
|
如需了解详情,请参阅标识符变更。
再举一个例子,使用 Merchant API 从 Merchant Center ID 4321
中检索标识符为 online~en~US~1234
的商品,如下所示:
GET
https://merchantapi.googleapis.com/products/v1beta/accounts/4321/products/online~en~US~1234
其中 {name}
等于 accounts/4321/products/online~en~US~1234
。此新名称字段会作为 Merchant API 中所有读取和写入调用的资源标识符返回。
在 Content API for Shopping 中,英文冒号 (:) 表示商品名称中的分隔符,而在 Merchant API 中,英文波浪号 (~) 执行此功能。
例如,Content API for Shopping 中的商品 ID:
channel:contentLanguage:feedLabel:offerId
。
在 Merchant Center API 中,以下内容:
channel~contentLanguage~feedLabel~offerId
。
子资源的父字段
在 Merchant API 中,所有子资源都具有 parent
字段。您可以使用 parent
字段指定要将子资源插入到的资源的 {name}
,而不是传递整个父资源。您还可以将 parent
字段与 list
搭配使用
例如,如需列出指定商品的实体店商品目录,请在 list
方法的 parent
字段中指定商品的 name
。在这种情况下,指定的 product
是返回的 LocalInventory 资源的 parent
。
GET
https://merchantapi.googleapis.com/inventories/v1beta/{parent}/localInventories
如需检索商品 online~en~US~1234'
和账号 4321
的所有本地商品目录,请求应如下所示
GET
https://merchantapi.googleapis.com/inventories/v1beta/accounts/4321/products/online~en~US~1234/localInventories</code>
父项为 accounts/{account}/products/{product}
。请注意,在这种情况下,localInventories 资源在名称标识符中包含两个父级(accounts/
和 products/
),因为账号是商品资源的父级。
常见枚举
使用通用枚举可提高一致性。
Destination.DestinationEnum
字段用于指定要显示资源的途径。
DestinationEnum
列出了目的地定位的所有可用值,并在各个子 API(例如促销信息属性)中保持统一。
ReportingContext.ReportingContextEnum
字段表示账号和商品问题所适用的情境。
此字段可用于各种报告方法(例如 IssueSeverityPerReportingContext
)。
向后兼容性
开始使用 Merchant API 后,您现有的 Content API for Shopping 集成功能将继续正常运行,不会中断。如需了解详情,请参阅兼容性。
将子 API 迁移到 Merchant API 后,我们建议您仅使用 Merchant API 来处理已迁移的子 API。
远程过程调用 (gRPC) 的可用性
gRPC 是目前推荐的与 Merchant API 集成的方式。
其优势包括:
- 与语言无关
- 依赖于 Protocol Buffers
使用 HTTP/2 提供高性能的可扩缩解决方案(RPC 参考)
如果您使用我们的客户端库或代码示例,gRPC 是默认的传输机制。
如需详细了解 gRPC,请参阅以下内容:
自定义批处理变为内置批处理
使用异步调用时,批处理的执行效率更高。详细了解如何在 Merchant API 中使用并行调用来实现批处理,以及如何重构代码以实现并发请求。
为帮助您加快迁移速度,我们建议您使用客户端库。
Merchant API 不支持 Content API for Shopping 中提供的 customBatch
方法。请改为参阅一次性发送多个请求或以异步方式执行调用。
以下 Java 示例演示了如何插入商品输入。
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.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 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();
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")
.addGtin("9780007350896")
.addShipping(shipping)
.addShipping(shipping2)
.build();
return ProductInput.newBuilder()
.setChannel(ChannelEnum.ONLINE)
.setContentLanguage("en")
.setFeedLabel("CH")
.setOfferId(generateRandomString())
.setAttributes(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);
}
}
如果您在 Content API 中使用 customBatch
,并且需要 Merchant API 提供此功能,请在反馈中告知我们原因。
专有功能
未来的功能将仅在 Merchant API 中提供。(但也有一些例外情况,例如 2025 年的 Feed 规范。)
Merchant API 独有的功能包括
价格
以下是 Merchant Common 软件包中针对 Price
所做的更改:
Content API for Shopping | Merchant API | |
---|---|---|
金额字段 | value:string |
amountMicros:int64 |
币种字段 | currency:string
|
currencyCode:string |
Price
金额现在以微单位记录,100 万微单位相当于您所用币种的标准单位。
在 Content API for Shopping 中,Price
是字符串形式的十进制数。
金额字段名称已从 value
更改为 amountMicros
币种字段名称已从 currency
更改为 currencyCode
。格式仍为 ISO 4217。
最新动态和公告
如需了解更精细的更新,请参阅每个子 API 的特定版本说明。如需了解更常规的 Merchant API 汇总更新,请查看我们的最新更新。
如需了解更具体的信息,并详细了解 Merchant API,请访问我们的开发者网站,查看概览和总体迁移指南,了解更多详情。
如需详细了解 Merchant API 及其子 API,请参阅 Merchant API 设计。