亚马逊SP-API Listing刊登重大更新:从XML到JSON的转型之路 - 2025年07月31日商品刊登Feed类型变更详解
前言
如果你在7月31日收到了亚马逊的这封邮件,那么恭喜你,你正式进入了SP-API的新时代:
"You are receiving this email as a notification to inform you that the following XML and Flat File Listings Feeds type values and operations have been successfully removed today,7/31/2025..."
没错,那些陪伴我们多年的XML Feed终于寿终正寝了。作为一个跟亚马逊API打了快10年交道的老兵,说不感慨是假的。但技术总要向前看,今天就来聊聊这次变革对我们开发者意味着什么。
一、被移除的Feed类型清单
先看看哪些老朋友离我们而去了:
POST_PRODUCT_DATA- 商品数据上传POST_INVENTORY_AVAILABILITY_DATA- 库存更新POST_PRODUCT_OVERRIDES_DATA- 商品覆盖数据POST_PRODUCT_PRICING_DATA- 价格数据POST_PRODUCT_IMAGE_DATA- 图片数据POST_PRODUCT_RELATIONSHIP_DATA- 商品关系数据(变体关系等)POST_FLAT_FILE_INVLOADER_DATA- 库存加载器POST_FLAT_FILE_LISTINGS_DATA- 商品刊登数据POST_FLAT_FILE_PRICEANDQUANTITYONLY_UPDATE_DATA- 价格和数量更新
从今天开始,调用这些API都会返回失败。如果你的系统还在用这些接口,那真的要抓紧时间改造了。
二、为什么要从XML转向JSON?
2.1 技术层面的考虑
说实话,XML虽然结构严谨,但在现代Web开发中确实显得有些笨重:
<!-- 以前的XML方式 -->
<Message>
<MessageID>1</MessageID>
<OperationType>Update</OperationType>
<Product>
<SKU>ABC-123</SKU>
<StandardProductID>
<Type>ASIN</Type>
<Value>B00EXAMPLE</Value>
</StandardProductID>
<Quantity>100</Quantity>
</Product>
</Message>
相比之下,JSON就简洁多了:
{
"sku": "ABC-123",
"product_id": {
"type": "ASIN",
"value": "B00EXAMPLE"
},
"quantity": 100
}
2.2 开发效率的提升
- 数据量更小:JSON格式比XML平均减少30-40%的数据传输量
- 解析更快:现代编程语言对JSON的支持都是原生的
- 调试更方便:JSON的可读性明显优于XML
- Schema验证更灵活:JSON Schema的表达能力不输XSD,但更容易理解
三、新的实现方式详解
3.1 单个商品操作:使用putListingsItem
对于单个商品的创建或更新,现在推荐使用Listings Items API。可以在putListingsItem接口文档查看详细说明。
PHP示例代码:
<?php
// 创建或完全更新一个listing
function createOrUpdateListing($sellerId, $sku, $productData) {
$client = new \GuzzleHttp\Client();
$requestBody = [
'productType' => 'SHIRT',
'attributes' => [
'title' => [
['value' => 'Amazing Cotton T-Shirt']
],
'description' => [
['value' => 'High quality 100% cotton t-shirt']
],
'bullet_points' => [
['value' => ['Comfortable fit', 'Machine washable', 'Available in multiple colors']]
],
'brand' => [
['value' => 'YourBrand']
],
// 库存和价格信息
'fulfillment_availability' => [
[
'fulfillment_channel_code' => 'DEFAULT',
'quantity' => 100
]
],
'purchasable_offer' => [
[
'currency' => 'USD',
'marketplace_id' => 'ATVPDKIKX0DER',
'our_price' => [
[
'schedule' => [
['value_with_tax' => 19.99]
]
]
]
]
]
]
];
$response = $client->request('PUT',
"https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items/{$sellerId}/{$sku}",
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken(),
'Content-Type' => 'application/json',
'x-amz-access-token' => getAccessToken()
],
'json' => $requestBody
]
);
return json_decode($response->getBody(), true);
}
Postman示例:
// PUT https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items/{{sellerId}}/{{sku}}
// Headers:
// Authorization: Bearer {{access_token}}
// Content-Type: application/json
// x-amz-access-token: {{access_token}}
{
"productType": "SHIRT",
"attributes": {
"title": [
{
"value": "Amazing Cotton T-Shirt"
}
],
"description": [
{
"value": "High quality 100% cotton t-shirt"
}
],
"fulfillment_availability": [
{
"fulfillment_channel_code": "DEFAULT",
"quantity": 100
}
]
}
}
3.2 批量操作:JSON_LISTINGS_FEED
当需要处理大量商品时(比如每天要更新几千个SKU的库存),使用Feed API会更高效。相关接口可以在createFeed文档和createFeedDocument文档查看。
PHP批量更新示例:
<?php
// 步骤1: 创建Feed文档
function createFeedDocument() {
$client = new \GuzzleHttp\Client();
$response = $client->request('POST',
'https://sellingpartnerapi-na.amazon.com/feeds/2021-06-30/documents',
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken(),
'Content-Type' => 'application/json'
],
'json' => [
'contentType' => 'application/json'
]
]
);
return json_decode($response->getBody(), true);
}
// 步骤2: 上传Feed内容
function uploadFeedContent($url, $feedContent) {
$client = new \GuzzleHttp\Client();
$feedData = [
'header' => [
'sellerId' => 'YOUR_SELLER_ID',
'version' => '2.0',
'feedId' => time(),
'report' => [
'includedData' => ['issues', 'status'],
'apiVersion' => '2021-08-01'
]
],
'messages' => [
[
'messageId' => 1,
'sku' => 'SKU-001',
'operationType' => 'UPDATE',
'productType' => 'PRODUCT',
'attributes' => [
'fulfillment_availability' => [
[
'fulfillment_channel_code' => 'DEFAULT',
'quantity' => 50
]
]
]
],
[
'messageId' => 2,
'sku' => 'SKU-002',
'operationType' => 'UPDATE',
'productType' => 'PRODUCT',
'attributes' => [
'fulfillment_availability' => [
[
'fulfillment_channel_code' => 'DEFAULT',
'quantity' => 75
]
]
]
]
]
];
$response = $client->request('PUT', $url, [
'body' => json_encode($feedData),
'headers' => [
'Content-Type' => 'application/json'
]
]);
return $response->getStatusCode() === 200;
}
// 步骤3: 创建Feed
function createFeed($feedDocumentId) {
$client = new \GuzzleHttp\Client();
$response = $client->request('POST',
'https://sellingpartnerapi-na.amazon.com/feeds/2021-06-30/feeds',
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken(),
'Content-Type' => 'application/json'
],
'json' => [
'feedType' => 'JSON_LISTINGS_FEED',
'marketplaceIds' => ['ATVPDKIKX0DER'],
'inputFeedDocumentId' => $feedDocumentId
]
]
);
return json_decode($response->getBody(), true);
}
3.3 查询商品信息
使用getListingsItem接口可以获取商品的详细信息:
PHP示例:
<?php
function getListingDetails($sellerId, $sku) {
$client = new \GuzzleHttp\Client();
$response = $client->request('GET',
"https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items/{$sellerId}/{$sku}",
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken(),
'x-amz-access-token' => getAccessToken()
],
'query' => [
'marketplaceIds' => 'ATVPDKIKX0DER',
'includedData' => 'attributes,issues,offers,fulfillmentAvailability'
]
]
);
return json_decode($response->getBody(), true);
}
Postman示例:
GET https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items/{{sellerId}}/{{sku}}?marketplaceIds=ATVPDKIKX0DER&includedData=attributes,issues
Headers:
Authorization: Bearer {{access_token}}
x-amz-access-token: {{access_token}}
3.4 部分更新商品
使用patchListingsItem接口可以只更新需要修改的字段:
PHP示例:
<?php
// 只更新库存数量
function updateInventoryOnly($sellerId, $sku, $quantity) {
$client = new \GuzzleHttp\Client();
$patchData = [
'productType' => 'PRODUCT',
'patches' => [
[
'op' => 'replace',
'path' => '/attributes/fulfillment_availability',
'value' => [
[
'fulfillment_channel_code' => 'DEFAULT',
'quantity' => $quantity
]
]
]
]
];
$response = $client->request('PATCH',
"https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/items/{$sellerId}/{$sku}",
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken(),
'Content-Type' => 'application/json'
],
'json' => $patchData
]
);
return json_decode($response->getBody(), true);
}
四、从XSD到JSON Schema的转变
4.1 获取产品类型定义
使用Product Type Definitions API获取商品类型的JSON Schema:
<?php
function getProductTypeSchema($productType = 'SHIRT') {
$client = new \GuzzleHttp\Client();
$response = $client->request('GET',
"https://sellingpartnerapi-na.amazon.com/definitions/2020-09-01/productTypes/{$productType}",
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken()
],
'query' => [
'marketplaceIds' => 'ATVPDKIKX0DER',
'requirements' => 'LISTING' // 或 'LISTING_PRODUCT_ONLY', 'LISTING_OFFER_ONLY'
]
]
);
$result = json_decode($response->getBody(), true);
return $result['schema'];
}
4.2 数据验证
使用JSON Schema验证数据:
<?php
use Opis\JsonSchema\Validator;
use Opis\JsonSchema\Schema;
function validateProductData($productData, $schemaData) {
$validator = new Validator();
// 创建schema对象
$schema = Schema::fromJsonString(json_encode($schemaData));
// 验证数据
$result = $validator->validate($productData, $schema);
if ($result->hasErrors()) {
$errors = [];
foreach ($result->getErrors() as $error) {
$errors[] = [
'path' => $error->dataPointer(),
'message' => $error->message()
];
}
return ['valid' => false, 'errors' => $errors];
}
return ['valid' => true];
}
五、错误处理与状态监控
5.1 检查Feed处理状态
使用getFeed接口查询Feed处理状态:
<?php
function checkFeedStatus($feedId) {
$client = new \GuzzleHttp\Client();
$response = $client->request('GET',
"https://sellingpartnerapi-na.amazon.com/feeds/2021-06-30/feeds/{$feedId}",
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken()
]
]
);
$feedInfo = json_decode($response->getBody(), true);
// 检查处理状态
switch($feedInfo['processingStatus']) {
case 'DONE':
// 获取处理报告
if (isset($feedInfo['resultFeedDocumentId'])) {
return getFeedReport($feedInfo['resultFeedDocumentId']);
}
break;
case 'FATAL':
// 处理失败
error_log("Feed processing failed: " . json_encode($feedInfo));
break;
case 'IN_QUEUE':
case 'IN_PROGRESS':
// 继续等待
return ['status' => 'processing'];
}
return $feedInfo;
}
5.2 处理商品限制
在刊登前使用getListingsRestrictions接口检查限制:
<?php
function checkListingRestrictions($asin, $condition = 'new') {
$client = new \GuzzleHttp\Client();
$response = $client->request('GET',
'https://sellingpartnerapi-na.amazon.com/listings/2021-08-01/restrictions',
[
'headers' => [
'Authorization' => 'Bearer ' . getAccessToken()
],
'query' => [
'asin' => $asin,
'conditionType' => $condition,
'sellerId' => 'YOUR_SELLER_ID',
'marketplaceIds' => 'ATVPDKIKX0DER'
]
]
);
$restrictions = json_decode($response->getBody(), true);
// 检查是否有限制
foreach ($restrictions['restrictions'] as $restriction) {
if (!empty($restriction['reasons'])) {
return [
'restricted' => true,
'reasons' => $restriction['reasons']
];
}
}
return ['restricted' => false];
}
六、实用的迁移技巧
6.1 构建通用的请求函数
<?php
class SpApiClient {
private $accessToken;
private $endpoint = 'https://sellingpartnerapi-na.amazon.com';
public function __construct($accessToken) {
$this->accessToken = $accessToken;
}
public function request($method, $path, $params = []) {
$client = new \GuzzleHttp\Client();
$options = [
'headers' => [
'Authorization' => 'Bearer ' . $this->accessToken,
'x-amz-access-token' => $this->accessToken,
'Content-Type' => 'application/json'
]
];
if ($method === 'GET' && !empty($params)) {
$options['query'] = $params;
} else if (!empty($params)) {
$options['json'] = $params;
}
try {
$response = $client->request($method, $this->endpoint . $path, $options);
return json_decode($response->getBody(), true);
} catch (\GuzzleHttp\Exception\ClientException $e) {
$errorBody = json_decode($e->getResponse()->getBody(), true);
throw new Exception('API Error: ' . json_encode($errorBody));
}
}
}
6.2 批量数据处理的最佳实践
<?php
// 批量更新库存的优化方案
function batchUpdateInventory($inventoryUpdates) {
$chunks = array_chunk($inventoryUpdates, 1000); // 每批1000个
foreach ($chunks as $chunk) {
$messages = [];
foreach ($chunk as $index => $update) {
$messages[] = [
'messageId' => $index + 1,
'sku' => $update['sku'],
'operationType' => 'UPDATE',
'productType' => 'PRODUCT',
'attributes' => [
'fulfillment_availability' => [
[
'fulfillment_channel_code' => 'DEFAULT',
'quantity' => $update['quantity']
]
]
]
];
}
// 提交这一批数据
submitFeedBatch($messages);
// 避免超过速率限制
sleep(1);
}
}
七、我们的实战经验
7.1 从早期实践到规模化
说到JSON Listings API,我们算是第一批吃螃蟹的人。当亚马逊刚推出JSON格式的刊登接口时,我们就开始着手对接。这几年下来,我们已经通过SP-API成功上架了超过100万个商品,覆盖了美国、欧洲、日本、澳洲等几乎所有主要站点。
7.2 踩过的坑和经验总结
在实际操作中,有几个关键点特别重要:
1. ProductType的正确选择 很多人在刊登时第一个难题就是不知道该用哪个ProductType。我们的经验是:
- 先通过关键词搜索相似商品的ASIN
- 用getCatalogItem获取该ASIN的productType
- 如果还是不确定,可以用searchDefinitionsProductTypes接口搜索
2. JSON Schema的智能解析 亚马逊的JSON Schema非常复杂,手动解析容易出错。我们开发了一套自动解析工具:
- 自动识别required字段
- 根据conditionalRequired动态调整必填项
- 智能提示可选值和格式要求
3. 大批量铺货的技术架构 要实现日均上万商品的刊登,需要完整的技术方案:
- 多线程/队列处理,充分利用API限流
- 智能重试机制,自动处理临时错误
- 实时监控系统,及时发现和处理问题
7.3 后续教程预告
这篇文章只是开了个头,接下来我会陆续分享更多深度内容:
《SP-API刊登实战系列》计划包括:
- JSON Schema深度解析 - 如何自动解析Schema,生成UI表单
- ProductType完全指南 - 各类目的ProductType详解和选择技巧
- 批量刊登架构设计 - 从0到日均10万商品的系统演进
- 多站点刊登策略 - 不同站点的特殊要求和优化方案
- 变体商品高级玩法 - 复杂变体关系的处理技巧
- 错误处理最佳实践 - 常见错误代码和解决方案大全
关注我,获取第一手SP-API实战经验! 如果这篇文章对你有帮助,请点赞👍收藏⭐评论💬三连支持。评论区留下你最想了解的内容,点赞评论多的话题我会优先更新详细教程。
7.4 特别提醒
如果你的业务涉及到敏感数据处理(比如买家信息、订单详情等),可能需要申请PII(Personally Identifiable Information)权限。这个权限的申请有一定门槛,需要提供详细的使用场景说明和数据安全措施。如果你在PII权限申请上遇到困难,也可以私信联系我,我们有丰富的申请经验可以分享。
总结
从XML到JSON的转变不仅仅是格式的改变,更是整个商品管理理念的升级。新的API设计更加RESTful,响应更快,错误信息更详细,整体开发体验有了质的飞跃。
虽然迁移过程可能会有些痛苦,但长远来看,这绝对是值得的。建议大家尽快开始迁移工作,别等到最后关头才手忙脚乱。
记住,技术债务就像信用卡账单,拖得越久利息越高。现在行动,还来得及!
相关资源: