平台标准接入协议

版本 v3.0 | 2026-11-06 | 平台定义协议,厂商按本协议适配 | 适用:UU跑腿游戏频道及后续租户
三条铁律
  1. 资金不碰池:订单由宿主自有收银台扣款,平台只记订单与状态,退款指令也由宿主执行。
  2. 发货只认服务端回调:前端 pay_success 事件仅用于刷新 UI,不得作为发货依据。
  3. appKey 只在服务端:任何情况下不得写入 H5、JS、客户端包或日志。

1. 接入角色与链路

宿主 App → 游戏大厅(同源 H5)→ SDK → 宿主收银台 → 平台订单中心 → CP 游戏服务器发货。

玩家点击购买
  → SDK.pay / CP 服务端 /sdkopen/order/create     创建订单(CREATED)
  → 宿主收银台扣款,回调 POST /api/host/notify    订单(PAID)
  → 平台按标准协议 POST {DeliverURL}              订单(DELIVERED)
  → 失败自动进入 9 次递增重试队列 → 死信人工补偿
  → 租户财务发起退单 → 宿主退款 → 订单(REFUNDED / PARTIAL_REFUNDED)
  → 次月 10 号按订单费率快照生成结算单

2. 签名算法(v1,MD5)

参与签名的字段按 key 升序 排列,用 k=v 以 & 拼接,末尾追加 &key=md5(appKey),再对整串取 MD5(小写 hex)。

raw = "amount=600&appId=guess&cpOrderId=CP001&playerId=P001&productId=diamond_1&key=" + md5(appKey)
sign = md5(raw)

密钥轮换期间平台同时接受新旧两把 key 验签(双 key 并行),但签名生成始终只用新 key,厂商可平滑切换。

v2 规划为 HMAC-SHA256,按应用配置切换版本,旧协议保持兼容。当前所有接口使用 v1。

3. 服务端接口(CP 游戏服务器调用,需 appKey 签名)

接口用途关键参数
POST /api/cp/pay/create创建支付单appId / playerId / cpOrderId / productId / amount(分) / sign,可选 tenant_code
GET /api/cp/order订单查询orderId 或 cpOrderId + appId
POST /api/cp/deliver/retry申请重发发货回调orderId
POST /api/sdkopen/token/verify校验玩家 tokentoken / appId / sign
POST /api/sdkopen/user/profile、/user/check玩家档案 / 存在性playerId / appId / sign
POST /api/sdkopen/role/query角色查询playerId / appId / sign
POST /api/sdkopen/order/create、/order/query、/order/confirm下单 / 查单 / 确认同上 + 订单字段
POST /api/sdkopen/deliver/retry发货重试orderId / sign
tenant_code(v3 新增,可选)

创建订单时若传 tenant_code,平台会校验它与 appId 所属租户一致,不一致直接拒绝。响应中也返回该字段。用于未来放开「跨租户同名 appId」时消除路由歧义;当前业务层仍保证 appId 全局唯一。

4. 发货回调标准(平台 → CP)

平台向租户后台登记的 DeliverURL 发起 application/x-www-form-urlencoded POST:

orderId=O...&playerId=P...&orderFee=600

厂商服务端必须返回纯文本 success(大小写不敏感)才算成功,其余任何响应或超时均视为失败。

生产环境若未登记 DeliverURL,平台不会把订单标记为已发货,而是进入重试队列并最终转死信,由租户运营人工补偿。开发环境保留「空地址直接成功」的演示语义。

重试序列:5s / 15s / 30s / 1m / 3m / 10m / 30m / 60m / 2h,共 9 次;每次尝试写 delivery_logs;死信可在租户后台改地址后重发或标记线下已处理。

5. 客户端 SDK(H5)

引入同源 /sdk/sdk.js,全局对象 SaaSGameSdk:

SaaSGameSdk.init({ appId: 'guess' })
SaaSGameSdk.login()                 // 宿主免登优先,外部浏览器降级 OAuth
SaaSGameSdk.reportRole({ roleId, roleName, roleLevel, serverId, serverName })
SaaSGameSdk.pay({ productId, productName, amount, cpOrderId })
SaaSGameSdk.getOrder(orderId)
SaaSGameSdk.createTicket({ subject, content })

同源是硬性要求:SDK、大厅、游戏页共享 localStorage 中的玩家 token,因此静态资源由 Go 单进程托管,不单独部署前端域名。聊天上报走 POST /api/sdk/chat。

6. 订单状态机

CREATED → PAYING → PAID → DELIVERED
                    └→ PARTIAL_REFUNDED → REFUNDED

支付回调幂等:重复回调因状态机被拒绝;发货由队列保证最终一致。订单记录 user_id、refunded_amount 与 fee_rate_snapshot(下单瞬间的三方分账费率 JSON)。

7. 分账与结算(决策 18 / 24)

按应用配置平台技术服务费 / 租户分成 / CP 分成,单位万分比,合计必须 = 10000(默认 1000 / 1000 / 8000)。

8. 错误码

码含义
0成功
1001 / 1002 / 1003 / 1004 / 1005参数错误 / 未登录 / 无权限 / 资源不存在 / 服务内部错误
2001 ~ 2004账号密码错误 / 宿主凭证无效 / 凭证过期 / 签名校验失败
3001 ~ 3003应用不存在 / 已停用 / appKey 无效
4001 ~ 4005订单不存在 / 状态不合法 / 金额不一致 / 重复订单 / 渠道未就绪
5001 ~ 5003礼包码无效 / 已使用 / 已领完
6001 ~ 6003任务不存在 / 未完成 / 奖励已领取

9. 联调自检清单(厂商可独立完成)

  1. 厂商后台 →「SDK 接入」查看 appId / appKey(明文需二次确认,会记审计)。
  2. 「签名工具」用同一组参数比对本地实现与平台输出是否逐字一致。
  3. 「沙箱联调」执行一键模拟支付成功 / 失败,检查订单状态与发货响应。
  4. 登记真实 DeliverURL,用「重放回调」验证服务端是否返回 success。
  5. 检查「接入自检清单」所有项为通过;失败项按说明补齐。
  6. 提交应用审核 → 租户审核通过 → 上架。
自检通过后即可进入生产联调。生产需:真实 HOST_VERIFY_URL / HOST_REFUND_URL、每应用登记 DeliverURL、APP_ENV=production、ALLOW_TENANT_PARAM=0、关闭演示发货语义。

10. 安全与合规

配套文档:docs/00-总体方案.md(业务与决策)、docs/01-Go技术架构.md(工程)、docs/02-...规划.md(隔离与装修)、docs/03-...落地.md(上线加固)、docs/04-SDK接入文档(CP版).md(SDK 与 OpenAPI)、docs/05-...闭环.md(资金闭环与运营补齐)。