快速对接amazon sp-api步骤
sp-api官方的接口文档:references
第一步:在amazon官网在注册开发者,获取调用amazon sp-api所需的配置信息 SellingPartnerApiDeveloperGuide(中文).md developer-docs.amazon.com/sp-api/refe…
第二步:下载amazon sp-api对应的sdk,在amazon已经针对sp-api调用封装好了,提供对应的sdk
一、获取token
- 获取token对应的接口文档:
步骤 1。卖家从商城应用商店启动授权
- 卖家登录卖家平台并进入商城应用商店。
- 卖家转到应用程序的详情页面,然后单击立即授权按钮。此时将显示您的应用程序的同意页面。
步骤 2。卖家同意授权您的应用程序
- 卖家查看同意页面,查看并接受您的应用程序所请求的数据访问,然后单击立即登录 [您的应用程序名称] 按钮继续。卖家可以单击取消按钮,在不授权的情况下退出。
- 亚马逊将您的登录 URI(您在应用程序注册时提供)加载到浏览器中,并添加以下查询参数:
| 参数 | 描述 |
|---|---|
| amazon_callback_uri | 用于将浏览器重定向到亚马逊的 URI。 |
| amazon_state | 亚马逊生成的状态值,用于防范跨站点请求伪造攻击。 |
| selling_partner_id | 授权您的应用程序的卖家的卖家编号。 |
**注意:**如果这是测试工作流程(卖家通过导航到您的 OAuth 授权 URI 开始),亚马逊将包含 version=beta 参数。如果这是一个生产工作流程(卖家从商城应用商店开始),亚马逊不包含该参数。
例如:
https://d2yzyfnnpjylxu.cloudfront.net/index.html?amazon_callback_uri=https://amazon.com/apps/authorize/confirm/amzn1.sellerapps.app.2eca283f-9f5a-4d13-b16c-474EXAMPLE57&amazon_state=amazonstateexample&selling_partner_id=A3FHEXAMPLEYWS
将显示您网站的登录页面。
步骤 3。卖家登录您的网站
- 卖家登录您的网站。如果卖家还没有账户,他们要完成注册流程。
- 您的应用程序将亚马逊回调 URI(在上一步中由亚马逊传递)加载到浏览器中,并添加以下参数:
| 参数 | 描述 |
|---|---|
| redirect_uri | 用于将浏览器重定向到您的应用程序的 URI。 |
| amazon_state | 亚马逊在上一步中传递的 amazon_state 值。 |
| state | 您的应用程序生成的状态值。您的应用程序使用此值来维护此请求和响应之间的状态,从而帮助防范跨站点请求伪造攻击。重要说明: 由于 OAuth 信息是通过 URI 查询参数传递的,我们强烈建议您执行以下操作: (1) 确保状态令牌对您的用户属于短期令牌,并且具有可验证的唯一性,以及 (2) 设置 Referrer-Policy: no-referrer HTTP 标头,防止将敏感信息泄露到您的网站链接到的网站。有关跨站点请求伪造和计算 state 参数的更多信息,请参阅“使用亚马逊账户登录”文档中的跨站点请求伪造。 |
**注意:**如果包含 Version=beta 参数,则工作流程将授权处于草稿状态的应用程序。如果您不包含该参数,则工作流程将授权在商城应用商店中发布的应用程序。
例如:
https://amazon.com/apps/authorize/confirm/amzn1.sellerapps.app.2eca283f-9f5a-4d13-b16c-474EXAMPLE57?redirect_uri=https://d2yzyfnnpjylxu.cloudfront.net/landing.html&amazon_state=amazonstateexample&state=-37131022&version=beta
或者
https://amazon.com/apps/authorize/confirm/amzn1.sellerapps.app.2eca283f-9f5a-4d13-b16c-474EXAMPLE57?redirect_uri=https://d2yzyfnnpjylxu.cloudfront.net/landing.html&amazon_state=amazonstateexample&state=-37131022
步骤 4。亚马逊向您发送授权信息
卖家平台会短时间显示一个页面,表明亚马逊正在授权您访问卖家数据。显示该页面时,将执行以下操作:
- 亚马逊将您的重定向 URI 加载到浏览器中,并添加以下查询参数:
| 参数 | 描述 |
|---|---|
| state | 您在上一步中传递的状态值。 |
| selling_partner_id | 授权您的应用程序的卖家的卖家编号。 |
| mws_auth_token | 您在为调用亚马逊商城网络服务创建查询字符串时使用的 MWSAuthToken 值。只有当卖家授权混合销售伙伴 API 应用程序时,才会传递 mws_auth_token 参数。有关更多信息,请参阅混合销售伙伴 API 应用程序。 |
| spapi_oauth_code | 您用来交换 LWA 刷新令牌的“使用亚马逊账户登录”(LWA) 授权码。有关更多信息,请参阅步骤 5:您的 应用程序用 LWA 授权码交换 LWA 刷新令牌。 |
例如:
https://client-example.com?state=state-example&mws_auth_token=mwsauthtokenexample&selling_partner_id=sellingpartneridexample&spapi_oauth_code=spapioauthcodeexample
- 您的应用程序可以验证 state 值。
- 您的应用程序会保存 selling_partner_id、mws_auth_token(如果传递)和 spapi_oauth_code 值。
- 显示网站的登录页面。
步骤 5。您的应用程序用 LWA 授权码交换 LWA 刷新令牌
适用于 JavaScript 的“使用亚马逊账户登录”SDK 可以帮助您用 LWA 授权码交换 LWA 刷新令牌。有关更多信息,请参阅《使用亚马逊账户登录》文档。
用 LWA 授权码交换 LWA 刷新令牌
- 您的应用程序调用“使用亚马逊账户登录 (LWA)”授权服务器 (
https://api.amazon.com/auth/o2/token),用 LWA 授权码交换 LWA 刷新令牌。调用必须包含以下查询参数。
| 参数 | 描述 |
|---|---|
| grant_type | 请求的访问授权类型。必须是 authorization_code。 |
| code | 您在步骤 4:亚马逊向您发送授权信息中收到的 LWA 授权码。 |
| redirect_uri | 您的应用程序的重定向 URI。 |
| client_id | 您的 LWA 凭证的一部分。要获得此值,请参阅查看您的开发者信息。 |
| client_secret | 您的 LWA 凭证的一部分。要获得此值,请参阅查看您的开发者信息。 |
例如:
POST /auth/o2/token HTTP/l.l
Host: api.amazon.com
Content-Type: application/x-www-form-urlencoded;charset=UTF-8
grant_type=authorization_code&code=SplxlOexamplebYS6WxSbIA&client_id=foodev&client_secret=Y76SDl2F
- LWA 授权服务器返回 LWA 刷新令牌。响应采用 JSON 格式并包含以下元素。
| 参数 | 描述 |
|---|---|
| access_token | 授权您的应用程序代表卖家采取某些操作的令牌。请参阅连接到销售伙伴 API。 |
| token_type | 返回的令牌类型。应该是 bearer。 |
| expires_in | 访问令牌失效之前的秒数。 |
| refresh_token | 可以交换为新访问令牌的长期令牌。请参阅连接到销售伙伴 API。 |
HTTP/l.l 200 OK
Content-Type: application/json;
charset UTF-8
Cache - Control: no-store
Pragma: no-cache
{
"access_token": "Atza|IQEBLjAsAexampleHpi0U-Dme37rR6CuUpSR",
"token_type": "bearer",
"expires_in": 3600,
"refresh_token": "Atzr|IQEBLzAtAhexamplewVz2Nn6f2y-tpJX2DeX"
}
- 您的应用程序保存 refresh_token 值。
- 浏览器向卖家显示一个页面,指示使用应用程序的后续步骤。
LWA 刷新令牌是您交换 LWA 访问令牌的长期令牌,它必须包含在销售伙伴 API 的每个请求中。发出访问令牌后,它的有效期为一小时。相同的访问令牌可用于多个 API 调用,直到它过期。请参阅连接到销售伙伴 API。
您的应用程序现在已获得授权,可以代表卖家调用销售伙伴 API。
通过SDK调用接口:
amazon sp-api # 2021-06-30版本的SDK地址:
pan.baidu.com/s/1N_JHAXOH… 提取码: 2p4a
amazon sp-api # 2020-09-04版本的SDK地址:
pan.baidu.com/s/1ePc3MbwK… 提取码: w74s
二、同步订单接口
String accessKeyId = authorConfigDTO.getAccessKeyId();
String secretKey = authorConfigDTO.getSecretKey();
String region = authorConfigDTO.getRegion();
String roleArn = authorConfigDTO.getRoleArn();
String roleSessionName = authorConfigDTO.getRoleSessionName();
String clientId = authorConfigDTO.getClientId();
String clientSecret = authorConfigDTO.getClientSecret();
String refreshToken = authorConfigDTO.getRefreshToken();
String lwaEndpoint = authorConfigDTO.getLwaEndpoint();
String spEndPoint = authorConfigDTO.getSpEndPoint();
AWSAuthenticationCredentials awsAuthenticationCredentials;
AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider;
LWAAuthorizationCredentials lwaAuthorizationCredentials;
//注意这个地方的region分北美,欧洲,远东三个AWS区域
awsAuthenticationCredentials = AWSAuthenticationCredentials.builder()
//注册成为开发者时生成的AWS访问密钥ID
.accessKeyId(accessKeyId)
//注册成为开发者时生成的AWS访问密钥
.secretKey(secretKey)
//注意,这里的region分北美(us-east-1),欧洲(eu-west-1),远东(us-west-2)
.region(region)
.build();
awsAuthenticationCredentialsProvider = AWSAuthenticationCredentialsProvider.builder()
//创建IAM职权的时候会生成这个ARN
.roleArn(roleArn)
//唯一值,可以使用UUID
.roleSessionName(roleSessionName)
.build();
lwaAuthorizationCredentials = LWAAuthorizationCredentials.builder()
//查看开发者信息的时候可看到LWA的客户端编码
.clientId(clientId)
//查看开发者信息的时候可看到LWA的客户端秘钥
.clientSecret(clientSecret)
//根据上面的客户端编码和客户端秘钥请求客户端令牌
.refreshToken(refreshToken)
//"https://api.amazon.com/auth/o2/token"
.endpoint(lwaEndpoint)
.build();
OrdersV0Api ordersV0Api = new OrdersV0Api.Builder()
.awsAuthenticationCredentials(awsAuthenticationCredentials)
.lwaAuthorizationCredentials(lwaAuthorizationCredentials)
.awsAuthenticationCredentialsProvider(awsAuthenticationCredentialsProvider)
//注意,这里的endpoint分北美,欧洲,远东三个地域,每个区域的链接是不一样的
//北美,https://sellingpartnerapi-na.amazon.com
//欧洲,https://sellingpartnerapi-eu.amazon.com
//远东,https://sellingpartnerapi-fe.amazon.com
.endpoint(spEndPoint)
.build();
OrdersV0Api ordersV0Api = commonSignHandler.buildOrdersV0Api(amazonAuthorConfigDTO);
List<String> fulfillmentChannels = new ArrayList<>();
// fulfillmentChannels.add("MFN");
List<String> orderStatuses = new ArrayList<>();
orderStatuses.add("Unshipped");
orderStatuses.add("PartiallyShipped");
List<String> marketplaceIds = this.buildMarketPlaceId(userAccountEcommerceModel);
GetOrdersResponse orders = ordersV0Api.getOrders(marketplaceIds,null,null,
DateUtils.getISO8601Timestamp(startTime.getTime()),DateUtils.getISO8601Timestamp(endTime.getTime())
,orderStatuses,fulfillmentChannels,null,null,null
,10,null,null,null);
注意:同步下来的订单商品id:
//商品id
orderEcommerceDetailModel.setItemId(orderItem.getASIN());
三、同步商品
AWSAuthenticationCredentials awsAuthenticationCredentials;
AWSAuthenticationCredentialsProvider awsAuthenticationCredentialsProvider;
LWAAuthorizationCredentials lwaAuthorizationCredentials;
//注意这个地方的region分北美,欧洲,远东三个AWS区域
awsAuthenticationCredentials = AWSAuthenticationCredentials.builder()
//注册成为开发者时生成的AWS访问密钥ID
.accessKeyId(authorConfigDTO.getAccessKeyId())
//注册成为开发者时生成的AWS访问密钥
.secretKey(authorConfigDTO.getSecretKey())
//注意,这里的region分北美(us-east-1),欧洲(eu-west-1),远东(us-west-2)
.region(authorConfigDTO.getRegion())
.build();
awsAuthenticationCredentialsProvider = AWSAuthenticationCredentialsProvider.builder()
//创建IAM职权的时候会生成这个ARN
.roleArn(authorConfigDTO.getRoleArn())
//唯一值,可以使用UUID
.roleSessionName(authorConfigDTO.getRoleSessionName())
.build();
lwaAuthorizationCredentials = LWAAuthorizationCredentials.builder()
//查看开发者信息的时候可看到LWA的客户端编码
.clientId(authorConfigDTO.getClientId())
//查看开发者信息的时候可看到LWA的客户端秘钥
.clientSecret(authorConfigDTO.getClientSecret())
//根据上面的客户端编码和客户端秘钥请求客户端令牌
.refreshToken(authorConfigDTO.getRefreshToken())
//"https://api.amazon.com/auth/o2/token"
.endpoint(authorConfigDTO.getLwaEndpoint())
.build();
ReportsApi reportsApi = new ReportsApi.Builder()
.awsAuthenticationCredentials(awsAuthenticationCredentials)
.lwaAuthorizationCredentials(lwaAuthorizationCredentials)
.awsAuthenticationCredentialsProvider(awsAuthenticationCredentialsProvider)
//注意,这里的endpoint分北美,欧洲,远东三个地域,每个区域的链接是不一样的
//北美,https://sellingpartnerapi-na.amazon.com
//欧洲,https://sellingpartnerapi-eu.amazon.com
//远东,https://sellingpartnerapi-fe.amazon.com
.endpoint(authorConfigDTO.getSpEndPoint())
.build();
解析下载文档的xml
/**
* 构建商品
*
* @param contents
*/
private List<GoodsModel> buildGoodsModel(List<String> contents,Long bPartnerId) {
if (CollectionUtils.isEmpty(contents)) {
return null;
}
List<GoodsModel> goodsModels = new ArrayList<>();
for (int i = 0, size = contents.size(); i < size; i++) {
try {
if (i == 0) {
continue;
}
if(null == contents.get(i)){
continue;
}
String[] content = contents.get(i).split("\t");
if(content.length > 16){
GoodsModel resModel = new GoodsModel();
resModel.setPlatformItemId(content[16]);
resModel.setPlatformItemName(content[0]);
//价格,目前不知道单位
if (StringUtils.isNotEmpty(content[4]) && DataUtils.isPositiveDecimal(content[4])) {
resModel.setPlatformItemPrice(new BigDecimal(content[4]));
}
resModel.setPlatformItemSku(content[3]);
resModel.setBpartnerId(bPartnerId.intValue());
resModel.setPlatform(EcaConstants.Platform.AMAZON.toLowerCase());
goodsModels.add(resModel);
logger.info("buildGoodsModel content size is greater than 16 :{}", JSON.toJSONString(content));
}else{
logger.info("buildGoodsModel content size is less than or equal to 16 :{}", JSON.toJSONString(content));
}
} catch (Exception e){
logger.error("buildGoodsModel构建商品详情出现异常Exception:{}",e);
}
}
return goodsModels;
}
四、上传跟踪号
//Step 1. Create a feed document
Map<String, String> document = createFeedDocument(model);
//Step 2. Construct a feed
String xmlFeed = constructFeed(model);
//Step 3. Upload the feed data
uploadFeedData(document, xmlFeed);
//Step 4. Create a feed
createFeed(document, model, resModel);
//step 5. getFeed
getFeed(model,resModel);
上传跟踪号上传的XML
/**
* Construct a feed
*
* @param model
* @return
*/
private String constructFeed(UploadTrackingEcommercePlatformModel model) {
if(null == model){
return null;
}
List<UploadTrackingEcommerceOrderModel> uploadTrackingEcommerceOrderModels = model
.getUploadTrackingEcommerceOrderModels();
if(CollectionUtils.isEmpty(uploadTrackingEcommerceOrderModels)){
return null;
}
StringBuilder content = new StringBuilder();
content.append("<?xml version="1.0" encoding="UTF-8"?>");
content.append("<AmazonEnvelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="amzn-envelope.xsd">");
content.append("<Header>");
content.append("<DocumentVersion>1.02</DocumentVersion>");
content.append("<MerchantIdentifier>" + model.getUserAccountEcommerceModel().getPlatformAccount() + "</MerchantIdentifier>");
content.append("</Header>");
content.append("<MessageType>OrderFulfillment</MessageType>");
content.append("<PurgeAndReplace>true</PurgeAndReplace>");
int cnt = 1;
for(int i=0;i<uploadTrackingEcommerceOrderModels.size();i++) {
content.append("<Message>");
content.append("<MessageID>" + cnt + "</MessageID>");
content.append("<OrderFulfillment>");
content.append("<AmazonOrderID>" + uploadTrackingEcommerceOrderModels.get(i).getSiteId() + "</AmazonOrderID>");
content.append("<FulfillmentDate>" + DateFormatUtils.format(DateUtils.addHours(new Date(), -9), "yyyy-MM-dd'T'HH:mm:ss") + ".304</FulfillmentDate>");
content.append("<FulfillmentData>");
content.append("<CarrierName>" + uploadTrackingEcommerceOrderModels.get(i).getCarrier()+ "</CarrierName>");
content.append("<ShippingMethod>" + uploadTrackingEcommerceOrderModels.get(i).getCarrier() + "</ShippingMethod>");
content.append("<ShipperTrackingNumber>" + uploadTrackingEcommerceOrderModels.get(i).getTrackingNo() + "</ShipperTrackingNumber>");
content.append("</FulfillmentData>");
content.append("</OrderFulfillment>");
content.append("</Message>");
cnt++;
}
content.append("</AmazonEnvelope>");
return content.toString();
}