28 KiB
0. 交付说明(给 PlayX)
- 交付物:本文件(接口清单 + 业务流程 + 联调验收清单)。
- 建议联调顺序:Token 验证(远程 PlayX 或本地
verify_token_local_only)→ 每日推送 → 领取 → 红利发放 → 提现入账 → 实物后台处理。 - 约定:接口 URL、字段最终表、签名细节以 PlayX 提供的最终口径为准;本文档负责把流程、幂等、重试与最小字段集合先对齐。
1. 文档目的与范围
本文档用于 PlayX 与积分商城(Points Mall)联调对接。范围仅包含:
- 前端:PlayX 以内嵌 Iframe 打开商城 H5,使用 postMessage 传递 token/session。
- 后端:商城后端独立部署;与 PlayX 后端通过 REST API 通讯。
- 数据同步:仅 PlayX 每日 Cron 推送(T+1)玩家数据到商城,用于计算“待领取积分/今日可领取上限”。
- 发放方式:商城在红利兑换/提现(回平台余额)下单后,直接调用 PlayX API 发放/入账;PlayX 侧每 10 分钟 Cron 执行 5.9 adjustment/最终入账。
不在本文档范围内:
- 任何实时 webhook(充值、外部积分、流水等)。
- 会员端“同步额度/同步流水”按钮触发的对接链路。
2. 系统边界与调用方向
flowchart LR
PlayXFrontend["PlayXFrontend"] -->|"postMessage(token/session)"| MallFrontend["MallFrontend(Iframe)"]
MallFrontend -->|"API(商城后端)"| MallBackend["MallBackend"]
MallBackend -->|"TokenVerificationAPI"| PlayXBackend["PlayXBackend"]
PlayXBackend -->|"DailyPushAPI(T+1)"| MallBackend
MallBackend -->|"BonusGrantAPI/BalanceCreditAPI"| PlayXBackend
当
playx.verify_token_local_only=true时,「Token 验证」一步在商城内完成,不经过PlayXBackend的 Token Verification API;详见 §4.1。
3. 关键业务对象与状态机
3.1 资产口径(最小集合)
- LockedPoints(待领取积分):由 PlayX 每日推送的“昨日输赢净额”在商城端按规则计算得到,未领取前不可消费。
- AvailablePoints(可用积分):领取后可用于兑换/提现的积分余额。
- TodayLimit(今日可领取上限):由 PlayX 每日推送的“昨日总存款”按规则计算得到。
- TodayClaimed(今日已领取):当日累计领取量(用于进度条与上限控制)。
3.2 订单类型
- BONUS:红利兑换
- PHYSICAL:实物兑换
- WITHDRAW:提现回平台余额(非现金出款)
3.3 统一订单状态
- PENDING(处理中):订单已创建,等待发放/审核/发货等后续处理
- COMPLETED(已发放):红利到账或提现入账完成
- SHIPPED(已发货):实物已发货,包含物流公司与单号
- REJECTED(已驳回):失败或人工拒绝;积分需退回(退回规则见 6.2)
4. 端到端流程(6 条)
4.1 登录鉴权(Iframe + token)
接口与字段细节以代码为准,完整说明见同目录《PlayX-接口文档.md》(§3 H5、§3.2
temLogin、§3.3verify-token)。
4.1.1 身份与数据模型(商城侧)
- 商城用户:表
mall_user(H5 临时登录、后台创建等均落此表)。 - PlayX 资产扩展:表
mall_playx_user_asset,与mall_user一对一(mall_user_id、playx_user_id均唯一)。 - 业务侧用户标识:对外接口中的
user_id(字符串)在多数场景下即playx_user_id(PlayX 玩家 ID)。- 若用户仅通过商城 临时登录 进入、尚无 PlayX 正式 ID,商城会生成占位 ID,形如
mall_{mall_user.id},与每日推送中的真实user_id区分(避免与纯数字 ID 混淆)。
- 若用户仅通过商城 临时登录 进入、尚无 PlayX 正式 ID,商城会生成占位 ID,形如
- H5 调业务接口时:服务端内部统一解析为
mall_user.id,再查资产与订单(解析规则见《PlayX-接口文档》§3.1)。
4.1.2 模式 A:联调 PlayX(生产/预发,远程校验 token)
- 用户在 PlayX 内打开积分商城入口(iframe)。
- PlayX 前端通过 postMessage 将 PlayX 下发的 token(及必要上下文)传给商城 H5。
- 商城 H5 调用商城后端
POST /api/v1/playx/verify-token,由商城向 PlayX 的 Token Verification API(playx.api.base_url+playx.api.token_verify_url)发起校验。 - 前提:配置
playx.verify_token_local_only = false,且playx.api.base_url已配置为可访问的 PlayX 基地址。 - PlayX 返回
user_id、username(及可选会话过期时间等)。 - 商城写入
mall_playx_session(session_id+ 上述user_id/username+ 过期时间),后续 H5 可用session_id或token(商城临时 token,见模式 B) 调用资产/领取等接口。
幂等与安全:
- H5 不要把 PlayX 的
user_id当作唯一可信凭据直传下单;以 token 换 session 或由商城签发 token 的流程为准。 - PlayX 侧 Token Verification API 的鉴权/签名(若有)按双方约定(可参考《PlayX-接口文档》§2.1)。
4.1.3 模式 B:本地 / 无 PlayX 环境(商城自校验,不请求 PlayX)
用于开发、联调前自测、或 PlayX 接口未就绪时:
- 配置
playx.verify_token_local_only = true(环境变量PLAYX_VERIFY_TOKEN_LOCAL_ONLY,默认可为开启,以项目config/playx.php为准)。 - 此时
/api/v1/playx/verify-token不会访问 PlayX,仅在商城内校验 商城临时 token(token 表类型muser,由下方temLogin签发)。 - 调用
GET/POST /api/v1/temLogin?username=...(需buildadmin.agent_auth.temp_login_enable = true):不存在则创建mall_user,并保证存在mall_playx_user_asset(含playx_user_id,默认mall_{id}),返回userInfo.token、playx_user_id、expires_in等。 - 再用该 token 调用
verify-token可得到session_id,与模式 A 一样供后续接口使用;或直接带token/ba-token调资产等接口(见《PlayX-接口文档》§3.1)。
4.1.4 会话续期与前端约定
- 会话续期:玩家停留时间较长时,若商城 API 返回 token/session 失效(如 401),H5 可通过 postMessage 请 PlayX 父页面 重新派发 PlayX token(模式 A);模式 B 下可重新
temLogin或走/api/common/refreshToken(muser-refresh)换取新 access token。 - 具体错误码与 Header(如
ba-token)以前端与《PlayX-接口文档》为准。
4.2 每日 T+1 入池(PlayX → 商城)
- PlayX 在每日固定时间向商城调用 Daily Push API,推送昨日玩家数据。(注:请确认并约定好
date字段对应的具体时区边界,如以 UTC+8 为准)。 - 商城按
user_id + date幂等去重入库。由于不支持通过重复推送做数据修正,若 PlayX 发现个别账单算错了,请联系商城运营在后台进行人工调账处理,勿重复推送。 - 商城计算:
- 新增保障金(待领取积分增量)
- 今日可领取上限
- 会员次日进入商城时,可在首页看到更新后的 LockedPoints 与 TodayLimit。
4.3 领取流程(Locked → Available)
- 会员在首页点击“领取”。
- 商城后端校验:LockedPoints > 0,且 TodayLimit - TodayClaimed > 0。
- 商城计算
canClaim = min(LockedPoints, TodayLimit - TodayClaimed),并原子更新:- LockedPoints -= canClaim
- AvailablePoints += canClaim
- TodayClaimed += canClaim
- 返回最新资产,前端刷新。
幂等:
- 领取操作建议使用
claim_request_id(由前端生成或后端生成返回)实现幂等,避免重复点击导致重复领取。
4.4 红利兑换(商城 → PlayX 发放)
- 会员在“红利”商品点击兑换并确认(为避免客诉,商城前端会提示会员:红利发放预计在此后约 10 分钟内入账,请耐心等待)。
- 商城创建 BONUS 订单(PENDING),并校验/扣减可用积分(原子扣减)。
- 商城调用 PlayX Bonus Grant API,传递红利发放信息(字段见 5.3)。
- 若 PlayX API 返回初步排队接收成功(HTTP 200 且
status="accepted"):- 商城订单保持 PENDING(等待 PlayX 侧 10 分钟 Cron 最终发放/入账)。
- 记录
playx_transaction_id(或外部流水号)用于后续追踪。 - 商城后端将通过调用 PlayX 的 “交易状态查询 API”(见 5.5)来轮询获取最终结果,最终确认为成功后,商城订单才会流转闭环为 COMPLETED。
- 若 PlayX API 返回失败:
- 订单保持 PENDING,并记录失败原因与下一次可重试时间
- 支持后台“手动重试”(见 6.3)
- 若经过 N 次重试仍失败或确认 PlayX 侧不可达成:订单转 REJECTED 并退回积分(见 6.2)
4.5 实物兑换(商城后台人工处理)
- 会员选择实物并填写收货信息(姓名/电话/地址)。
- 商城创建 PHYSICAL 订单(PENDING),并原子扣减可用积分。
- 后台运营:
- 发货:录入物流公司与单号 → 状态 SHIPPED
- 驳回:录入原因 → 状态 REJECTED → 自动退回积分
4.6 提现回平台余额(商城 → PlayX 入账)
- 会员在“提现到平台余额”商品点击提现并确认(前端同样需向用户提示约 10 分钟入账预期)。
- 商城创建 WITHDRAW 订单(PENDING),并原子扣减可用积分。
- 商城调用 PlayX Balance Credit API(或同一发放接口的提现模式),传入入账信息。
- 若 PlayX API 返回初步排队接收成功(HTTP 200 且
status="accepted"):- 商城订单保持 PENDING(等待 PlayX 侧 10 分钟 Cron 最终入账)。
- 记录
playx_transaction_id(或外部流水号)用于后续追踪。 - 商城后端通过「交易状态查询 API」(见 5.5)轮询获取终态,确认成功后订单才流转为 COMPLETED。
- 若 PlayX API 返回失败(非 200 或
status非accepted):失败处理同 4.4。
5. 接口清单(按调用方向)
说明:以下为接口“结构与字段清单”。具体 URL、Header、签名算法、错误码需 PlayX 提供或双方确认后固化。
5.1 PlayX → Mall:Daily Push API(每日推送)
- 目的:推送昨日玩家数据,用于 T+1 计算入池与领取上限。
- 幂等键:
user_id + date(date 建议为 PlayX 业务日) - Method/Path(建议):
POST /api/v1/playx/daily-push
请求字段说明(最小集合,来自现有资料):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
String | 是 | 请求的唯一网关流水号,商城端用于日志追踪和外层防重。 |
date |
String | 是 | 数据归属的业务日期(如 "2026-03-18"),用于限定该批数据的生效周期。 |
user_id |
String | 是 | 玩家在 PlayX 的唯一标识 ID,在此商城体系中以此作为核心绑定主键。 |
username |
String | 否 | 玩家展示名,仅用于后台日志人工可读性或冗余展示,不作业务主键。 |
lifetime_total_deposit |
Decimal | 否 | 玩家历史总充值(如有需要用于玩家 VIP 分层,当前传值保留即可)。 |
lifetime_total_withdraw |
Decimal | 否 | 玩家历史总提现(储备字段)。 |
yesterday_win_loss_net |
Decimal | 是 | 昨日净输赢金额(如果玩家亏损,应为负数)。注:务必是已扣除返点、红利、奖励、推荐佣金、VIP Bonus 的税后净额,严格代表玩家的真实净负盈利。 |
yesterday_total_deposit |
Decimal | 是 | 昨日玩家总充值金额,积分商城专门用此字段来计算“今日可领取上限(TodayLimit)”。 |
请求示例:
{
"request_id": "px_20260319_000001",
"date": "2026-03-18",
"user_id": "U123",
"username": "demo_user_01",
"lifetime_total_deposit": 5000.0,
"lifetime_total_withdraw": 2000.0,
"yesterday_win_loss_net": -120.5,
"yesterday_total_deposit": 50.0
}
响应字段说明(建议):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
String | 是 | 完全透传原请求的 request_id,便于双向日志匹配追踪。 |
accepted |
Boolean | 是 | true 标识商城已成功接收并解析了该批数据。 |
deduped |
Boolean | 是 | 若 true,标识该条数据因 user_id + date 已存在而被商城系统幂等静默丢弃(去重)。 |
message |
String | 否 | 成功或失败的补充说明(如 "ok" 或 "duplicate input" 等异常提示)。 |
响应示例:
{
"request_id": "px_20260319_000001",
"accepted": true,
"deduped": false,
"message": "ok"
}
5.2 Mall → PlayX:Token Verification API
- 目的:商城后端校验 token/session,获取可信
user_id与username。 - Method/Path(示例占位):
POST /api/v1/auth/verify-token
请求字段说明(建议):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
String | 是 | 商城系统生成的唯一请求流水号。 |
token 或 session |
String | 是 | 从带有商城的 Iframe postMessage 接收到的用户加密登录散列或临时会话凭证。 |
请求示例:
{
"request_id": "mall_20260319_9f1b6d",
"token": "eyJhbGciOi..."
}
响应字段说明(建议):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
String | 是 | 透传请求时的 request_id。 |
user_id |
String | 是 | 该凭证解密后对应的、在 PlayX 平台具有唯一性的玩家专属 ID。 |
username |
String | 否 | 该玩家显示名,用于加载商城的界面头部“欢迎:xxx”渲染。 |
token_expire_at |
String | 否 | Token 的物理过期时间(如 ISO8601),用于商城前端预判是否到了需要执行无感续期重置的底线时间。 |
响应示例:
{
"request_id": "mall_20260319_9f1b6d",
"user_id": "U123",
"username": "demo_user_01",
"token_expire_at": "2026-03-19T10:12:00Z"
}
5.3 Mall → PlayX:Bonus Grant API(红利发放)
来自 PlayX 现有字段清单(待 PlayX 确认最终口径):
请求字段说明(待 PlayX 确认最终口径):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
String | 是 | 商城发起的 HTTP 请求流水号(纯用于网关层)。 |
externalTransactionId |
String | 是 | 核心防重键:强制要求 PlayX 凭此字段做完全的幂等拦截。这是商城侧派发红利的唯一本地订单号(如 "BONUS_ORD001")。 |
user_id |
String | 是 | 要派发红利的玩家在 PlayX 的基础 ID,这需对齐每日推送。 |
memberLogin |
String | 否 | 玩家登录名(若当前 PlayX 核心接口必须传登录名,则商城会补充;若以 user_id 为准,此项可废弃)。 |
amount |
Decimal | 是 | 实际加给玩家游戏余额或红利钱包的具体现金数字。 |
rewardName |
String | 否 | 商城中对应的该红利商品名称,用于让用户后续在 PlayX 流水里看懂这笔钱从何而来。 |
description |
String | 否 | 系统行为备注说明(如 "PointsMall bonus")。 |
memberInboxMessage |
String | 否 | 是否需借调此时机向玩家发送站内站群信内容提示。 |
category |
String | 是 | 标明该红利在游戏侧的所属业务类别的枚举代码(如 daily)。 |
categoryTitle |
String | 否 | 该红利业务类别的中文展示名称。 |
multiplier (或 turnover) |
Int | 是 | 款项入账后,玩家需完成的打码流水约束倍数(如 1 倍或 5 倍)。 |
startTime / endTime |
String | 否 | 红利生效时间窗口(起止时间,视 PlayX 规则传参)。 |
请求示例:
{
"request_id": "mall_bonus_20260319_000001",
"externalTransactionId": "BONUS_ORD20260319_000001",
"user_id": "U123",
"memberLogin": "demo_user_01",
"amount": 50.0,
"rewardName": "每日回馈 50",
"description": "PointsMall bonus redemption",
"memberInboxMessage": "红利已提交,预计 10 分钟内到账",
"category": "daily",
"categoryTitle": "每日回馈",
"multiplier": 1,
"startTime": "2026-03-19T00:00:00Z",
"endTime": "2026-03-19T23:59:59Z"
}
响应字段说明(建议):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
String | 是 | 透传请求号。 |
playx_transaction_id |
String | 否 | PlayX 内部初创的接收入列单号或派发流水号,商城会将其归档以备应对极端客诉争议寻找记录用。 |
status |
String | 是 | 核心状态枚举。若为 accepted,表示请求成功列入 10 分钟 Cron,商城中止重试;其他值皆触发商城的补偿拦截网。 |
message |
String | 否 | 对入列状态的额外提示信息内容。 |
响应示例:
{
"request_id": "mall_bonus_20260319_000001",
"playx_transaction_id": "PX_TX_778899",
"status": "accepted",
"message": "queued"
}
5.4 Mall → PlayX:Balance Credit API(提现回平台余额)
字段建议与 5.3 保持结构一致,至少包含:
请求字段说明(建议与 5.3 保持结构一致):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
String | 是 | 商城下发的网络请求追溯号。 |
externalTransactionId |
String | 是 | 提现唯一单号,提现接口也需要基于此值做绝对拦截幂等功能。 |
user_id |
String | 是 | 申请提现的玩家 ID。 |
memberLogin |
String | 否 | 玩家名(视老接口历史包袱兼容)。 |
amount |
Decimal | 是 | 本次提现要充入 PlayX 主游戏平台真金余额池的具体现金。 |
multiplier (或 turnover_rule) |
Int | 是 | 本真金提现入账后的硬性流水锁定要求倍数限制。 |
description |
String | 否 | 日志源记录说明(如 "PointsMall withdraw")。 |
请求示例:
{
"request_id": "mall_withdraw_20260319_000001",
"externalTransactionId": "WITHDRAW_ORD20260319_000002",
"user_id": "U123",
"memberLogin": "demo_user_01",
"amount": 100.0,
"multiplier": 1,
"description": "PointsMall withdraw to PlayX balance"
}
响应说明与 5.3 (Bonus Grant API) 保持一致,主要接收 status="accepted" 作为暂挂确认。
{
"request_id": "mall_withdraw_20260319_000001",
"playx_transaction_id": "PX_TX_889900",
"status": "accepted",
"message": "queued"
}
5.5 Mall → PlayX:Transaction Status Query API(交易终态查询)
- 目的:红利/提现申请经 PlayX 接收后(即返回
accepted后)可能处于排队发放下款状态(如 10 分钟 Cron)。商城将通过此接口查询最终业务结果,用于闭环商城自身的 PENDING 订单。 - Method/Path(预留):
GET /api/v1/transaction/status - 传参方式:使用 Query String 传递查询主键(若 PlayX 更倾向 POST,可改为
POST+ JSON body,但需在联调前双方定稿一种即可)。
示例:
GET /api/v1/transaction/status?externalTransactionId=WITHDRAW_ORD20260319_000002GET /api/v1/transaction/status?playx_transaction_id=PX_TX_889900(与externalTransactionId二选一,推荐优先externalTransactionId)
轮询建议(商城侧):首次调用可在入队成功后约 1 分钟开始;之后间隔约 60 秒 查询一次,直至 status 为 COMPLETED 或 FAILED,或累计轮询达到约 15~20 分钟(与 10 分钟 Cron 留足余量)仍未终态则告警并转人工跟进。
请求字段说明(建议选其一作主键):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
externalTransactionId |
String | 是* | 商城之前提报请求时创建挂钩的原始提现单号,推荐此查维优先。 |
playx_transaction_id |
String | 否 | 如果之前排队响应抛出了内部派发流水,也可以持此作为二级兜底查询条件。(二选一必填) |
响应字段说明(建议):
| 字段名 | 类型 | 必填 | 说明 |
|---|---|---|---|
status |
String | 是 | 该笔资产调拨定时任务执行的彻底终态。只有两种预期终点:COMPLETED(入账成功) 或 FAILED(发放彻底阻断:如平台风控/未通过规则/账号封禁)。如果返回 PENDING 表示该 10 分钟 Cron 仍然没碰这笔单。 |
amount |
Decimal | 否 | 最后实际结算派发的精准明细金额数。 |
message |
String | 否 | 若拦截至 FAILED 终态,该字段负责说明 PlayX 端驳回的业务层原因,便于商城后端登记审计并自动回退积分。 |
6. 一致性、幂等与退回规则
6.1 幂等原则
- 每日推送:以
user_id + date去重,重复推送不得导致重复入池。 - 兑换/提现交易:以
externalTransactionId幂等(商城生成并传给 PlayX)。 - 领取:以
claim_request_id幂等,避免重复领取。
6.2 退积分规则(建议统一)
- 红利/提现:
- PlayX API 调用失败:订单保持 PENDING,进入可重试队列(不立即退积分,避免“退了但 PlayX 已受理/最终入账”的不一致)。
- 当订单被判定为“最终失败”(例如超过最大重试次数或 PlayX 返回不可恢复错误)时:订单转 REJECTED,退回积分并记录原因。
- 实物:
- 驳回必须退回积分,并记录
reject_reason。
- 驳回必须退回积分,并记录
6.3 重试与后台操作边界
- 仅允许对 “尚未收到
status = \"accepted\"响应、且可以确认未成功发放/未入账” 的订单发起重试。 - 每次重试必须生成并记录
retry_request_id与操作者审计日志。 - 强制防重约定:**PlayX 必须根据
externalTransactionId提供严格的幂等拦截能力!**由于网络请求存在“Read Timeout(读超时)”的黑盒场景,即 PlayX 实际已处理但响应由于网络中断未抵达商城,商城将会发起重试保护。如果 PlayX 不去拦截此重发单号,将必然出现给用户发双份钱的高危资损事故。
接收成功与终态闭环判定(关键约定):
- 第一步(接收排队):本系统调用发放类 API,仅当收到 HTTP 200 且
status = "accepted"时,视为 PlayX 已接收入队成功,此时商城绝不再对发放接口发起新的成功路径请求。若返回非 200、或响应超时、或未能解析出明确accepted:商城可对同一externalTransactionId进行有限次重试;PlayX 须对该单号严格幂等——重复请求不得产生第二笔发放,且应返回与首次受理一致或可识别的幂等结果(如再次返回accepted或明确DUPLICATE_REQUEST等,由双方约定响应形态)。 - 第二步(确认终态闭环):针对已入队返回 accepted 的订单,商城将调用**“交易终态查询 API”(5.5)**验证 PlayX 后台的最终发放结果实现闭环更新。
默认重试策略(建议):
- 自动重试:对
PLAYX_UPSTREAM_ERROR/超时类错误,最多 3 次(间隔 1min/5min/15min)。 - 不重试:
INVALID_SIGNATURE、REQUEST_EXPIRED、RULE_NOT_SATISFIED、INVALID_TOKEN(需要修复请求或重新鉴权)。 - 人工重试:后台按钮触发,要求输入原因并记录审计。
7. 安全要求(Shared Secret Key)
建议所有 PlayX ↔ Mall 的后端调用统一:
- Header:
X-Request-IdX-TimestampX-Signature
- 签名:使用共享
SecretKey,对 request body + timestamp + requestId 进行 HMAC(具体算法由双方定稿)。 - 时效:timestamp 允许偏差窗口(例如 5 分钟),超出拒绝。
签名建议(可直接落地的默认):
X-Signature = HMAC_SHA256(secret, canonical_string)canonical_string = X-Timestamp + \"\\n\" + X-Request-Id + \"\\n\" + HTTP_METHOD + \"\\n\" + PATH + \"\\n\" + SHA256(REQUEST_BODY_JSON)
其中:
PATH不含域名与 querystring(例如/api/v1/playx/daily-push)。REQUEST_BODY_JSON使用原始 request body(不做 key 排序时,需双方约定序列化方式;更推荐双方统一为“key 排序后的紧凑 JSON”)。
8. 错误码与可观测(建议)
最低要求:
INVALID_SIGNATUREREQUEST_EXPIREDINVALID_TOKENDUPLICATE_REQUESTINSUFFICIENT_POINTSRULE_NOT_SATISFIEDPLAYX_UPSTREAM_ERROR
错误码返回结构(建议统一):
{
"request_id": "xxx",
"code": "PLAYX_UPSTREAM_ERROR",
"message": "timeout",
"retryable": true
}
8.1 幂等:同一 externalTransactionId 重复调用(Bonus Grant / Balance Credit)
PlayX 须保证:同一 externalTransactionId 无论被调用多少次,资金侧最多只入账一次。商城在「读超时重试」或联调压测时会重复提交同一单号,响应须符合以下 两种约定之一(联调前择一写死,避免双方解析不一致)。
模式 A(推荐):再次请求仍返回 HTTP 200,且与首次受理语义一致
- 第二次及以后请求:
status仍为"accepted"(或文档约定的等价成功态),不得再次触发新的发放队列条目导致双发。 - 建议同时带回首次的
playx_transaction_id(若与首次不同,须在联调中禁止或说明兼容规则)。
{
"request_id": "mall_bonus_20260319_000099",
"playx_transaction_id": "PX_TX_778899",
"status": "accepted",
"message": "duplicate externalTransactionId, already accepted"
}
模式 B:显式重复错误码(HTTP 状态可与 PlayX 规范一致,如 200 或 409,联调前约定)
code为DUPLICATE_REQUEST(或双方统一的幂等冲突码),retryable为false,提示商城勿再重试发放接口、改查 5.5 终态。
{
"request_id": "mall_bonus_20260319_000099",
"code": "DUPLICATE_REQUEST",
"message": "externalTransactionId already processed",
"retryable": false,
"playx_transaction_id": "PX_TX_778899"
}
日志与审计:
- 每次跨系统调用必须落
request_id、入参摘要、响应摘要、耗时、结果码。
9. 联调与验收清单
9.1 鉴权
- token 正常/过期/无效/重复请求
- postMessage 未收到 token 的超时提示
9.2 每日推送
- 正常推送 1 次
- 同一
user_id+date重复推送(应 dedup) - 跨时区日期边界(按约定业务日)
9.3 领取
- locked=0 不可领取
- 上限不足部分领取
- 幂等:重复点击不重复加积分
9.4 红利/提现
- 发放接口:HTTP 200 且
status="accepted"后,订单 PENDING,记录playx_transaction_id,不再对发放接口重放(终态靠 5.5)。 - 发放接口:非 200 / 超时 / 非
accepted:失败原因落库,可自动或人工重试;PlayX 对同一externalTransactionId须严格幂等。 - 交易终态查询(5.5):按
externalTransactionId查询,验证返回COMPLETED/FAILED/PENDING;长时间PENDING走告警与人工。 - 幂等联调:同一
externalTransactionId连续发送 2 次,PlayX 侧不得重复入账,第二次响应须符合双方约定的幂等语义。
9.5 实物
- 提交收货信息
- 发货录入物流单号
- 驳回退积分并展示原因
10. 需要 PlayX 提供/确认的信息清单(用于联调收口)
- Token Verification API:URL、请求/响应字段、错误码、token 有效期/刷新策略、是否支持 session。
- Daily Push API:推送时间点、时区、date 口径(业务日还是自然日)、失败重发策略、字段定义(特别是
yesterday_win_loss_net的扣项范围)。 - Bonus Grant API / Balance Credit API:URL、鉴权签名要求、字段最终表、确认以
externalTransactionId作为拦截幂等键,以及返回的playx_transaction_id定义与查询方式。 - 交易终态查询 API(如适用):提供专门供商城拉取订单最终入账结果的查询接口 URL 及返回结构。
- 发送站内信 API(如适用):在管理后台手动处理实物商品发货/驳回时,如需通过信箱通知用户,请提供外部触发站内信的 API 渠道。
- 枚举值配置:请尽早提供发放接口中
category等字段的固定枚举值字典,以便商城后台完成商品发货配置项的落库。