第三方平台 开发指南 接口说明 代授权小程序接口 担保支付接口附录
# 服务商担保支付接口附录
更新时间:2023-02-08 11:00:04
# 附录1、请求签名算法
所有由开发者发起到快手平台的接口请求,都需要使用开发者的 app_secret 签名,以保证请求来源和请求数据完整性。
具体的参数签名方式如下:
- 参加签名的字段:① URL中的请求参数;② POST 的 body 参数字段。以下两种字段不参与签名:
- 特定字段名:sign、authorizer_access_token。
- 值为空的字段。
将第1步收集的字段(K)和对应的字段值(V),放到 Map<K, V> 中,并按照字段的 ASCII 码升序排列,按照下述方式连接,组装成参数字符串:
将开发者的 app_secret 拼接在参数字符串后面,使用MD5计算。
# 请求示例(如何获取签名字段)
请求信息:
curl --location --request POST 'http://localhost:8883/openapi/mp/tp/epay/create_order?component_app_id=ks675258471005732800&authorizer_access_token=ChZrcy5tcC5zYWFzLmFjY2Vzc1Rva2VuElC5yQBzk7qN5IOVM2q9ZgMZp2bxhoKm91uOm2PMPRs1ZMk3UckCHTzOof2jPdPh226F32SOzote5lQ0v3pcCZdvlpO1JiE0HQ6AQ14pY94sXhoSXk57RcScLU7SKlZ8_r20S1cmIiBpes6JyB1GknnXN3ijMlSNNlSI00e4B7TyEKcnqmPbWSgPMAE'
--header 'Content-Type: application/json'
--data-raw '{
"component_app_id":"ks675258471005732800",
"open_id":"5b748c61ef290140c0656638e8f702d3",
"out_order_no":"zxz1231111sw11as",
"total_amount":1,
"subject":"肯德基10元代金券",
"type":1,
"detail":"详情介绍",
"expire_time":3600,
"notify_url":"https://qa-mp.corp.kuaishou.com/zeus/epay/notify",
"goods_id":"productId",
"goods_detail_url":"/pages/index/index%_%",
"sign":"8be033c448a50bd96c797b34f100f3d1"
}'
签名参数信息:
Map<String, Object> signParamMap = new HashMap();
signParamMap.put("component_app_id", "ks707065143182423884");
signParamMap.put("open_id", "5b748c61ef2901405450656638e8f702d3");
signParamMap.put("out_order_no", "kdj1231113454676");
signParamMap.put("total_amount", 100);
signParamMap.put("subject", "肯德基10元代金券");
signParamMap.put("type", 1);
signParamMap.put("detail", "详情介绍");
signParamMap.put("expire_time", 3600);
signParamMap.put("notify_url", "https://xxxx.kuaishou.com/zeus/epay/notify");
待签名字符串
component_app_id=ks675258471005732800&detail=详情介绍&expire_time=3600¬ify_url=https://xxxx.kuaishou.com/zeus/epay/notify&open_id=5b748c61ef2901405450656638e8f702d3&out_order_no=kdj1231113454676&subject=肯德基10元代金券&total_amount=100&type=1your_app_secret
# 签名示例代码
Java 示例代码
/**
* 服务商 app_secret
*/
private static final String APP_SECRET = "your_app_secret";
/**
* 获取参数 Map 的签名结果
*
* @param signParamsMap 含义见上述示例
* @return 返回签名结果
*/
public static String calcSign(Map<String, Object> signParamsMap) {
// 去掉 value 为空的
Map<String, Object> trimmedParamMap = signParamsMap.entrySet()
.stream()
.filter(item -> !Strings.isNullOrEmpty(item.getValue().toString()))
.collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue));
// 按照字母排序
Map<String, Object> sortedParamMap = trimmedParamMap.entrySet()
.stream()
.sorted(Map.Entry.comparingByKey())
.collect(Collectors.toMap(
Map.Entry::getKey,
Map.Entry::getValue,
(oldValue, newValue) -> oldValue, LinkedHashMap::new));
// 组装成待签名字符串。(注,引用了guava工具)
String paramStr = Joiner.on("&").withKeyValueSeparator("=").join(sortedParamMap.entrySet());
String signStr = paramStr + APP_SECRET;
// 生成签名返回。(注,引用了commons-codec工具)
return DigestUtils.md5Hex(signStr);
}
# 附录2、回调方式和策略
在支付、退款、结算流程中,如果流程结束,第三方平台服务器会向第三方应用【消息与事件接收URL】以 HTTP POST 方式推送相应通知。
# 支付回调通知
POST 数据示例:
{
"msgId":"e3057aaf-8a99-45c0-9ea1-1110c578c199", // 消息id
"componentAppId":"ks670191919896045465", // 服务商id
"encryptedMsg":"x7s4PZ9WEvFuQc3IzPkPvu1V/s0KkdG8kScnHlsQL5l7lJeES42PWZqDdZoUdaV5h4ugpG1XAGC4EWpm9/ymImyEl1bvfdSXH5Crgur6zZjiAfMSoIgtlR55D/8Rc6c3ZXfza6zUnuU8AJIVJIJpZ2NXYpPHLS5gbPU3AIpQaNy77+z0rXzBcsrTm5HKjOz/pvo2BUXq/pZo7EYbiyjhWKF4KmHDHAwM4Cpe9F+fTrm/7YBWz5l7KMur9yzvSYX0TBaVJsk4BadYhUBgd6MFOZthBsOxLpSlOY2RWqFQIJhkpgQMGNk3iWQj3XbXxPJ4FcJNACKgPNaY61kU+C6O0+xsW5FcfqKGaJ9rVttxLsnC4qOvP3awfGUOfO7CIeiDBnkMMNqVWeKJl3OJIRO57a7sCrYLFXvfG6qVfXycQROQIZE2AQulSeBE9cgWp3OEROsGEJ3o5CAaOeh6DET/68ibIDd4BBjMg7ncrzi/GRXa1N1GBtY4laQpqNsHNLxS1/f17bBBGSp+O63+6UXAfbDTx5vo4CQmbxSVM3ZfCOqxgF8RiGic4odmF+4gD5zEjMjSVPjZzsI3j97BaQ1RnjiAwJksgtLaYV7RYAJsHwpB3t0/JwIPqUJZW2AePpL+8fR8mhdgRx/RIIXs0xoNbnG9SHEttOePRPY9T+IuejDkuH0cjnYdvDYqNwKfspMODsr3PIPl6O+e1ffNS2EktwqnS1kh2mwHdNozmm6mKE33EULcU9mWPuA23FZfRt1ZYqf6voHZqmL5Ir3UX1nCAA==", // 加密消息
"timestamp":1646033522892 // 毫秒
}
其中 encryptedMsg 字段需要解密,解密详情见消息加密解密部分。解密后消息格式如下:
{
"outOrderNo":"1646033512003demo",
"outRefundNo":null,
"outSettleNo":null,
"channel":"ALIPAY",
"attach":"小程序demo得",
"refundAmount":null,
"settleAmount":null,
"status":"SUCCESS",
"ksOrderNo":"122022801774775693641",
"tradeNo":"2022022822001445601459760702",
"ksRefundNo":null,
"ksSettleNo":null,
"orderAmount":1,
"extraInfo":"{"url":"3xdun4a3t2yr2m9","item_type":"VIDEO","item_id":"95912","author_id":"2164558553"}",
"enablePromotion":false,
"promotionAmount":0,
"appId":"ks707065143182458884",
"componentAppId":"ks670191919896045465",
"event":"PAYMENT",
"eventTime":1646033522879
}
# 退款回调通知
POST 数据示例:
{
"msgId":"6dbab05d-5e66-4269-8410-45a3334fb5dd", // 消息id
"componentAppId":"ks670191919896045465", // 服务商id
"encryptedMsg":"DvkJ0O1BumnSUmz9/loEuXqINme9U18BvCkmxwOocI6+hOucRoaJcIRvDEnuMat+HpfvxjY/Mtvd94T+fsIRNhNQQahtsIGZqYC/q588eY88MRwyljRuigs1QMBF1sURwStE6aCSDZ2yw5UWN8/JWpN8LP8mh2zl4y6h/uePUnT9iu46/PBMOMqYLjpD61jZpxui6bPC2ckLff0G42Etb9+/iIfCI/JajhZpu8cHMxa6omPxAelQDPo8//qtxy0PJZTMZ5UXpU0QQeaa93h5GrhycYuQdg+GMGm59JDzXywYSGLJTh2GIuXswZ9CQuhxFrsjUeL8jpxtK06DroszGSv/R/GqnX7zgs23JXvDlV/LzSrh8TOelQkc17pQN8exAHK1zLloTUsYDF1eNkpbfdH1mVTv8hSmexAlO83g5hazaYI9PRFhAhaF1gxFAjcLTrujPQumHLI/kRj3EWCOK+Lv2SJVrqgFbWoW6nudA5YNkeJdJwURuG/C/mV1Yl5HDoPDKYgjf5uJ9B1pmCEvapmJUAZCZ8BrEEcTEvKXVOcWi5CPtCPZLjSnY/3KDt0Ox8ZkE63+nNml41O1uGhnVpxGUicLrAKCf+lk0oNUt7c=", // 加密消息
"timestamp":1646039102361 // 毫秒
}
其中 encryptedMsg 字段需要解密,解密详情见消息加密解密部分。解密后消息格式如下:
{
"outOrderNo":null,
"outRefundNo":"400105",
"outSettleNo":null,
"channel":null,
"attach":"订单退款",
"refundAmount":1,
"settleAmount":null,
"status":"SUCCESS",
"ksOrderNo":"122022810022318493641",
"tradeNo":null,
"ksRefundNo":"222022812100019608641",
"ksSettleNo":null,
"orderAmount":null,
"extraInfo":null,
"enablePromotion":false,
"promotionAmount":0,
"appId":"ks707065143182458884",
"componentAppId":"ks670191919896045465",
"event":"REFUND",
"eventTime":1646039102355
}
# 结算回调通知
POST 数据示例:
{
"msgId":"f2e7827f-86c8-4410-8e40-8df3a1200284",
"componentAppId":"ks670191919896045465",
"encryptedMsg":"DvkJ0O1BumnSUmz9/loEuXqINme9U18BvCkmxwOocI6vUW60x/s4FRjflgxcknGeSCYHreVeIx7BQWn0xQ+Q4/BVPrtBQOzGis0sO9aMOX2gWXoG3Hestxlou7ixg70CFmDEwqZl01EeDaWQRQvYrIeEuGdkPJYODaS4LQXHMcOh26Qy1SJXXlH/rnNt6SG8Uv22DBx3K7baDzRwz5RglhW2GZcblln80LWx8+I8xdxq6AoGdlMhsuM02A7+hojlb1KgAvmdqJ9qBQT55IH5dnC3iVG1N5HYzwR2+x32FIg5Jetejt2AA2XNuyUclIkbJ7OZBkDrLTig+BOSNDFG4D/X/NKgLn3SNdngqyUDKy3TD0rcRzsJbRG49qGZHWwCvYAXdCdFQ0iQcaluI14jHQpt7haJUxzJZuqUEQhWPXGBxAilMeQewL5K7BwvfiifMEI6BLNYOKlf7YwmIyavgW0hvabpDG4Ib0+ZPe/5lmI2e+Y3WsY324IO8rtCZBCn7gQJMsvz6TIJtjiC0jPZOhg3+65TNAb2oYMSZ/74JFLoAbyVipAAUlpdWo4VaiAvpmZUBC3S9J3ojfIKRqUetF7skhYjIZOG0ATLDeckOh0=",
"timestamp":1646037363616
}
其中 encryptedMsg 字段需要解密,解密详情见消息加密解密部分。解密后消息格式如下:
{
"outOrderNo":null,
"outRefundNo":null,
"outSettleNo":"40001004",
"channel":null,
"attach":"订单结算",
"refundAmount":null,
"settleAmount":1,
"status":"SUCCESS",
"ksOrderNo":"122022810022318493641",
"tradeNo":null,
"ksRefundNo":null,
"ksSettleNo":"322022800818265709641",
"orderAmount":null,
"extraInfo":null,
"enablePromotion":false,
"promotionAmount":0,
"appId":"ks707065143182458884",
"componentAppId":"ks670191919896045465",
"event":"SETTLE",
"eventTime":1646037363573
}
# 开发者返回
开发者在接收到回调消息,并正确处理后,需要返回以下内容格式,以通知小程序平台不再持续回调:
{
"result" : 1, //必填。 1-成功,其他-失败。失败小程序平台会尝试重推此消息
"message_id" : "ChFvYXV0aC5hY2Nlc3NUb2tlbhJQvpR51x8In46B1sDB" //当前消息的message_id
}
如果开发者没有返回或者返回的result不等于1,则小程序平台会尝试重复推送此消息,开发者务必做好消息的幂等处理!
# 回调通知
注意:
1、上述提到的【支付回调通知】、【退款回调通知】、【结算回调通知】地址,均为服务商在创建第三方应用时填写的【消息与事件接收URL】。
2、服务商接收到第三方平台服务器推送给第三方应用的消息后必须返回约定成功内容,否则第三方平台服务器会认为推送失败,从而进行多次重试(重试 16 次)。
重复次数 | 延迟时间 |
---|---|
1 | 10s |
2 | 30s |
3 | 1m |
4 | 2m |
5 | 3m |
6 | 4m |
7 | 5m |
8 | 6m |
9 | 7m |
10 | 8m |
11 | 9m |
12 | 10m |
13 | 11m |
14 | 12m |
15 | 1h |
16 | 2h |
MD5(参数字符串 + app_secret)
K1=V1&K2=V2&...&Kn=Vn // 参数字符串