LCM服务端(V2版本) 接入指南
1、游戏服务端与LCM服务端交互(GS vs LS)
简体域名
- Production: https://lcm-api.mobage.cn
- Sandbox : https://lcm-api-sand.mobage.cn
繁体域名
- Production: https://lcm-api.mobage.tw
- Sandbox : https://lcm-api-sand.mobage.tw
接口签名验证:
- Game Server和LCM Server之间使用MD5延签。
- LCM系统事先线下发行consumer key和consumer secret给Game Server方,每一次Game Server通过Web API调用LCM Server的时候,都需要在Http的header里面加入 signature 头
- 以下为 signature 头部的生成方法:
1. 以method=post,接受参数为json为例;原始body参数
{
"key": "10000000", // key -> LCM 下发的consumer key
"b":"b",
"d":["a","b","c"],
"a":"a",
"c":"c",
"g":{"g":"g","f":"f"}
}
2. 将secret添加到参数中原始body参数
{
"key": "10000000",
"b":"b",
"d":["a","b","c"],
"a":"a",
"c":"c",
"secret":"dena-dev", // secret -> LCM 下发的consumer secret
"g":{"g":"g","f":"f"}
}
3. 将参数按照key升序排序,依次将key value合并; 如果value是list或者object,则递归
sign_string = aabbccdabcgffggkey10000000secretdena-dev
4. 将得到的字符串md5
md5(sign_string) = 9d1a8070bb9735c203f5e348e4c27abf
5. 将md5串作为signature字段添加到header中
1-1 登陆:AccessToken校验接口
- /game/token/validate : 指定一个accessToken,检查该accessToken是否合法
-
Method: POST
-
Request:
type value signature xxxxxxxxxxxxxx Accept application/json Content-Type application/json Request body {"key":"10000000", "accessToken": "xxx.xxx.xxx"} -
Response:
type value Content-Type application/json Response body -
Response body:
key type description key string consumer key lid long storeType string storeAccount string rnInfo int 0:未录入, 1:未成年人, 2:成年人 example:
无 realNameExceptionInfo 字段:
{
"key": "10000000",
"lid": 810801,
"storeType": "LCM_A_CN",
"storeAccount": "109900",
"rncStatus": 0,
"rnInfo": 1
}
有 realNameExceptionInfo 字段:
{
"key": "10000000",
"lid": 810801,
"storeType": "LCM_A_CN",
"storeAccount": "109900",
"rnInfo": 1,
"rncStatus": 0,
"realNameExceptionInfo": {
"code": "9992000",
"message": "not available for minor",
"trace": "192899.60.16065656803670299"
}
}
rncStatus -> 认证状态:0: 认证成功 1: 认证中。2: 认证失败 3:待认证
-
防沉迷相关异常码【
realNameExceptionInfo
】code message desc 9991900 NEED_RECORD_REAL_NAME_INFO_CAN_SKIP 需要实名且可跳过 (实名制) 9991901 NEED_RECORD_REAL_NAME_INFO_CANNOT_SKIP 需要实名且不可跳过(实名制) 9992000 not available for minor 未成年游玩时间段限制生效(防沉迷) 9992001 reached play time limit 未成年游玩总时长限制生效(防沉迷) -
状态码
status description 200 OK 400 request body is wrong 401 wrong sign 429 too many request 500 Internal Server Error
1-2 支付:消费L币接口
- bank/spend/{lid} : 消费用户的L币(lid 用户标识)
- Method: POST
-
Request:
type value signature xxxxxxxxxxxxxx Accept application/json Content-Type application/json Request body { "key":"10000000", "items":[ ],"memo":"","billingId":"abc123"} -
Response:
type value Content-Type application/json Response body {"transactionId": "hSkwNL-wQQN-qF-P-oOXhvphg", "paidAmount": 7, "freeAmount": 2,"paidBalance": 1030,"freeBalance": 10 } -
状态码
status description 200 OK 400 bad request 401 wrong sign 402 invalid parameter 402 指定的用户不存在指定的storeType的Bank信息 409 余额不足 429 too many request 500 Internal Server Error -
Example for Request body:
简洁模式(推荐):
{
"items": [{
"id": "gacha1",
"totalValue": 300,
"quantity": "1"
}, {
"id": "gacha2",
"totalValue": 200,
"quantity": "3"
}],
"memo": "可选,供游戏记录更多信息",
"billingId": "abc123:可选(最长128个字符)"
}
旧模式(继续兼容):
{
"items": [{
"id": "gacha1",
"paidValue": 100,
"freeValue": 200,
"totalValue": 300,
"quantity": "1"
}, {
"id": "gacha2",
"paidValue": 200,
"freeValue": 0,
"totalValue": 200,
"quantity": "3"
}],
"memo": "可选,供游戏记录更多信息",
"billingId": "abc123//可选(最长128个字符)"
}
-
注意:
-
1.物品价格:
- totalValue是物品的单价(对应商品配置中L币的数量),如果未传入totalValue或该值为0,则看paidValue和freeValue,如果有值,则不关心paidValue和freeValue的值;
- paidValue和freeValue加起来是物品的單價。quantity是物品的數量。
- L服務器端會計算總共這條request應該扣除多少Paid L幣和Free L幣;
paidTotal = sum(paidValue*quantity) 例子中 paidTotal = 100*1 + 200*3
即 item gacha1 和 gacha2 总的paidValue之和freeTotal = sum(freeValue*quantity)
例子中freeTotal = 200*1 + 0*3
即item gacha1 和gacha2 总的freeValue之和
-
2.余额判断:
- 有totalValue时,
totalValue>paidBalance+freeBalance
则余额不足; - 没有totalValue时,paidBalance和freeBalance分别判断
paidTotal>paidBalance
或者freeTotal>freeBalance
都会是余额不足
- 有totalValue时,
-
3.支付:
- 有totalValue时,先消费freeBalance, 后消费paidBalance
-
4.billing id:
- 该字段请务必传入LCM订单号(<福利L币及>余额消费是可能获取不到LCM订单号,请游戏自行创建一个唯一id或者传空),主要用于超时重试,如果不传会直接扣款,如果传了,第一次会扣款,重复传多次不扣款,第三方可用该字段重试一些失败的消费,不同消费操作传入全局唯一的值,同一笔消费重试时每次传入相同的值。
1-3 支付:消费L币查询接口(可选)
- bank/queryConsume/{billingId} : 消费记录查询(billingId 消费订单标识)
- Method: POST
-
Request:
type value signature xxxxxxxxxxxxxx Accept application/json Content-Type application/json Request body { "key": "10000000" } -
Response:
type value Content-Type application/json Response body {"code":"204", "message": "the consume record already exist"} code : 204表示已经存在消费记录,205表示不存在消费记录
-
状态码
status description 200 OK 400 bad request 401 wrong sign 402 invalid parameter 403 指定的用户不存在指定的storeType的Bank信息 409 余额不足 429 too many request 500 Internal Server Error ### 1-4 支付:LCM服务端异步回调接口(可选) - LCM建议游戏服务器可以向LCM提供异步回调接口,用于接收异步到账通知,在收到异步回调时考虑给用户补发道具或者物品,并做好去重操作,避免向LCM重复消费 - URL(需要游戏服务器提供)配置在LCM后台(目前只支持配置一个地址, 如需配置多地址请咨询平台同事);如下图红色框位置 - Method: POST - Request: -
1、headers:
User-Agent = MobageUA/2.0 Content-Type = application/json
-
2、Request body:
{ "lid": 406, "transaction_id": "ul8IEN-S2QP-megc-AGrNgI7g", "store_type": "APPLE", "paid_lnum": 6, "free_lnum": 0, "sku": "lcm.denachina.pickle.tire01", "status": 2, "memo": "", "sign": "65ff4b5cd481a955cf12447cbed264ac" }
-
3、签名生成方式
MD5_32(lid + transaction_id + store_type + paid_lnum + free_lnum + sku + status + consumer_secret) 以上面的请求体为例:sign = MD5_32(406ul8IEN-S2QP-megc-AGrNgI7gAPPLE60lcm.denachina.pickle.tire012999) 结果为 65ff4b5cd481a955cf12447cbed264ac
-
4、body体参数定义
name description 是否参与md5签名 lid 用户标识 是 transaction_id LCM订单号 是 store_type 渠道名称 是 paid_lnum 付费L币数量 是 free_lnum 免费L币数量 是 sku 商品编号 是 status 0:尚未回调,1:回调失败,2:回调成功 是 memo 订单详情 否 expires_date 订阅过期时间戳(apple订阅订单会传入该字段) 否 sign MD5签名 否
-
-
Response:
请求结果返回 httpcode = 200 时,表示请求游戏服务器成功;httpcode != 200 时,LCM会在12小时内重试5次
1-5 支付:苹果订阅异步回调接口(可选)
- LCM建议游戏服务器在启用APPLE订阅功能是可以向LCM提供异步回调接口,用于接收异步订阅取消通知,在收到异步回调时终止和用户的订阅关系
- URL(需要游戏服务器提供)给到平台同事配置(目前只支持配置一个地址, 如需配置多地址请咨询平台同事);或者自行配置在OPE工具的lcmadmin的app配置的模块中;
-
Method: POST
-
Request:
-
1、headers:
Content-Type = application/x-www-form-urlencoded
-
2、Request body
name description 是否参与md5签名 lid 用户标识 是 memo 用户开启订阅创建订单时游戏透传的memo字段 是 store_type 渠道名称 是 notification_type 订阅通知类型 -> 'CANCEL' 是 cancellation_date 订阅取消的Unix时间戳(单位: s) 是 sign MD5签名 否 -
3、签名生成方式
sign = MD5_32(cancellation_date + lid + memo + notification_type + store_type + secret)
-
-
Response:
请求结果返回 httpcode = 200 时,表示请求游戏服务器成功;httpcode != 200 时,LCM会重试
1-6 支付:苹果谷歌退款订单查询接口(可选)
-
LCM服务提供接口,用于返回对应游戏谷歌、苹果支付的退单用户信息(lid、store、lnum、order_id、sku、memo等)
-
/order/refund/query
-
Method: GET
-
Request:
-
1、headers
signature = MD5加密字符串
-
2、Request body
name description 是否参与md5签名 类型 queryType 查询类型,1:返回最近15分钟内的恶意退单信息,2:返回指定时间范围内的恶意退单信息,3:根据lid进行查询,不传时间范围则默认查询指定lid的最近15分钟内的恶意退单信息 是 Integer startTime 起始时间,不得超过当前时间1个月,当查询类型为2时为必传参数 是 Long endTime 截止时间,当查询类型为2时为必传参数 是 Long key LCM系统对应游戏的consumer_key 是 String lid 用户的lid,想根据用户的lid进行查询时传入 是 Long -
3、签名生成方式
步骤:
1. 将lcm下发的游戏的consumer_secret作为"secret"加入到参数中,并将所有的参数按照key升序排序,依次将key value合并
2. 将得到的字符串md5
3. 将md5串作为signature字段添加到header中
例子:以pickle为例,consumer_key为abc,consumer_secret为999
查询类型为1时:
https://lcm-api.mobage.tw/order/refund/query?queryType=1&key=abc
则:
拼接后的字符串为:
sign_string="keyabcqueryType1secret999"
md5后的字符串为:
md5(sign_string) = aa3f8bb1aff327508ccb34220f6db7ea
查询类型为2时:
https://lcm-api.mobage.tw/order/refund/query?queryType=2&startTime=1586763068&endTime=1586939994&key=abc
则:
拼接后的字符串为:
sign_string="endTime1586939994keyabcqueryType2secret999startTime1586763068"
md5后的字符串为:
md5(sign_string) = e9e9b8bc71371dd0a83a6508d0746cf3
-
Response:
-
1、Response body
name description returnCode 返回状态码,100表示返回异常,200表示返回成功 returnMsg 返回结果msg returnData 返回结果集,为json格式 totalCount 返回结果总数,为returnData内的值 data 退单信息集合,为returnData内的值 -
2、examples:
正常返回时:
{
"returnCode": 200,
"returnMsg": "successed",
"returnData": {
"data": [
{
"orderId": "HeDX88-lmTd-WBq--48ZTrS0g",
"storeType": "GOOGLE",
"lid": 1000000000058786,
"lnum": 1,
"sku": "lcm.dena_zhifu.alipay.tire01",
"memo": "from api test"
},
{
"orderId": "LdWD9O-g2TH-myar-aULkjqhw",
"storeType": "GOOGLE",
"lid": 1000000000058787,
"lnum": 1,
"sku": "lcm.dena_zhifu.alipay.tire01",
"memo": "from api test"
}
],
"totalCount": 2
}
}
异常返回时:
{
"returnCode": 100,
"returnMsg": "startTime can't beyond lately one month",
"returnData": null
}
1-7 支付:苹果谷歌促销码异步回调接口(可选)
- LCM建议游戏服务器在启用苹果谷歌促销码功能时向LCM提供异步回调接口,用于接收兑换成功的异步通知,在收到异步回调时向用户发放对应道具
-
URL(需要游戏服务器提供)给到平台同事配置(目前只支持配置一个地址);或者自行配置在OPE工具的
lcmadmin
的app配置
的额外app信息1
模块中; -
Method: POST
-
Request:
-
1、headers:
Content-Type = application/application.json
-
2、Request body
name description 是否参与md5签名 order_id 兑换后生成的LCM唯一标示 是 lid_list 可领取的用户标识列表【分隔符 , 】 是 uuid 用户设备标示 是 sku 商品编号(苹果: type=3 苹果兑换商品; 谷歌: type=0 普通商品) 是 store_type 渠道名称 是 redemption_time 兑换码兑换的时间戳 是 sign MD5签名 否 -
3、签名生成方式
sign = MD5_32(lid_list + order_id +redemption_time + sku + store_type + uuid + secret)
-
4、苹果和谷歌的区别
- 苹果 : type = 3 为特殊商品,需要在苹果后台新生成并配置于LCM后台
- 谷歌 : type = 0 为普通商品,复用应用内商品;只会推送用户在谷歌商店兑换成功的通知 (应用内兑换会按照普通商品的购买流程正常到账)
-
-
Response:
请求结果返回 httpcode = 200 时,表示请求游戏服务器成功;httpcode != 200 时,LCM会重试
1-8 注销:游戏端唤起注销功能,AccessToken校验
- auth/logOff : 注销接口,指定一个accessToken,检查该accessToken是否合法,检验合法后可唤起注销
- Method: POST
-
Request:
type value signature xxxxxxxxxxxxxx Accept application/json Content-Type application/json Request body {"key":"10000000", "accessToken": "xxx.xxx.xxx"} -
Response:
type value Content-Type application/json Response body {"redirectURL":"https://tickets-prod-cn-stage.mobage.cn/1?type=0&content=mbyYRznNR8u0Z5PhKBMx8rKcEBCNQ1DPM8FRMrsl3aLm3reGlp7h5A2GgQq4F7DGg8Yk6b4KrMwEnKx5Q/U%2BPmD4qA/BHSGk2DUGlsUF1yPNFaA6UGJuxc3C%2BekOZCDaWHIml2%2BR1pJMc04IEdChZc/woJ7yHMG4Qa9k/75k9JQRWfTt%2BaIbIYR%2BSn5LY1fb6KwjVMqxTOWPy6f4IiU5irYa0wGE58N/M41I/OZXI2A%3D&logOff=1"}
备注 :
1.Response body 返回结果中redirectURL为重定向URL,只需游戏方将redirectURL对应的网页展示出来(游戏内部通过webview打开),具体注销功能由lcm实现
2.可参考 服务器2.0接入文档中 1-1 登陆:AccessToken校验接口中的参数值
-
状态码
status description 200 OK 400 request body is wrong 401 wrong sign 429 too many request 500 Internal Server Error
2、联系方式
LCM-SERVER
邮箱:mobageplatformdev_cn@dena.jp