支付通知
OmniSDK 服务器在收到渠道的订单支付成功通知时,会主动调用支付通知 URL 通知游戏服务器订单支付信息
游戏通知地址根据优先级的先后,可通过以下三种方式提供:
支付时将通知地址传给 OmniSDK
提供一个用于特定版本和特定渠道的通知地址,由运营同学配置到 OmniSDK 管理后台
提供一个统一的通知地址,由运营同学配置到 OmniSDK 管理后台
游戏服务器在接收到支付通知时,应再次调用 OmniSDK 提供的订单查询接口,验证订单信息的一致性,否则一旦服务端密钥泄漏,就有可能遭受伪造订单通知攻击。
如游戏无支付需求,则无需接入支付通知。
支付通知接口
当接收到渠道的支付结果回调信息后,OmniSDK 服务端会对订单支付信息进行确认,确认后 OmniSDK 服务端会将订单支付结果信息推送到游戏服务器提供的支付订单回调地址。
此通知有重试机制。根据返回值的不同会进行指数后退重试 24 小时。若游戏服务器的返回值为 1,则判断为主动请求重试,会不断重试直到成功。
此接口的发起方为 OmniSDK 服务端,接收方为游戏服务器,游戏方提供 URL,服务器主动调用
- 接口类型为 HTTP
POST
Content-Type: application/json;charset=UTF-8
- 使用签名
参数说明
Name | Type | Max Length | Description | Must |
---|---|---|---|---|
type | String | 32 | 接口类型,固定为字符串: notify-game | Yes |
xgAppId | String | 64 | OmniSDK 分配给游戏的唯一 ID | Yes |
channelId | String | 32 | 渠道 ID | Yes |
uid | String | 128 | 用户 ID | Yes |
zoneId | String | 32 | 游戏区编号 | No |
serverId | String | 32 | 游戏服编号 | No |
roleId | String | 32 | 角色编号 | Yes |
roleName | String | 64 | 角色名称 | No |
roleLevel | String | 32 | 角色等级 | No |
roleVipLevel | String | 32 | 角色 VIP 等级 | No |
currencyName | String | 64 | 支付商品价格货币代码,如 CNY、USD(国际货币代码) | No |
productId | String | 64 | 商品编号 | Yes |
productName | String | 64 | 商品名称 | No |
productDesc | String | 128 | 商品描述 | No |
productQuantity | String | 10 | 商品数量 | No |
productUnitPrice | String | 10 | 商品单价(单位:分) | No |
totalAmount | String | 10 | 总面额(单位:分) | Yes |
paidAmount | String | 10 | 总支付金额(单位:分) | Yes |
customInfo | String | 2000 | 游戏方创建订单时自定义字段,透传给游戏服务器 | No |
ts | String | 14 | 当前时间表达式,秒级,如 20150723150028 对应 2015/7/23 15:00:28 | Yes |
gameTradeNo | String | 64 | 游戏订单号 | No |
sign | String | 40 | 详见文档签名与验签,使用 OmniSDK 分配给用游戏的服务端密钥 | Yes |
tradeNo | String | 64 | OmniSDK 订单号 | Yes |
paidTime | String | 14 | 支付时间 yyyyMMddHHmmss ,格式参考 ts 字段 | Yes |
payStatus | String | 1 | 订单支付状态: 1 表示支付成功 2 表示支付失败 | Yes |
payType | String | 20 | 订单支付类型, 内购没有此字段,网页支付:WebPay | No |
ext | String | 2000 | 参看 EXT 支付扩展参数 JSON 字段说明 | No |
EXT 支付扩展参数 JSON 字段说明:
Key | Type | Description |
---|---|---|
isSandbox | Bool | 是否是沙箱环境 |
isTrialPeriod | Bool | 是否是试用期 |
cancellationDate | String | 取消订阅时间 |
expiresDate | String | 订阅过期时间 |
paidCurrencyName | String | 实际支付的商品币种代码,如 CNY、USD(国际货币代码,游戏可利用此字段与 currencyName 进行对比做业务逻辑处理 |
返回结果
游戏服务器处理完支付通知后,应返回如下格式的 JSON 字符串
Name | Description |
---|---|
code | 返回码,0 代表成功。详情请参考错误码章节中 支付通知错误码 |
msg | 接口调用信息提示 |
请求样例
请求示例
POST foobar HTTP/1.1
Host: foobar.com
Content-Type: application/json
{
"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"
}
请求签名原始字符串
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
游戏服务端密钥及签名
密钥:aca57f8a6c494a36a516e5c282c4db87
签名:60ebcd07edf4e0563c8632c53be5af6df07f3400
返回结果
{
"code": "0",
"msg": "success"
}
注意:请动态拼接所有参数(方便以后添加新参数时自动加入签名),所有非空的参数都参与签名,值为空的参数不参与签名,按参数名字自然升序排列)
游戏支付通知返回值处理注意事项
为了避免被人网络截包篡改充值数据,需要游戏服务器收到充值通知后,按如下逻辑来实现校验充值数据,并到 OmniSDK 服务器再次验证:
如遇服务升级不能响应,则需返回
{ "code": "1" }
先要进行验证签名,不通过则需返回
{ "code": "-1" }
如果游戏保留了游戏订单但找不到对应订单时,则需返回
{ "code": "-6" }
做订单排重,如果重复则需返回
{ "code": "2" }
如果游戏保留了游戏订单,最好能够验证 OmniSDK 订单和游戏订单的一致性,如
productId
、productQuantity
、paidAmount
、uid
、roleId
,保证人、财、物是一致的,避免有人在网络截获包,同时密钥泄露时,冒充发送通知。如果验证不一致,返回{ "code": "-98" }
二次查询验证订单,如果订单不存在或者返回的订单信息不一致时,需返回
{ "code": "-98" }
如果游戏系统发生内部异常,则需返回
{ "code": "-99" }
若以上7步都正常,则返回 { "code": "0" }
订单查询验证
此接口用于游戏服务器验证收到的订单通知是否正确有效。
接口的发起方为游戏服务端,接收方为 OmniSDK 服务器,
- 接口类型为 HTTP GET
- 字符集编码为 UTF-8
- 使用签名
请求地址为:
https://a2.xgsdk.seayoo.com/pay/verify-order/{omniAppId}
其中 omniAppId
是 OmniSDK 分配的游戏编号。
参数说明
Name | Type | Max Length | Description | Must |
---|---|---|---|---|
type | String | 32 | 接口类型,固定为 verify-order | Yes |
tradeNo | String | 32 | OmniSDK 订单号 | Yes |
ts | String | 14 | 当前时间表达式,秒级,如 20150723150028 对应 2015/7/23 15:00:28 | Yes |
sign | String | 40 | 详见文档签名与验签,使用 OmniSDK 分配给用游戏的服务端密钥 | Yes |
返回结果
OmniSDK服务器处理完查询后,应返回如下格式的JSON字符串
Name | Description |
---|---|
code | 返回码,0 代表成功。详情请参考错误码章节中 查询订单错误码 |
msg | 接口调用信息提示 |
data | 订单数据 |
data 字段具体说明:
Name | Type | Max Length | Description | Must |
---|---|---|---|---|
type | String | 32 | 接口类型,固定为字符串:notify-game | Yes |
xgAppId | String | 64 | OmniSDK 分配给游戏的唯一 ID | Yes |
channelId | String | 32 | 渠道 ID | Yes |
uid | String | 128 | 用户 ID | Yes |
zoneId | String | 32 | 游戏区编号 | No |
serverId | String | 32 | 游戏服编号 | No |
roleId | String | 32 | 角色编号 | Yes |
roleName | String | 64 | 角色名称 | No |
roleLevel | String | 32 | 角色等级 | No |
roleVipLevel | String | 32 | 角色 VIP 等级 | No |
currencyName | String | 64 | 支付货币名称 | No |
productId | String | 64 | 商品编号 | Yes |
productName | String | 64 | 商品名称 | No |
productDesc | String | 128 | 商品描述 | No |
productQuantity | String | 10 | 商品数量 | No |
productUnitPrice | String | 10 | 商品单价(单位:分) | No |
totalAmount | String | 10 | 总面额(单位:分) | Yes |
paidAmount | String | 10 | 总支付金额(单位:分) | Yes |
customInfo | String | 2000 | 游戏方创建订单时自定义字段,透传给游戏服务器 | No |
ts | String | 14 | 当前时间表达式,秒级,如 20150723150028 对应 2015/7/23 15:00:28 | Yes |
gameTradeNo | String | 64 | 游戏订单号 | No |
sign | String | 40 | 详见文档签名与验签,使用 OmniSDK 分配给用游戏的服务端密钥 | Yes |
tradeNo | String | 64 | OmniSDK 订单号 | Yes |
paidTime | String | 14 | 支付时间 yyyyMMddHHmmss ,格式参考 ts 字段 | Yes |
payStatus | String | 1 | 订单支付状态: 1 支付成功,2 支付失败 | Yes |
payType | String | 20 | 订单支付类型, 内购没有此字段,网页支付:WebPay | No |
ext | String | 2000 | iOS 支付订阅扩展参数 | No |
请求样例
请求参数
tradeNo: 31602f1000000001
当前时间戳ts: 20150723150028
游戏服务端密钥: aca57f8a6c494a36a516e5c282c4db87
请求签名原始字符串及签名
请求签名源串为:tradeNo=2984456&ts=20150723150028&type=verify-order
签名为:516b7da2faa4f1c27f70209eec32a29935b8f80d
请求示例
https://a2.xgsdk.seayoo.com/pay/verify-order/2018?tradeNo=31602f1000000001&ts=20150723150028&type=verify-order&sign=516b7da2faa4f1c27f70209eec32a29935b8f80d
响应签名原始字符串及签名
响应签名源串为:channelId=ios_jinshanApple¤cyName=CNY&customInfo={"guid":"061EBC8F-EEAA-b438-23FF-5D245001D707","createtime":"1641525026","serverId":20231201}&ext={"originalTradeNo":"122j261034971318","isRefund":"1","isTrialPeriod":false,"isSandbox":false,"refundDate":"20220107053903","refundAmount":"1800"}&gameTradeNo=18337670027887102412&paidAmount=0&paidTime=20220108215058&payStatus=1&productDesc=开启初入江湖礼包,可获得10个绿玄晶、4个真元丹、3个黄金钥匙、3个黄金宝箱。&productId=jxsj3.libao.cuxiao18&productName=初入江湖礼包&productQuantity=1&productUnitPrice=0&roleId=100321&roleLevel=23&roleName=慕容军&serverId=2312&totalAmount=1800&tradeNo=122q2d1000708125&ts=20220108215058&type=notify-game&uid=ios_jinshanApple__b304cacec191f055992819__EXP_.&xgAppId=111111551&zoneId=2312
签名为: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\",\"isTrialPeriod\":true}"
}
}
注意:请动态拼接所有参数(方便以后添加新参数时自动加入签名),所有非空的参数都参与签名,值为空的参数不参与签名,按参数名字自然升序排列)
退款通知接口
用于通知游戏服务器退款结果,目前仅限于iOS
当接收到渠道的支付退款回调信息后,OmniSDK 服务端会将退款信息推送到游戏服务器提供的退款回调地址。
此通知OmniSDK有重试机制。
此接口的发起方为 OmniSDK 服务端,接收方为游戏服务器,游戏方提供 URL,OmniSDK 服务器主动调用
- 接口类型为 HTTP
POST
- Content-Type:
application/json;charset=UTF-8
- 使用签名。
参数说明
Name | Type | Max Length | Description | Must |
---|---|---|---|---|
type | String | 32 | 接口类型,固定为字符串: notify-game | Yes |
xgAppId | String | 64 | OmniSDK 分配给游戏的唯一 ID | Yes |
channelId | String | 32 | 渠道 ID | Yes |
uid | String | 128 | 用户 ID | Yes |
zoneId | String | 32 | 游戏区编号 | No |
serverId | String | 32 | 游戏服编号 | No |
roleId | String | 32 | 角色编号 | Yes |
roleName | String | 64 | 角色名称 | No |
roleLevel | String | 32 | 角色等级 | No |
roleVipLevel | String | 32 | 角色 VIP 等级 | No |
currencyName | String | 64 | 支付商品价格货币代码,如 CNY、USD(国际货币代码) | No |
productId | String | 64 | 商品编号 | Yes |
productName | String | 64 | 商品名称 | No |
productDesc | String | 128 | 商品描述 | No |
productQuantity | String | 10 | 商品数量 | No |
productUnitPrice | String | 10 | 商品单价(单位:分) | No |
totalAmount | String | 10 | 总面额(单位:分) | Yes |
paidAmount | String | 10 | 总支付金额(单位:分) | Yes |
customInfo | String | 2000 | 游戏方创建订单时自定义字段,透传给游戏服务器 | No |
ts | String | 14 | 当前时间表达式,秒级,如 20150723150028 对应 2015/7/23 15:00:28 | Yes |
gameTradeNo | String | 64 | 游戏订单号 | No |
sign | String | 40 | 详见文档签名与验签,使用 OmniSDK 分配给用游戏的服务端密钥 | Yes |
tradeNo | String | 64 | OmniSDK 订单号 | Yes |
paidTime | String | 14 | 支付时间 yyyyMMddHHmmss ,格式参考 ts 字段 | Yes |
payStatus | String | 1 | 订单支付状态: 1 表示支付成功 2 表示支付失败 | Yes |
payType | String | 20 | 订单支付类型, 内购没有此字段,网页支付:WebPay | No |
ext | String | 2000 | 参看 EXT 支付扩展参数 JSON 字段说明 | No |
EXT 支付扩展参数 JSON 字段说明:
Key | Type | Description |
---|---|---|
isRefund | String | 是否是退款, 1 表示退款 |
isSandbox | Bool | 是否是沙箱环境 |
isTrialPeriod | Bool | 是否是试用期 |
refundDate | String | 退款时间表达式,秒级,如 20150723150028 对应 2015/7/23 15:00:28 |
refundAmount | String | 退款金额 |
返回结果
游戏服务器处理完支付通知后,应返回如下格式的 JSON 字符串
Name | Description |
---|---|
code | 返回码,0 代表成功。详情请参考支付通知错误码 |
msg | 接口调用信息提示 |
请求样例
请求示例
POST foobar HTTP/1.1
Host: foobar.com
Content-Type: application/json
{
"channelId": "ios_jinshanApple",
"channelTradeNo": "6941",
"currencyName": "CNY",
"ext": {
"isRefund": "1",
"isTrialPeriod": false,
"isSandbox": false,
"refundDate": "20230917101110",
"refundAmount": "3000"
},
"gameTradeNo": "3f9636851b52c04a363cd5",
"paidAmount": "3000",
"paidTime": "20230916105714",
"payStatus": "1",
"productDesc": "首次充值可获得双倍奖励",
"productId": "10086",
"productName": "300钻石",
"productQuantity": "1",
"productUnitPrice": "30",
"roleId": "123744619726391",
"roleLevel": "111",
"roleName": "foobar",
"roleVipLevel": "2",
"serverId": "0",
"sign": "75e065ec4619dea9014a95bccf4dc6fb6",
"totalAmount": "3000",
"tradeNo": "92302e10487547",
"ts": "20230917102743",
"type": "notify-game",
"uid": "jinshan__2c02c7b8868__EXP_.",
"xgAppId": "1150",
"zoneId": "0"
}