亚马逊SP-API Listing刊登重大更新:从XML到JSON的转型之路 - 2025年07月31日商品刊登Feed类型变更详解

187 阅读7分钟

亚马逊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刊登实战系列》计划包括:

  1. JSON Schema深度解析 - 如何自动解析Schema,生成UI表单
  2. ProductType完全指南 - 各类目的ProductType详解和选择技巧
  3. 批量刊登架构设计 - 从0到日均10万商品的系统演进
  4. 多站点刊登策略 - 不同站点的特殊要求和优化方案
  5. 变体商品高级玩法 - 复杂变体关系的处理技巧
  6. 错误处理最佳实践 - 常见错误代码和解决方案大全

关注我,获取第一手SP-API实战经验! 如果这篇文章对你有帮助,请点赞👍收藏⭐评论💬三连支持。评论区留下你最想了解的内容,点赞评论多的话题我会优先更新详细教程。

7.4 特别提醒

如果你的业务涉及到敏感数据处理(比如买家信息、订单详情等),可能需要申请PII(Personally Identifiable Information)权限。这个权限的申请有一定门槛,需要提供详细的使用场景说明和数据安全措施。如果你在PII权限申请上遇到困难,也可以私信联系我,我们有丰富的申请经验可以分享。

总结

从XML到JSON的转变不仅仅是格式的改变,更是整个商品管理理念的升级。新的API设计更加RESTful,响应更快,错误信息更详细,整体开发体验有了质的飞跃。

虽然迁移过程可能会有些痛苦,但长远来看,这绝对是值得的。建议大家尽快开始迁移工作,别等到最后关头才手忙脚乱。

记住,技术债务就像信用卡账单,拖得越久利息越高。现在行动,还来得及!


相关资源