统一游戏平台 · 03

🔌 API 规范:契约、时序与防作弊

HTTPS REST,前缀 https://api.example.cn/v1;管理端独立前缀 /admin/v1。原则:一切资产数值只在服务端产生和变更——客户端提交的是"行为与凭证",不是"结果"。

1. 通用约定

1.1 请求头

Header说明
Authorization: Bearer <jwt>登录后必带;2h 过期,SDK 自动用 refreshToken 续签并重放失败请求
X-Ts / X-Nonce / X-Sign写接口必带:sign = HMAC(secret, method+path+body+ts+nonce);服务端校验 ts±300s、nonce 于 Redis 去重(防重放)
X-Cver客户端 SDK 版本,灰度与排查用

1.2 响应包与错误码

{ "code": 0, "msg": "ok", "data": { ... } }   // code!=0 时 data 可空
code含义客户端处理
0成功
1001参数错误视为 bug 上报
1401token 失效SDK 静默刷新/重登后重放
1403签名/重放校验失败拒绝并埋点(风控信号)
1409存档版本冲突data 附服务端最新档,SDK 走冲突策略(04
1429限频退避重试;领奖类直接提示"今日次数已满"
2001余额/体力不足showUnlockChoice 双通道(05
2002奖励已领取(幂等拒绝)静默刷新状态
3001订单状态非法轮询 GET /orders 以服务端为准
4001内容安全不通过提示修改昵称/文本

2. 登录时序(code2session)

游戏(分包)          game-sdk.js            API 服务端              微信/抖音
   │ GameSDK.init()      │                     │                      │
   │────────────────────▶│ wx.login()/tt.login │                      │
   │                     │──── code ──────────▶│ POST /auth/login     │
   │                     │                     │── jscode2session ───▶│
   │                     │                     │◀─ openid/unionid ────│
   │                     │                     │ upsert identities → users
   │                     │                     │ 签发 JWT + refresh    │
   │                     │◀─ token,user,wallet,│                      │
   │                     │   hubSave,isNew ────│                      │
   │◀── ready(用户/钱包/大厅档) ──│                     │                      │
端点入参出参备注
POST /auth/loginplatform, appid, codetoken, refreshToken, user, wallet, isNew静默登录,无需用户授权;isNew 触发新手礼
POST /auth/refreshrefreshTokentoken

3. 业务端点清单

3.1 用户与配置

端点说明
GET /me用户资料 + 钱包 + streak + 未领任务红点计数(大厅一屏所需聚合)
PUT /me昵称/头像(服务端过 secCheck,4001 拒绝)
GET /games游戏库:status=online 列表 + 每款 config + updated_at(客户端按 updated_at 缓存)
GET /configsapp_configs 公开子集:公告、分享限额、活动开关、首充弹窗开关

3.2 云存档

端点入参 → 出参规则
GET /saves/{gameId}slot → {data, version, updatedAt}无档返回 version=0
PUT /saves/{gameId}{slot, data, version} → {version+1}乐观锁:版本不匹配返回 1409+服务端档;data ≤64KB;写入限频 1 次/10s/游戏(SDK 侧节流合并)

3.3 钱包 / 体力(服务端权威记账)

端点说明
GET /walletcoin/gem/energy(体力按恢复速率惰性补算后返回)
POST /wallet/consume{currency, amount, reason, gameId} 消耗(买道具/抽卡/复活);余额不足 2001;写 currency_txns
POST /energy/spend开局扣体力,返回 sessionToken(本局凭证,提交分数时必带——体力闸门与防作弊共用一个凭证)
POST /energy/refill{channel: ad | share | pay | item} 按渠道限额恢复(限额配置见 05)

3.4 排行榜

端点说明
POST /lb/{gameId}/score{score, extra, sessionToken}。服务端校验链见 §5;仅保留历史最高分(或按游戏 config 取"本季最高")
GET /lb/{gameId}?scope=global|province&season=currenttop50 + 我的排名(Redis ZSET)。留意 微信好友榜不走本 API——好友关系只能在开放数据域(子域 canvas)内渲染,服务端只提供全服/省榜;抖音同理用平台榜单能力

3.5 分享(回流发奖,详见 05

端点说明
POST /share{gameId, scene} → {shareId, copywritingId}:创建 share_records,返回文案模板序号(求助/挑衅 A/B 由服务端配置)
POST /share/visit访客侧上报 {shareId}(从分享卡 query 取得):判重(同好友当日一次)、判新用户、给分享者入账待领奖励,给访客发欢迎奖励
GET /share/{shareId}分享者轮询:回流人数/是否达成/可领奖励——用于"喊好友帮忙"弹窗的实时反馈

3.6 广告奖励

端点说明
POST /ad/event{gameId, scene, status: show|complete|abort} 漏斗埋点
POST /ad/reward{gameId, scene} 完播后领奖。留意 小游戏激励视频无服务端回调,凭据只有客户端 onClose(ended)——因此该接口必须叠加:签名 + 每场景每日限额 + 与 ad_events(show→complete) 时序一致性校验 + 风控降权,把伪造收益压到不值得

3.7 签到 / 任务 / 埋点

端点说明
POST /signin今日签到:算 streak(昨日未签且无冻结则清零)、按阶梯发奖,幂等(signins PK)
POST /signin/fix{channel: ad|pay|item} 补签(消耗断签保护);每周限 1 次广告补签
GET /tasks / POST /tasks/{id}/claim任务列表(含进度)/ 领奖(幂等)
POST /events批量埋点上报(≤50 条/次);服务端异步驱动 task_progress 与 stats 聚合

3.8 支付(M8)

客户端                    API 服务端                        平台支付
  │ POST /pay/order {productId}  │                             │
  │─────────────────────────────▶│ 校验限购→建 orders(created)   │
  │◀── {orderId, payParams} ─────│                             │
  │ 调起支付 midas / tt.pay ──────────────────────────────────▶│
  │                              │◀──── 支付回调(平台签名) ─────│
  │                              │ 验签→paid→[事务:发货+流水]→delivered→应答
  │ GET /orders/{orderId}(轮询/onShow 触发)                     │
  │─────────────────────────────▶│ status=delivered + 最新钱包   │
端点说明
POST /pay/order建单:校验商品上下架/限购(首充一次)/平台可用性(iOS 政策),返回调起支付所需参数
POST /callback/wxpay · POST /callback/ttpay平台回调:验签失败直接 4xx;重复回调按订单状态机幂等应答;发货全程单事务。红线 本路由不鉴 JWT、只鉴平台签名,且必须与业务路由隔离限频
GET /orders/{orderId} / GET /orders单笔状态 / 我的订单列表(客服口径)

3.9 管理端(/admin/v1,模块详见 07

独立 JWT 与密钥、RBAC 中间件、全写操作落 audit_logs。核心资源:/admin/v1/users · /saves · /orders · /games · /products · /configs · /lb · /stats

4. 限频总表(Redis 用户级)

接口限额超限行为
PUT /saves1 次/10s/游戏1429,SDK 本地合并后重试
POST /lb/score10 次/小时/游戏1429
POST /ad/reward按场景配置(默认 10 次/日/场景)2002 话术"今日已达上限"
POST /share/visit(同一访客)1 次/shareId;3 个不同 shareId/日静默不发奖
POST /signin/fix(ad)1 次/周引导付费补签
POST /events60 次/分钟丢弃并计数

5. 防作弊校验链(提交分数为例)

  1. 凭证:必须携带开局 POST /energy/spend 签发的 sessionToken(一次性,Redis 存开局时间)。
  2. 时长:now - 开局时间 ≥ games.config.sessionMinSec(秒杀"瞬间高分"脚本)。
  3. 上限:score ≤ games.config.scoreMax;超限拒绝并 risk_level+1。
  4. 速率:分数增幅相对该用户历史分布突变(>P99.9)→ 收下分数但标记 risk,榜单延迟展示待复核(07 后台队列)。
  5. 签名与重放:X-Sign + nonce 去重。
  6. 降权:risk_level=2 用户:奖励减半、榜单匿名、进入后台复核列表——不封禁(避免误伤),先隔离影响。
设计底线:单机小游戏防作弊做不到绝对(代码在客户端),目标是让作弊拿不到经济收益、上不了榜:钱包只认服务端记账(作弊改不了钱),榜单有校验链(作弊上不了榜),广告奖励有限额(伪造刷不多)。