此文档是西瓜SDK支付通知接口接入文档。包括如下2个接口:
西瓜订单服务器在收到渠道的订单成功支付通知时,会主动调用支付通知URL通知游戏服务器订单支付信息。
游戏服务器在接收到支付通知时,应再次调用西瓜提供的订单查询接口,验证订单信息的一致性,否则一旦服务端密钥泄漏,就有可能遭受伪造订单通知攻击。
注意: 如游戏无支付要求,则无需接入。
发起方 | 西瓜SDK服务端 |
接收方 | 游戏服务器 |
接口类型 | HTTP POST Content-Type: application/json;charset=UTF-8 |
字符集编码 | UTF-8 |
安全机制 | 签名 |
请求地址 | 游戏方提供URL,西瓜SDK服务器主动调用 |
功能描述 | 当接收到渠道的支付结果回调信息后,西瓜SDK服务端会对订单支付信息进行确认,确认后,西瓜SDK服务端会将订单支付结果信息推送到游戏服务器提供的支付订单回调地址。 |
参数说明: 参数为一个JSON字符串
参数 | 参数类型 | 最大长度 | 说明 | 必须 |
type | String | 32 | 接口类型,固定为notify-game | 是 |
xgAppId | String | 64 | 西瓜SDK分配给游戏的唯一ID 去西瓜Web控制台查看我的xgAppId | 是 |
channelId | String | 32 | 渠道ID | 是 |
uid | String | 128 | 用户ID | 是 |
zoneId | String | 32 | 游戏区编号 | 否 |
serverId | String | 32 | 游戏服编号 | 否 |
roleId | String | 32 | 角色编号 | 是 |
roleName | String | 64 | 角色名称 | 否 |
roleLevel | String | 32 | 角色等级 | 否 |
roleVipLevel | String | 32 | 角色VIP等级 | 否 |
currencyName | String | 64 | 支付货币名称 | 否 |
productId | String | 64 | 商品编号 | 是 |
productName | String | 64 | 商品名称 | 否 |
productDesc | String | 128 | 商品描述 | 否 |
productQuantity | int | 10 | 商品数量 | 否 |
productUnitPrice | int | 10 | 商品单价(单位分) | 否 |
totalAmount | int | 10 | 总面额(单位分) | 是 |
paidAmount | int | 10 | 总支付金额(单位分) | 是 |
customInfo | String | 2000 | 游戏方创建订单时自定义字段,透传给游戏服务器 | 否 |
ts | String | 14 | 当前时间戳,秒级,如20150723150028 对应2015/7/23 15:00:28 | 是 |
gameTradeNo | String | 64 | 游戏订单号 | 否 |
sign | String | 40 | 签名,签名算法参见签名章节,使用游戏服务端密钥 | 是 |
tradeNo | String | 64 | 西瓜订单号 | 是 |
paidTime | String | 14 | 支付时间 yyyyMMddHHmmss | 是 |
payStatus | String | 1 | 订单支付状态 1 支付成功 2 支付失败 | 是 |
payType | String | 20 | 订单支付类型, 内购没有此字段,网页支付:WebPay | 否 |
ext | String | 2000 | ios 支付订阅扩展参数 | 否 |
游戏服务器处理完支付通知后,应返回如下格式的JSON字符串:
参数 | 说明 |
code | 返回码,0代表成功。详情参考错误码章节 |
msg | 接口调用信息提示 |
请求参数:
type=notify-game
xgAppId=2018
channelId=mi
uid=mi__3099245
zoneId=1
serverId=1
roleId=224455
roleName=八神
roleLevel=42
roleVipLevel=8
currencyName=CNY
productId=com.mygame.diamond600
productName=600钻石
productDesc=6元购买600钻石
productQuantity=600
totalAmount=600
paidAmount=600
customInfo=foo
gameTradeNo=20160325000001
tradeNo=31602f1000000001
paidTime=20150723145928
payStatus=1
ts=20150723150028 //当前时间戳
payType=WebPay
ext={"cancellationDate": "20160901201417","expiresDate": "20160901201417","isSandbox": true,"originalTradeNo": "016q2f1000303885"}
游戏服务端密钥: aca57f8a6c494a36a516e5c282c4db87去西瓜Web控制台查看我的游戏服务端密钥XgServerKey
则请求签名源串为:
channelId=mi¤cyName=CNY&customInfo=foo&ext={"cancellationDate": "20160901201417","expiresDate": "20160901201417","isSandbox": true,"originalTradeNo": "016q2f1000303885"}&gameTradeNo=20160325000001&paidAmount=600&paidTime=20150723145928&payStatus=1&productDesc=6元购买600钻石&productId=com.mygame.diamond600&productName=600钻石&productQuantity=600&roleId=224455&roleLevel=42&roleName=八神&roleVipLevel=8&serverId=1&totalAmount=600&tradeNo=31602f1000000001&ts=20150723150028&type=notify-game&uid=mi__3099245&xgAppId=2018&zoneId=1
(注意:请动态拼接所有参数(方便以后添加新参数时自动加入签名),所有非空的参数都参与签名,值为空的参数不参与签名,按参数名字升序排列)
签名为:
60ebcd07edf4e0563c8632c53be5af6df07f3400
请求样例:
http://172.63.55.62:18888/moon/pay
POST Body:
{"type":"notify-game", "xgAppId":"2018", "channelId":"mi", "uid":"mi__3099245", "zoneId":"1", "serverId":"1", "roleId":"224455", "roleName":"八神", "roleLevel":"42", "roleVipLevel":"8", "currencyName":"CNY", "productId":"com.mygame.diamond600", "productName":"600钻石", "productDesc":"6元购买600钻石", "productQuantity":"600", "totalAmount":"600", "paidAmount":"600", "customInfo":"foo", "gameTradeNo":"20160325000001", "tradeNo":"31602f1000000001", "paidTime":"20150723145928", "payStatus":"1", "ts":"20150723150028", "ext":"{\"cancellationDate\": \"20160901201417\",\"expiresDate\": \"20160901201417\",\"isSandbox\": true,\"originalTradeNo\": \"016q2f1000303885\"}","sign":"4873560491111c3f719dada104a0b055e2531d8f"}
{
"code": "0",
"msg": "success"
}
错误码 | 备注 |
0 | 成功 |
-1 | 签名失败 |
1 | 请求重发,表示游戏服前置机收到xg服务器通知,但是由于游戏服务器正在升级,不能处理响应,请求延后重新发送 |
2 | 重复订单,表示游戏服务器之前已收到了同样订单的通知,为避免因网络等原因导致道具或者游戏代币重复到账,建议游戏做订单排重 |
-2 | xgAppId不存在 |
-3 | channelId不存在 |
-4 | 区服不存在 |
-5 | 账号不存在 |
-6 | 订单号不存在 |
-98 | 请求参数疑似被篡改 |
-99 | 服务器内部错误 |
签名算法采用HmacSHA1
为了避免被人网络截包篡改充值数据,需要游戏服务器收到充值通知后,按如下逻辑来实现校验充值数据,并到西瓜SDK服务器再次验证。
若以上7步都正常,则返回 { "code": "0" }。
发起方: 游戏服务器
接收方: 西瓜SDK服务端
接口类型: HTTP GET
字符集编码: UTF-8
安全机制: 签名
请求地址:
http://p2.xgsdk.com/pay/verify-order/{xgAppId} 去西瓜WEB控制台查看我的xgAppId
其中xgAppId是西瓜SDK分配的游戏编号,如剑侠情缘是2018。 p2.xgsdk.com是金山云上的西瓜SDK服务器域名,接入不同的云环境有不同的域名,具体值请参考在西瓜Web控制台配置界面里的西瓜SDK接入参数。
功能描述: 用于游戏服务器验证收到的订单通知是否正确有效。
参数说明:
参数名称 | 参数类型 | 最大长度 | 说明 | 必须 |
type | String | 32 | 接口类型,固定为verify-order | 是 |
tradeNo | String | 32 | 西瓜订单号 | 是 |
ts | String | 14 | 当前时间戳,秒级,如20150723150028对应2015/7/23 15:00:28 | 是 |
sign | String | 40 | 签名,签名算法参见签名章节,使用游戏服务端密钥 | 是 |
返回结果为JSON格式的字符串,分别有如下几个字段:
字段 | 说明 |
code | 返回码,0代表成功。详情参考错误码章节 |
msg | 接口调用信息提示 |
data | 订单数据 |
data字段具体说明:
参数名称 | 参数类型 | 最大长度 | 说明 | 必须 |
type | String | 32 | 接口类型,固定为verify-order | 是 |
xgAppId | String | 64 | 西瓜SDK分配给游戏的唯一ID 去西瓜Web控制台查看我的xgAppId | 是 |
channelId | String | 32 | 渠道ID | 是 |
uid | String | 128 | 用户ID | 是 |
zoneId | String | 32 | 游戏区编号 | 否 |
serverId | String | 32 | 游戏服编号 | 否 |
roleId | String | 32 | 角色编号 | 是 |
roleName | String | 64 | 角色名称 | 否 |
roleLevel | String | 32 | 角色等级 | 否 |
roleVipLevel | String | 32 | 角色VIP等级 | 否 |
currencyName | String | 64 | 支付货币名称 | 否 |
productId | String | 64 | 商品编号 | 是 |
productName | String | 64 | 商品名称 | 否 |
productDesc | String | 128 | 商品描述 | 否 |
productQuantity | int | 10 | 商品数量 | 否 |
productUnitPrice | int | 10 | 商品单价(单位分) | 否 |
totalAmount | int | 10 | 总面额(单位分) | 是 |
paidAmount | int | 10 | 总支付金额(单位分) | 是 |
customInfo | String | 2000 | 游戏方创建订单时自定义字段,透传给游戏服务器 | 否 |
ts | String | 14 | 当前时间戳,秒级,如20150723150028 对应2015/7/23 15:00:28 | 是 |
gameTradeNo | String | 64 | 游戏订单号 | 否 |
sign | String | 40 | 签名,签名算法参见签名章节,使用游戏服务端密钥 | 是 |
tradeNo | String | 64 | 西瓜订单号 | 是 |
paidTime | String | 14 | 支付时间 yyyyMMddHHmmss | 是 |
payStatus | String | 1 | 订单支付状态 1 支付成功 2 支付失败 | 是 |
payType | String | 20 | 订单支付类型, 内购没有此字段,网页支付:WebPay | 否 |
ext | String | 2000 | ios 支付订阅扩展参数 | 否 |
请求参数:
tradeNo: 31602f1000000001
当前时间戳ts: 20150723150028
游戏服务端密钥: aca57f8a6c494a36a516e5c282c4db87 去西瓜Web控制台查看我的游戏服务端密钥XgServerKey
则请求签名源串为: tradeNo=2984456&ts=20150723150028&type=verify-order
签名为: 516b7da2faa4f1c27f70209eec32a29935b8f80d
响应签名源串为:
channelId=mi¤cyName=CNY&customInfo=foo&ext={"cancellationDate": "20160901201417","expiresDate": "20160901201417","isSandbox": true,"originalTradeNo": "016q2f1000303885"}&gameTradeNo=20160325000001&paidAmount=600&paidTime=20150723145928&payStatus=1&productDesc=6元购买600钻石&productId=com.mygame.diamond600&productName=600钻石&productQuantity=600&roleId=224455&roleLevel=42&roleName=八神&roleVipLevel=8&serverId=1&totalAmount=600&tradeNo=31602f1000000001&ts=20150723150028&type=verify-order&uid=mi__3099245&xgAppId=2018&zoneId=1
(注意:请动态拼接所有参数(方便以后添加新参数时自动加入签名),所有非空的参数都参与签名,值为空的参数不参与签名,按参数名字升序排列)
游戏服务端密钥: aca57f8a6c494a36a516e5c282c4db87 去西瓜Web控制台查看我的游戏服务端密钥XgServerKey
签名为:
8a76ba82cf1dd26b91d6cc5d86162c57b8d521c1
最终返回为:
{
"code": "0",
"msg": "success",
"data": {
"type": "verify-order",
"xgAppId": "2018",
"channelId": "mi",
"uid": "mi__3099245",
"zoneId": "1",
"serverId": "1",
"roleId": "224455",
"roleName": "八神",
"roleLevel": "42",
"roleVipLevel": "8",
"currencyName": "CNY",
"productId": "com.mygame.diamond600",
"productName": "600钻石",
"productDesc": "6元购买600钻石",
"productQuantity": "600",
"totalAmount": "600",
"paidAmount": "600",
"customInfo": "foo",
"ts": "20150723150028",
"gameTradeNo": "20160325000001",
"sign": "9986011d474d1bb6cc927b0a1c7600aa074b7e89"
"tradeNo": "31602f1000000001",
"paidTime": "20150723145928",
"payStatus": "1",
"ext":"{\"cancellationDate\": \"20160901201417\",\"expiresDate\": \"20160901201417\",\"isSandbox\": true,\"originalTradeNo\": \"016q2f1000303885\"}"
}
}
错误码 | 备注 |
0 | 成功 |
-1 | 签名失败 |
-6 | 订单号不存在 |
-99 | 西瓜SDK系统内部服务器错误 |