文档管理中心
我的
API参考应用内支付服务订单、订阅服务ServerSubscription服务验证购买Token

Subscription服务验证购买Token

功能介绍

此接口用于校验购买的商品,判断商品是否已经成功购买,是否在有效期内。

场景描述

在完成一笔支付后,IAP客户端会返回商品购买单详情JSON字符串InAppPurchaseData和签名字符串dataSignature。InAppPurchaseData中有用于唯一标识商品和用户对应关系的purchaseToken。

通过签名验证,可确保InAppPurchaseData有效性。您还可以解析出InAppPurchaseData中的purchaseToken数据,调用华为应用内支付服务器提供的Subscription服务验证购买Token接口。为避免资金损失,您在验签成功后,必须校验InAppPurchaseData中的productId、price、currency等信息的一致性。验证方法和公钥获取方式可参见验证InAppPurchaseData。一般应该判断商品是否已经成功购买,对于订阅型商品返回最近的收费情况,包括何时收费以及是否在有效期内。

说明
  • 该接口只针对订阅型商品。

接口原型

承载协议

HTTPS POST

接口方向

开发者服务器-> 华为应用内支付服务器

接口URL

{rootUrl}/sub/applications/v2/purchases/get

说明

rootUrl在不同站点有不同的url:您应固定选择最近站点的Subscription服务地址访问。具体请参见站点信息和站点选择。

数据格式

请求消息:Content-Type: application/json

响应消息:Content-Type: application/json

请求参数

Request Header

展开

参数

是否必选

参数类型

描述

Content-Type

是

String

取值为:application/json; charset=UTF-8

Authorization

是

String

认证信息,使用Access Token进行鉴权,这里使用开放平台鉴权提供的服务接口获取Access Token,格式说明参考公共说明,获取方式参考获取应用级AT。

Request Body

展开

参数

是否必选

参数类型

描述

subscriptionId

是

String

订阅ID。

purchaseToken

是

String

商品的购买Token,发起购买和查询订阅信息均会返回。

请求示例

收起
自动换行
深色代码主题
复制
  1. POST /sub/applications/v2/purchases/get
  2. Content-Type: application/json; charset=UTF-8
  3. Authorization: Basic QVQ6Q1YzQ1NPbVlBaGwrZUtRWExtMTBVV2pyWXZHTVF4MmYvcVMya1B0ZElLY3UwaFJrdFNTMmxwdk1FQkIyYldXWGt0REVaR3I4UjFUTTRLMVlmNXdwWU80RG04THdXQWxjaFhEYjBMUjBNTUJtWnFYcGFtazc3THN3UnFJbkhHK28xekdqRzNSMg==
  4. Accept: application/json
  5. Content-Length: 171
  6. {
  7. "purchaseToken": "00000173741056a37eef310dff9c6a86fec57efafe318ae478e52d9c4261994d64c8f6fc8ea1abbdx5347.5.3089",
  8. "subscriptionId": "1581789719266.D40972AC.3089"
  9. }

响应参数

Response Header

展开

参数

是否必选

参数类型

描述

Content-Type

是

String

取值为:application/json; charset=UTF-8

Response Body

展开

参数

是否必选

参数类型

描述

responseCode

是

String

返回码。

  • 0:成功。
  • 其他:失败,具体请参见错误码。

responseMessage

否

String

响应描述。

inappPurchaseData

否

String

包含购买详情的字符串(JSONString格式),格式请参见InappPurchaseDetails。

dataSignature

否

String

inappPurchaseData基于应用RSA IAP私钥的签名信息,签名算法为signatureAlgorithm。应用请参见对返回结果验签使用IAP公钥对inappPurchaseData的JSON字符串进行验签。

signatureAlgorithm

是

String

签名算法。默认为:SHA256WithRSA/PSS。

响应示例

收起
自动换行
深色代码主题
复制
  1. HTTP/1.1 200 OK
  2. Content-Type: application/json; charset=UTF-8
  3. Content-Length: 1035
  4. {
  5. "responseCode": "0",
  6. "inappPurchaseData": "{\"autoRenewing\":true,\"subIsvalid\":true,\"orderId\":\"1581789719266.E359BC66.3089\",\"lastOrderId\":\"L1581789719266.E359BC66.3089\",\"packageName\":\"com.huawei.packagename\",\"applicationId\":123456,\"productId\":\"prd2\",\"kind\":2,\"productName\":\"订阅型商品名称\",\"productGroup\":\"0DED5AC93D084C489F94312E217E1DBD\",\"purchaseTime\":1597677768003,\"oriPurchaseTime\":1597677768003,\"purchaseState\":0,\"developerPayload\":\"payload data\",\"purchaseToken\":\"00000173741056a37eef310dff9c6a86fec57efafe318ae478e52d9c4261994d64c8f6fc8ea1abbdx5347.5.3089\",\"purchaseType\":0,\"currency\":\"CNY\",\"price\":50,\"country\":\"CN\",\"subscriptionId\":\"1581789719266.D40972AC.3089\",\"quantity\":1,\"daysLasted\":0,\"numOfPeriods\":1,\"numOfDiscount\":0,\"expirationDate\":1597677948003,\"retryFlag\":1,\"introductoryFlag\":0,\"trialFlag\":0,\"renewStatus\":1,\"renewPrice\":50,\"cancelledSubKeepDays\":30,\"payOrderId\":\"WX123456789ce8e23ee927\",\"payType\":\"17\",\"confirmed\":1}",
  7. "dataSignature": "FiJJZYRdVIFgEzDA4GbGrR/JbmExXgXJOnYLINc1besVPKakC01NuwfD54HFYKcm092iwoctqEbGleODbwjINRv047320p51dzeXozB8ozjqXQ2DlkaMgYUe0CLgB72ttkYG2EIrHyJullNpPuaMXNQ6R5DOrY0XRLDF4yOpiRoSHuQohTVk2wx5ugZ7537E2c5ZCc/AmiGLJT1Uxh4EDyTB8aGBZTWJgy2D/ogJLW86PKpVREhJEWxVco1IbVe5dvjutheh5oBfRcsJg+AgSLoNgbKvjn1dNlEGc4VoRsJSBP1M5ukYgh16r4y7DBqBA/QrRE7ocvzzPm/W/teeng==",
  8. "signatureAlgorithm":"SHA256WithRSA"
  9. }

调用示例

说明

在完成一笔支付后,您的客户端会获取到商品订单详情JSON字符串InAppPurchaseData。

更多语言示例代码请参见服务端示例代码,您可直接下载代码工程。相关的库和方法可参见代码工程。

Java
Python
Go
收起
自动换行
深色代码主题
复制
  1. public class SubscriptionService {
  2. // TODO: 将(ip:port)替换为实际值,如果协议使用的是https,您还应该处理证书认证相关的逻辑
  3. public static final String TOC_SITE_URL = "https://ip:port";
  4. public static void getSubscription(String subscriptionId, String purchaseToken)
  5. throws Exception {
  6. // 获取应用级AccessToken
  7. String appAt = AtDemo.getAppAT();
  8. // 在请求头中构建Authorization
  9. Map<String, String> headers = AtDemo.buildAuthorization(appAt);
  10. // 包装request的body信息
  11. Map<String, String> bodyMap = new HashMap<>();
  12. bodyMap.put("subscriptionId", subscriptionId);
  13. bodyMap.put("purchaseToken", purchaseToken);
  14. String msgBody = JSONObject.toJSONString(bodyMap);
  15. // demo中使用5000作为超时时间,您可以按照需要调整
  16. String response = AtDemo.httpPost(TOC_SITE_URL + "/sub/applications/v2/purchases/get",
  17. "application/json; charset=UTF-8", msgBody, 5000, 5000, headers, true);
  18. // TODO: 在console中将response作为字符串打印,您可以根据业务逻辑替换处理方式
  19. System.out.println(response);
  20. }
  21. }
收起
自动换行
深色代码主题
复制
  1. class SubscriptionService:
  2. def __init__(self):
  3. # TODO: 将(ip:port)替换为实际值,如果协议使用的是https,您还应该处理证书认证相关的逻辑
  4. self.TOC_SITE_URL = "https://ip:port"
  5. self.getSubscriptionUrl = "%s/sub/applications/v2/purchases/get"
  6. def getSubscription(self, subscriptionId, purchaseToken):
  7. # 获取应用级AccessToken
  8. appAt = AtDemo.getAppAT()
  9. if appAt is None or appAt == "":
  10. return
  11. # 在请求头中构建Authorization
  12. headers = AtDemo.buildAuthorization(appAt)
  13. # 包装request的body信息
  14. bodyDict = {"subscriptionId": subscriptionId, "purchaseToken": purchaseToken}
  15. data = json.dumps(bodyDict)
  16. response = AtDemo.httpPost(self.getSubscriptionUrl % self.TOC_SITE_URL, str.encode(data), headers)
  17. # TODO: 在console中将response作为字符串打印,您可以根据业务逻辑替换处理方式.
  18. print(response)
收起
自动换行
深色代码主题
复制
  1. type SubscriptionClient struct {
  2. }
  3. // TODO: 将(ip:port)替换为实际值,如果协议使用的是https,您还应该处理证书认证相关的逻辑
  4. const TOC_SITE_URL = "https://ip:port"
  5. var SubscriptionDemo = &SubscriptionClient{}
  6. func (subscriptionDemo *SubscriptionClient) GetSubscription(subscriptionId, purchaseToken string) {
  7. bodyMap := map[string]string{
  8. "subscriptionId": subscriptionId,
  9. "purchaseToken": purchaseToken,
  10. }
  11. url := TOC_SITE_URL + "/sub/applications/v2/purchases/get"
  12. bodyBytes, err := SendRequest(url, bodyMap)
  13. if err != nil {
  14. log.Printf("err is %s", err)
  15. }
  16. // TODO: 在console中将response作为字符串打印,您可以根据业务逻辑替换处理方式.
  17. log.Printf("%s", bodyBytes)
  18. }

Postman调试

您可以使用Postman在线调试此接口。