| 修订内容描述 | 修订日期 | 版本号 |
|---|---|---|
| 创建文档 | 20140130 | 1.0 |
| 去掉goodscount参数 | 20140221 | 1.1 |
| 重构文档 | 20140226 | 1.2 |
| 增加手机话费支付更新商品信息说明。 | 20140311 | 1.3 |
| 增加Android客户端集成支付SDK | 20140312 | 1.4 |
| 修改Android客户端集成支付SDK说明 | 20150527 | 1.5 |
| 增加文字描述 | 20150909 | 1.6 |
| 更新银联SDK | 20150916 | 1.7 |
| 新增网易支付SDK | 20160504 | 1.8 |
| 新增微信支付SDK | 20160605 | 1.9 |
| 更新网易支付SDK | 20160711 | 2.0 |
| 添加透传机制 | 20161226 | 2.1 |
| 增加获取用户信息接口 | 20170915 | 2.2 |
| 增加支付流程角色说明 | 20170917 | 2.3 |
| 梳理异常和签名错误FAQ | 20171010 | 2.4 |
| 文档markdown,删除无用信息 | 20180813 | 2.5 |
| 支付流程变更 | 20210104 | 3.0 |
| 实名认证接口变更 | 20210510 | 3.2 |
重大提醒:
客户端5.3.0之前版本下单流程由游戏服务端发起,客户端5.3.0版本及以上由客户端直接发起下单,服务器不再需要请求原下单接口,请各游戏渠道做到版本兼容。
客户端5.3.2版本及以上实名认证请求新接口:http://yixingame.cn/sdk/user/center/info, 请各游戏渠道做到版本兼容。

参与支付流程交互的角色有:
从上面的描述中,第三方游戏仅需要关心以下部分流程:

流程说明
由流程图可知
第三方APP负责调用第三方Server``生成订单1.1,并处理返回值、调用支付接口。用户支付完成后,SDK回调接口返回支付结果2.7给第三方APP第三方Server负责生成订单,并将订单信息持久化到数据库。第三方Server负责处理支付通知,并对支付成功的订单进行发货、更改数据库状态,在支付成功后,PayServer通过异步发送支付通知4.1通知第三方Server发货,第三方Server自行进行发货。流程注意点

必须
传递用户的access_token,用于提取用户名、验证。
任一步
都可能中断,要保证最终数据的一致性、正确。比如悬挂订单最终要超时。
任一步
都要签名,防篡改、欺骗、重放。
任一步
都有可能多次重复调用,被调用者负责去重。服务器端接口包括第三方Server、PayServer提供给对方和Android客户端的接口。主要包括订单生成、支付通知两类接口。考虑到安全性,除了用户输入、UI交互接口需要在Android端完成,其他跟支付有关的接口必须在服务器端进行调用。签名由服务器端进行,公钥不要暴露在Android端。
第三方Server需要对订单信息包括订单id、支付状态、各类时间戳等信息、接口参数使用数据库进行持久化用来对账。
支付完成后Payserver调用第三方Server接口通知发货,相同订单支付通知接口可能被调用多次,需要去重并避免重复发货等问题。如更新数据库时可以使用类似的SQL:
update Trade set PayState=Payed where PayState=UnPay and Id=?;

很重要
我方需要两个公钥一个私钥。请谨记括号里面的名字。

游戏方公钥
或
游戏方私钥
)


平台公钥
)30819f300d06092a864886f70d010101050003818d0030818902818100ac1b8d63bcaf49cdd0d1e79c916aba0250421b3ee8eaf134f80843c5033e30a150b9e26e78025fde8e52538d4beb572940966b0c80460d90a26c9119a0d28c4277024dbeb20e31403360aeca70da506a19d89e95512e5347be0eae9b2c49da3150a93e3bc80817fa9a1d8170555e6117c86f84f13afc39944fb6bdfc85e3723b0203010001

非常重要
绝大部分平台接入失败都卡在签名这一步,请仔细阅读下面各点。
String param = URLEncoder.encode("2014-01-01 12:12:12", "UTF-8");, 输出为2014-01-01+12%3A12%3A12第三方Server接收PayServer的支付通知回调接口的sign签名字段操作
字符串拼接 (参与签名计算的参数会在每个接口中进行说明)
需要、需要、需要
进行URLEncodeAndroid Demo工程的类im.yixin.game.demo.rsa.RSA中的RSA.verify()接口和
平台公钥
以及上述拼接字符串验证sign参数是否正确,正确再执行业务逻辑// 生成签名 需要哪些参数请仔细看每个接口的说明
StringBuilder signSrcSb = new StringBuilder();
signSrcSb.append(v);
signSrcSb.append(thirdpart_orderid);
signSrcSb.append(thirdpart_ordertime);
signSrcSb.append(tradeName);
signSrcSb.append(access_token);
// 如果goodscount为1或不传则不需要添加此项
if (goodscount > 1L) {
signSrcSb.append(goodscount);
}
// 需不需要Encode,参考每个接口的说明,每个都不一样,请仔细看,不需要的话直接用
// String signSrc = signSrcSb.toString(); 即可
String signSrc = URLEncoder.encode(signSrcSb.toString(), "UTF-8");
// 注意看接口说明,一般情况生成签名用privateKey,验证签名用publicKey
PrivateKey privateKey = RSA.getPrivateKey("游戏方私钥");
String sign = RSA.sign(privateKey, signSrc);
// 验证签名 具体需要拼接哪些参数,请查看后续接口文档
StringBuilder signSrcSb4Ret = new StringBuilder();
signSrcSb4Ret.append(retMap.get("v"));
signSrcSb4Ret.append(retMap.get("thirdpart_orderid"));
signSrcSb4Ret.append(retMap.get("thirdpart_ordertime"));
signSrcSb4Ret.append(retMap.get("result"));
signSrcSb4Ret.append(retMap.get("trade_serialid"));
signSrcSb4Ret.append(retMap.get("goodsprice"));
signSrcSb4Ret.append(retMap.get("goodsamount"));
signSrcSb4Ret.append(retMap.get("pay_url"));
if (goodscount > 1L) {
signSrcSb4Ret.append(goodscount);
}
//
PublicKey publicKey = RSA.getPublicKey("平台公钥")
// signSrcSb4Ret.toString() 查看接口文档决定此处是否需要URLEncode
// 验证失败则抛出异常
RSA.verify(publicKey, sign, signSrcSb4Ret.toString());
| 异常码 | 说明 | 用户页面提示文案 |
|---|---|---|
| -1 | 服务器内部异常。未知异常,或无需详细说明的一般性异常。 | 支付请求失败,请重试 |
| -2 | 登陆账号异常 | 账号登录失败,请重试 |
| -3 | 生成签名失败 | 生成签名失败,请重试 |
| -4 | 验证签名失败 | 验证签名失败,请重试 |
| -5 | 商品不存在 | 商品不存在,请重试 |
| -6 | 订单不存在 | 订单不存在,请重试 |
| -7 | 支付方式错误 | 支付方式错误,请重试 |
| -8 | 参数非法 | 参数非法 |
| -9 | 支付超时 | 支付超时,请重新支付 |
| -10 | 更新支付类型失败(已经有支付类型或者已经支付) | 更新支付类型失败 |
| -31 | 第三方订单号重复 | 订单重复 |
| -51 | 支付工具通知的支付状态非法 | 无效订单 |
| -101 | 服务器内部错误,数据库异常 | 支付数据请求失败,请重试 |
| -1001 | 渠道游戏的状态为停用,无法下单 | 无效订单 |
本接口为流程图中的异步发送支付通知 4.1接口。Android页面通知可能因为网络故障导致通知失败,需要PayServer多次异步通知来保证通知到第三方Server。
第三方Server可以将此接口和Android页面通知接口在同一个接口中合并处理,此接口增加了notifyid、notifytime两个参数,并且from值不一样。第三方Server需要去重,可能会重复通知,避免多次发货第三方Server响应success字符串时,PayServer停止异步通知,否则按如下时间间隔不断通知直到收到success:40秒、2分钟、5分钟、10分钟、30分钟、1小时、2小时、6小时、15小时,超过以上时间后,即使没接收到success也不再通知。第三方Server定义并填写到开发者后台的对应游戏配置中第三方ServerPayServerPOST
拼接在URL中
| 参数 | 参数名称(FulfillWithEngCharacter) | 参数说明 | 类型(字符长度) |
|---|---|---|---|
| v | 接口版本号 | String | |
| thirdpart_orderid | 第三方唯一订单id | String | |
| thirdpart_ordertime | 第三方订单下单时间 | String | |
| tradeName | 商品名称 | String | |
| result | 返回结果 | 正常0、异常时返回异常号。返回异常时其他字段可能不返回。 | int |
| trade_serialid | 支付平台订单序列号 | String | |
| goodsprice | 商品单价 | 单位元,精确到分,如0.01元 | String |
| goodsamount | 支付金额 | 单位元,精确到分,如0.01元 | String |
| paystatus | 支付结果 | 支付状态:0未支付1已支付成功2关闭。result返回0时才有此字段。 | int |
| paytime | 付款时间 | long | |
| paytooltype | 支付工具类型 | int | |
| notifyid | 通知内部id | 用于校验 | long |
| notifytime | 通知时间戳 | long | |
| from | 来源参数 | 值固定为backend |
String |
| sign | 签名 | 请先阅读2.1.4 签名校验及参数值编码,参与签名的参数 严格 依照以下顺序,中间的+表示前后字符串直接拼接,不要把+加到字符串中,拼接后![]() 需要URLEncode , v+thirdpart_orderid+thirdpart_ordertime+tradeName+result+trade_serialid+goodsprice+goodsamount+paystatus+paytime+paytooltype+notifyid+notifytime+from,使用![]() 平台公钥 进行签名验证计算 |
String |
成功处理则返回success这7个字符,失败返回fail。
获取用户信息,校验access_token有效性, 本接口无签名校验
https://yixingame.cn/api/user/infoPayServer第三方ServerGET拼接在URL中
| 参数 | 参数名称(FulfillWithEngCharacter) | 参数说明 | 类型(字符长度) |
|---|---|---|---|
| access_token | token值 | 从客户端获取的token值 | String |
JSON非1的code值都是异常返回,code一定有,errorMsg可能没有{
"code": 400,
"errorMsg": "access_token is illegal,oauthUserApp is empty"
}
code值为1| 参数 | 参数名称(FulfillWithEngCharacter) | 参数说明 | 类型 |
|---|---|---|---|
| code | 响应码 | 响应码,1为正确,其他都是异常 | int |
| userinfo | 用户信息 | code为1时有 | Object |
| accountId | 支付方用户账号 | 包含在userinfo内,支付方用户账号 | String |
| nick | 用户昵称 | 包含在userinfo内,用户昵称 | String |
| icon | 用户头像 | 包含在userinfo内,用户头像 | String |
| registerUser | 为用户是否在支付方已经实名认证 | 包含在userinfo内,是否在支付方已经实名认证 | boolean |
示例
{
"userinfo": {
"accountId": "7a950a752ca8bef6",
"nick": "yazhitest",
"icon": "http://nos.netease.com/yixinpublic/pr_tp8qsfuk8xlsyhj98qooeq==_1422263772_13102",
"registerUser": true
},
"code": 1
}