基本配置
- 生产环境域名:https://api.kkmh.com
服务端出口 IP
以下是服务端公网出口 IP 地址列表,可用于游戏方设置 IP 白名单、限制来源访问等可选操作:
- 152.136.121.23
- 154.8.223.246
- 192.144.138.68
- 62.234.96.209
- 152.136.121.188
- 62.234.98.227
接口验证
签名(Sign)
所有游戏服务端调用快看服务端提供的接口统一使用 Query 参数中的 sign 字段验证请求调用方的合法性,即游戏服务端以
https://api.kkmh.com/v1/game/oauth/someApi?sign=<sign>&otherQuery=<query>
的形式调用快看服务端提供的接口,该签名参数必须经过 urlencode 编码。
签名算法
签名生成的通用步骤如下,设有除了 sign 参数之外的参数键值对 fruit=apple,color=red,number=10
和值为空的键值对 money=
,游戏方在快看方接入时分配的密钥为 key=donottellanyone
:
- 排除 Query 参数中参数值为空的键值对,即排除
money=
; - 对剩下大小写敏感的 Query 参数键值对按照字段名称 ASCII 码的字典序(从小到大)顺序 ,即 color=red,fruit=apple,number=10;
- 对键值对用 URL 键值对的格式拼接成 URL 查询串,即
color=red&fruit=apple&number=10
,记作S1
; - 在得到的 URL 查询串后拼接上密钥键值对,得到最终查询串,即
color=red&fruit=apple&number=10&key=donottellanyone
,记作S2
; - 对
S2
做 MD5 哈希运算得到的字节数组B1
; - 将字节数组
B1
做 Base64 编码运算得到最终的签名sign
。 - 签名
sign
在放入 URL 之前必须经过 urlencode 编码。
示例代码(Java)
// 设置快看密钥
String key = "key=donottellanyone";
// 设置参数
Map<String, String> params = new HashMap<>();
params.put("fruit", "apple");
params.put("color", "red");
params.put("number", "10");
String S1 = params.entrySet().stream()
// 过滤掉 value 为空
.filter(e -> e.getValue() != null && !e.getValue().equals(""))
// 按键做字典排序
.sorted(Comparator.comparing(Entry::getKey))
// 转化成 key=value 的形式
.map(e -> String.format("%s=%s", e.getKey(), e.getValue()))
// 拼接成 & 连接的字符串
.collect(Collectors.joining("&"));
// 追加 key 后缀
String S2 = S1 + "&" + key;
// 此处需要处理 NoSuchAlgorithmException
MessageDigest messageDigest = MessageDigest.getInstance("MD5");
// 计算 MD5 哈希值,
byte[] B1 = messageDigest.digest(S2.getBytes(StandardCharsets.UTF_8));
// 进行 Base64 编码获得签名
String sign = Base64.getEncoder().encodeToString(B1);
以上代码的输出签名结果为:
njradWgg29vuIsSp9nB5Fw==
示例代码(PHP)
$params = "color=red&fruit=apple&number=10&key=donottellanyone";
$digest = md5($params, true);
$sign = base64_encode($digest);
echo $digest;
echo "<br>";
echo $sign;
验证数据集
游戏方可使用以下提供的预计算的输入参数和签名来验证自己的实现是否符合文档要求。
- 数据集 A
- 输入参数串(未排序):
fruit=apple&color=red&number=10
- 快看密钥:
donottellanyone
- 签名:
njradWgg29vuIsSp9nB5Fw==
- 输入参数串(未排序):
- 数据集 B
- 输入参数串(未排序):
app_id=1024&out_order_id=1104&wares_id=1&open_uid=88881024
- 快看密钥:
donottellanyone
- 签名:
utwycklpsZjmRQoMW446lw==
- 输入参数串(未排序):
- 数据集 C
- 输入参数串(未排序):
app_id=1024&out_order_id=1104&wares_id=1&open_uid=88881024
- 快看密钥:
mealdeal
- 签名:
9w/2KQotTPCS72sYYJ9JIA==
- 输入参数串(未排序):
接口返回
快看服务端提供的 API 接口具有统一的返回结构,所有请求在成功被快看后端服务接收后,无论请求成功或失败,合法或非法,都会返回以下的结构:
{
"code": 200,
"message": "OK",
"data": {
...
}
}
其中 code
字段描述反馈的状态码,message
字段描述返回的具体信息,data
字段描返回的数据,若无数据返回,则 data
字段为 null
。针对 H5 SDK,服务端可能返回的错误码列表如下:
状态码 | 具体信息 | 描述 |
---|---|---|
200 | OK | 表示请求合法且按快看服务端的预期被正确处理,即请求成功,并且可能包含可选的 data 字段。 |
2005 | 服务器暂时不可用,请稍后重试 | 表示快看服务端未能成功处理请求,可能的原因有:服务端抛出未处理的异常、请求对应的资源不存在(非法 appId 或不存在的用户)。 |
7002 | sign 非法 | 表示快看服务端校验参数传入的 sign 和实际计算的 sign 不一致,可能是请求的 sign 计算错误,此时游戏方服务端需要检查传入的参数列表和 sign 的计算是否符合本文档定义。 |
7003 | sign 非法 | 下单参数错误。 |
7018 | 达到支付限额 | 该用户该月达到支付限额,或该笔交易的金额达到最大单笔支付限额,具体见支付限额 |
40051 | 该游戏不支持付费或无可用支付平台,请检查配置 | 目前仅针对 iOS 平台下单,且游戏未开通 KK 币支付时出现,具体见 KK 币支付 |
支付限额
快看支付服务统计每个未成年用户的支付行为,每个未成年用户每月有一定数额的支付上限和单笔支付上限,该功能基于实名认证而实现,若用户未进行实名认证,则按照最严格支付限额处理,具体的支付限额见下表所示:
阶段 | 单笔支付限额 | 每月支付限额 |
---|---|---|
实名认证成年用户 | 无 | 无 |
16 ~ 18 岁用户 | 100 | 400 |
8 ~ 15 岁用户 | 50 | 200 |
8 岁以下用户 | 不可支付 | 不可支付 |
未实名认证用户 | 不可支付 | 不可支付 |
游戏方可选择是否开启改支付限额功能,该功能的启用请联系快看运营同学。
KK 币支付
若 H5 游戏选择在 iOS 平台发型,则支付方式只能选择接入快看 KK 币支付,KK 币是快看漫画 app 内的货币,可用于购买漫画或者游戏内消费。
API 定义
验证 open_id 合法性
游戏方服务端可通过调用该接口来验证 open_id 是否在给定 app_id 下合法,该接口不强制游戏服务端必须调用,建议游戏方服务端主动调用。(由于前端会缓存access_token(有效时长 5min),如果返回状态码为 4002,表明 access_token 已失效,需要接入方主动调用 kkH5sdk.clearUserCache 后重新调用 kkH5sdk.autoAuthorize 获取新的access_token)
GET /v1/game/oauth/check_open_id
参数 Query
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
app_id | text | 是 | 游戏 id | |
open_id | text | 是 | 开放 id,游戏用户在渠道分配的 id | |
access_token | text | 是 | 访问口令,用于登录和标识请求来源。 | |
sign | text | 是 | 参数签名 |
返回结果 JSON
{
"code": 200,
"message": "OK",
"data": {
"ret": boolean, // open_id 合法时返回 true 否则为 false
}
}
获取用户信息
游戏方服务端可通过调用该接口来获取用户信息,游戏方调用该接口时需要区分 access_token 对应的时授权用户还是游客,目前游客无法通过调用该 API 来获取信息,即使用游客的 access_token 和使用非法的 access_token 返回的结果是一样的。
GET /v1/game/oauth/user_info
参数 Query
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
access_token | text | 是 | 访问口令,用于登录和标识请求来源。 |
返回结果 JSON
{
"code": 200,
"message": "OK",
"data": {
"open_id": string, // open_id
"nickname": string, // 昵称
"avatar_url": string, // 头像 URL
}
}
查询实名认证状态
游戏服务器向渠道服务器请求特定游戏用户的实名认证状态。
快看渠道提供了记录游戏用户实名认证状态的功能,游戏服务器可通过该接口查询对应用户在快看的实名认证状态,根据认证状态来做相应的防沉迷处理。
GET /v1/game/oauth/real_name/verify
参数 Query
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
app_id | text | 是 | 游戏 id | |
open_id | text | 是 | 开放 id,游戏用户在渠道分配的 id | |
sign | text | 是 | 参数签名 |
返回结果 JSON
{
"code": 200,
"message": "OK",
"data": {
"id": string, // 用于表示身份证的唯一字符串,未认证状态不返回
"id_type": number, // 固定为 1,表示身份证,未认证状态不返回
"age": number, // 年龄,未认证状态不返回
"oversea": boolean, // 是否是海外用户
"verify_status": number, // 认证状态,1 - 未验证,2 - 验证通过,3 - 验证失败
"birthday": string // 出生日期,格式为 yyyy-MM-dd,未认证状态不返回
}
}
支付
游戏申请接入后,快看会为游戏分配 app_id;游戏方不必向快看提供游戏内商品列表,快看方只作为支付过程中的收银台,只以订单编号区分不同支付请求以及价格,不关心具体的商品商品 id 和类型。
所有接口都需要签名验证,签名规则见上文「签名(Sign)」部分,必须在登录的情况下下单,不支持游客下单,用户必须是快看用户,且 out_order_id 必须唯一。
下单接口
SDK 已封装下单接口,游戏服务端按照要求格式传参即可,传参格式示例:
trans_data={"app_id":"123","wares_id":1,"out_order_id":"22222","open_uid":"123","out_notify_url":"https://www.iapppay.com/test","trans_money":1.1,"wares_name":"自定义商品名","url_r":"https://xxxxx/xx","url_h":"https://xxxxx/yyy"}&sign=xxxxxx
参数描述
参数名称 | 参数含义 | 类型 | 必填 | 说明 |
---|---|---|---|---|
trans_data | 传输内容 | text | 是 | 传输内容,JSON 格式的字符串 |
sign | 签名 | string | 是 | 参数签名 |
trans_data结构
参数名称 | 参数含义 | 类型 | 必填 | 说明 |
---|---|---|---|---|
app_id | 应用编号(游戏 id) | string(20) | 是 | 快看平台分配的游戏 id |
wares_id | 商品 id | integer | 是 | 商品 id,固定传 1 |
out_order_id | 游戏方订单 id | string(64) | 是 | 游戏方订单 id,有游戏方生成,需保证唯一 |
out_notify_url | 支付结果通知 URL | string(500) | 是 | 用于支付结果的通知,若通知失败会尝试重试。 |
open_uid | 用户在游戏应用的唯一标识 | string(20) | 是 | 唯一标识用户 |
trans_money | 订单金额(元) | float | 是 | 最高保留两位小数,比如 1 元为 1, 1.1 元为 1.1,1 毛为 0.1 |
wares_name | 商品名称 | string(32) | 是 | 用于订单描述,必须不为空 |
在用户支付完成后,快看服务端会以 POST 的方式调用参数中 out_notify_url 指定的支付结果通知 URL,通知的参数依然为 trans_data 和 sign,其中通知返回的 tran_data 的结构见「订单查询接口」和「返回结果 JSON」章节。
此时游戏服务端需要根据通知结果的数据和自身逻辑判断是否进行发货,并在发货完成后回复快看服务端以下结果作为 out_notify_url 的返回值:
- 不区分大小写的字符串 SUCCESS,即 "SUCCESS"(不包含引号),表示订单发货成功;
- 任何其他字符串,表示订单处理失败,此时快看服务端会进行最多 10 次的请求重试。
- 同样的通知结果可能会多次发送给商户系统,商户系统必须能够正确处理重复的通知。如果已处理过,直接返回成功。
订单查询接口
用于服务端主动查询订单信息
POST /v2/game_pay/query_order
参数 Query
属性 | 类型 | 默认值 | 必填 | 说明 |
---|---|---|---|---|
trans_data | text | 是 | 传输内容,JSON 格式的字符串 | |
sign | text | 是 | 参数签名 |
trans_data 结构
{"app_id":"123","order_id":111111,"out_order_id":"22222","notify_url":"https://www.iapppay.com/test"}
属性 | 类型 | 说明 |
---|---|---|
app_id | string | 传输内容 |
order_id | number | 快看生成的订单 id |
out_order_id | string | 游戏方生成的订单 id |
notify_url | string | 回调通知 URL |
可通过 order_id 或者 out_order_id 查询订单状态
返回结果 JSON
{
"code": 200,
"message": "OK",
"data": {
"trans_data": " {
\"wares_id\": number, // 商品 id
\"pay_status\": number, // 支付状态,1 - 等待支付,2 - 支付成功
\"out_order_id\": string, // 游戏方生成的订单 id
\"trans_money\": number(float), // 交易金额,元
\"trans_id\": 交易 id, // 本次交易生成的流水 id
\"trans_result\": 交易结果, // 交易状态,与 pay_status 类似,0 - 交易成功,1 - 交易失败,2 - 交易进行中
\"currency\": string, // 货币类型,固定为 RMB
\"pay_type\": number, // 支付方式
\"trans_time\": number, // 交易时间戳,毫秒表示
\"open_uid\": string, // 游戏用户 id
\"order_id\": string, // 快看订单 id
\"app_id\": string, // 游戏 id
}",
"sign": string, // 签名
}
}
支付方式 pay_type 枚举
支付方式枚举值 | 描述 |
---|---|
1 | 支付宝 |
2 | 微信支付 |
11 | 微信公众号 H5 移动端网站支付 |
14 | QQ H5 移动端网站支付 |
FAQ
验证签名无法通过:
- 回调通知的 trans_data,如果使用 PHP 语言,会存在精度丢失问题,如:trans_data 中的 trans_money 是 1.0,但使用 PHP 语言时,验证签名的时候是 1,这样会导致验证不通过。
- 调用订单查询接口时,若返回签名错误,可以比较一下传的trans_money参数和接口返回的trans_money参数是否一致
- trans_money参数在下单时需要传数字类型,而非字符串
- 部分cp接入时出现传输的sign参数后面带有空格等特殊字符,可以重点关注
提示open_uid未登录:
- open_uid 非法,应当传一个通过快看 SDK 登录的快看 open_uid。
trans_data 是否是 JSON 格式的字符串?
- 是的。
下单时提示open_uid未登录:
- 检查是否是以游客身份登录,游客身份登录目前不支持支付
未收到支付回调
- 确保下单时传递的回调接口参数out_notify_url是完整的url