Files
webman-buildadmin-mall/docs/PlayX-接口文档.md

23 KiB
Raw Blame History

PlayX 接口文档(按调用方向拆分)

说明:本文档严格依据当前代码 app/api/controller/v1/Playx.phpapp/api/controller/v1/Auth.php(临时登录)、config/playx.php 与定时任务 app/process/PlayxJobs.php 整理。

三类接口分别为:

  • 积分商城 -> PlayXPlayX 调用商城)
  • PlayX -> 积分商城(商城调用 PlayX
  • 积分商城 -> H5H5 调用商城)

1. 积分商城 -> PlayXPlayX 调用商城)

1.1 Daily Push API

  • 方法:POST
  • 路径:/api/v1/playx/daily-push

Header多语言可选

  • lang: zh/zh-cn 返回中文(默认);en 返回英文

Header签名校验HMAC 必填)

playx.daily_push_secret 配置非空时需要携带HMAC

  • X-Request-Id:请求 ID
  • X-Timestamp:时间戳
  • X-Signature签名HMAC_SHA256

服务端签名计算:

  • canonical = X-Timestamp + "\n" + X-Request-Id + "\nPOST\n/api/v1/playx/daily-push\n" + sha256(json_body)
  • expected = hash_hmac('sha256', canonical, daily_push_secret)
  • 校验:hash_equals(expected, X-Signature)

说明:

  • 本项目对接方案为 仅启用 HMAC,不使用 Authorization 头做校验。

Body

字段 类型 必填 说明
request_id string 外部推送请求号(原样返回)
date string(YYYY-MM-DD) 业务日期(入库到 mall_playx_daily_push.date
user_id string PlayX 用户 ID用于幂等入库 mall_playx_daily_push.user_id 等;服务端会映射/创建 mall_usermall_playx_user_asset
username string 展示冗余(同步到商城用户侧逻辑时使用)
yesterday_win_loss_net number 昨日净输赢(仅当 < 0 时计算新增保障金)
yesterday_total_deposit number 昨日总充值(用于计算今日可领取上限)
lifetime_total_deposit number 历史总充值
lifetime_total_withdraw number 历史总提现
格式 B新版批量上报兼容你截图

新版 body 形如:

{
  "report_date": "1700000000",
  "member": [
    {
      "member_id": "123456",
      "login": "john",
      "lty_deposit": 15230.75,
      "lty_withdrawal": 12400.50,
      "yesterday_total_w": -320.25,
      "yesterday_total_deposit": 500.00
    }
  ]
}

字段映射(服务端内部会转换成旧字段再计算):

  • report_date -> date(若为 Unix 秒则转为 YYYY-MM-DD
  • member[].member_id -> user_id
  • member[].login -> username
  • member[].yesterday_total_w -> yesterday_win_loss_net
  • member[].yesterday_total_deposit -> yesterday_total_deposit
  • member[].lty_deposit -> lifetime_total_deposit
  • member[].lty_withdrawal -> lifetime_total_withdraw

返回补充:

  • 批量模式会在 data 里增加 results[],每个成员一条结果(是否 deduped)。

幂等规则

  • 幂等键:user_id + date
  • 重复推送:不会重复入账,返回 data.deduped=true

返回Response

外层通用返回结构:{ code, msg, time, data }

成功(首次入库):

字段 类型 说明
data.request_id string 原样返回
data.accepted boolean true
data.deduped boolean false
data.message string ok

成功(重复推送):

字段 类型 说明
data.request_id string 原样返回
data.accepted boolean true
data.deduped boolean true
data.message string duplicate input

失败:

  • 当缺少必填字段code=0msg 为缺少字段错误
  • 当签名不正确HTTP 401code=0msg 为 INVALID_SIGNATURE

示例(未开启签名校验)

请求:

curl -X POST 'http://localhost:1818/api/v1/playx/daily-push' \
  -H 'Content-Type: application/json' \
  -d '{
    "request_id":"req_1001",
    "date":"2026-03-18",
    "user_id":"U123",
    "username":"demo_user",
    "yesterday_win_loss_net":-120.5,
    "yesterday_total_deposit":50,
    "lifetime_total_deposit":5000,
    "lifetime_total_withdraw":2000
  }'

响应(首次):

{
  "code": 1,
  "msg": "",
  "data": {
    "request_id": "req_1001",
    "accepted": true,
    "deduped": false,
    "message": "ok"
  },
  "time": 0
}

示例(新版批量上报)

请求:

curl -X POST 'http://localhost:1818/api/v1/playx/daily-push' \
  -H 'Content-Type: application/json' \
  -d '{
    "report_date": "1700000000",
    "member": [
      {
        "member_id": "123456",
        "login": "john",
        "lty_deposit": 15230.75,
        "lty_withdrawal": 12400.50,
        "yesterday_total_w": -320.25,
        "yesterday_total_deposit": 500.00
      }
    ]
  }'

返回(首次写入至少一个成员时的示例):

{
  "code": 1,
  "msg": "",
  "time": 0,
  "data": {
    "request_id": "report_2023-11-14",
    "accepted": true,
    "deduped": false,
    "message": "Ok",
    "results": [
      {
        "user_id": "123456",
        "accepted": true,
        "deduped": false,
        "message": "Ok"
      }
    ]
  }
}

2. PlayX -> 积分商城(商城调用 PlayX

下面这些接口由 PlayX 提供。商城侧仅按“请求参数 + 期望返回判定条件”发起调用与处理结果。
说明H5 调商城的 /api/v1/playx/verify-token 在配置 playx.verify_token_local_only=true(默认)时不会请求本节接口,而是在商城内校验 muser token远程对接 PlayX 时见 3.3 与下文 2.1

2.1 Token Verification APIPlayX 侧实现,远程验证时使用)

  • 方法:POST
  • URL${playx.api.base_url}${playx.api.token_verify_url}
    • 默认:/api/v1/auth/verify-token

请求 Body商城侧发送

字段 类型 必填 说明
request_id string 形如 mall_{uniqid}
token string 前端传入的 PlayX token

返回(期望)

商城侧校验:

  • HTTP 状态码必须为 200
  • 且响应体中必须包含 user_id

期望字段(示例):

字段 类型 说明
user_id string 必选
username string 可选
token_expire_at string 可选(能被 strtotime 解析)

示例(成功):

{
  "user_id": "U123",
  "username": "demo_user",
  "token_expire_at": "2026-04-01T12:00:00Z"
}

示例(失败):

{
  "message": "invalid token"
}

2.2 Bonus Grant API

  • 方法:POST
  • URL${playx.api.base_url}${playx.api.bonus_grant_url}
    • 默认:/api/v1/bonus/grant

请求 Body商城侧发送

字段 类型 必填 说明
request_id string 形如 mall_bonus_{uniqid}
externalTransactionId string MallPlayxOrder.external_transaction_id
user_id string PlayX 用户 ID
amount number MallPlayxOrder.amount
rewardName string mall_item.title
category string mall_item.category(默认 daily
categoryTitle string mall_item.category_title
multiplier int MallPlayxOrder.multiplier

返回(期望)

商城侧判定:

  • HTTP 状态码 200
  • data.status === "accepted"

成功时读取:

  • data.playx_transaction_id

失败时读取:

  • data.message 写入订单 fail_reason

示例accepted

{
  "status": "accepted",
  "playx_transaction_id": "PX_TX_001"
}

示例rejected

{
  "status": "rejected",
  "message": "insufficient balance"
}

2.3 Balance Credit API

  • 方法:POST
  • URL${playx.api.base_url}${playx.api.balance_credit_url}
    • 默认:/api/v1/balance/credit

请求 Body商城侧发送

字段 类型 必填 说明
request_id string 形如 mall_withdraw_{uniqid}
externalTransactionId string MallPlayxOrder.external_transaction_id
user_id string PlayX 用户 ID
amount number MallPlayxOrder.amount
multiplier int MallPlayxOrder.multiplier

返回(期望)

与 Bonus Grant 一致:

  • data.status === "accepted" -> 读取 playx_transaction_id
  • 否则 -> 读取 message 写入 fail_reason

示例accepted

{
  "status": "accepted",
  "playx_transaction_id": "PX_TX_002"
}

示例rejected

{
  "status": "rejected",
  "message": "insufficient balance"
}

2.4 Transaction Status Query API交易终态查询

  • 方法:GET
  • URL${playx.api.base_url}${playx.api.transaction_status_url}
    • 默认:/api/v1/transaction/status

Query 参数

字段 类型 必填 说明
externalTransactionId string 订单幂等键 external_transaction_id

返回(期望)

定时任务读取 data.status

  • COMPLETED:商城将订单 status 更新为 COMPLETED
  • FAILEDREJECTED:商城将订单 status=REJECTEDgrant_status=FAILED_FINAL,并退回积分
  • 失败信息取 data.message 写入订单 fail_reason

示例completed

{ "status": "COMPLETED" }

示例failed

{ "status": "FAILED", "message": "grant rejected by PlayX" }

3. 积分商城 -> H5服务端提供给 H5 的接口)

3.0 数据模型说明(与代码一致)

  • 商城用户:表 mall_user(主键 id)。
  • PlayX 资产扩展:表 mall_playx_user_asset,与 mall_user 一对一mall_user_id 唯一,playx_user_id 唯一)。
  • 对外业务 ID:接口里返回或订单里使用的 user_id 字符串多为 PlayX 侧用户 IDplayx_user_idH5 临时登录场景若尚无真实 PlayX ID会生成形如 mall_{mall_user.id} 的占位 IDtemLogin)。
  • 服务端内部Playx 控制器内部用 mall_user.id(整型)解析资产;session_id / token / user_id 会映射到该 mall_user

3.1 鉴权解析规则(resolveMallUserIdFromRequest

以下接口在服务端最终都会解析出 商城用户 mall_user.id,再按该用户查询 mall_playx_user_asset 等。

优先级(由高到低):

  1. session_idpost 优先,get 兼容)
    • mall_playx_session 中存在且未过期:用会话里的 user_id(即 playx_user_id)在 mall_playx_user_asset 反查 mall_user_id
    • 若会话无效:兼容把 session_id 参数误当作 商城 token 再试一次UUID 形态 token
  2. tokenpost / get 或请求头 ba-token / token
    • 校验 token 表:类型为会员 user 或商城临时 musermall_user 登录),未过期则 user_id 字段即为 mall_user.id
  3. user_idpost / get 兼容)
    • 纯数字:视为 mall_user.id
    • 非纯数字:视为 playx_user_id,在 mall_playx_user_asset 查找对应 mall_user_id

注意:请求参数的取值方式是 post() 优先,get() 兼容(即同字段既可传 post 也可传 get


3.2 临时登录(获取商城 token

  • 方法:GET(推荐)或 POST
  • 路径:/api/v1/temLogin
  • 开关:config/buildadmin.phpagent_auth.temp_login_enabletrue;有效期 agent_auth.temp_login_expire(秒)。

请求参数

字段 类型 必填 说明
username string 商城用户名(唯一);不存在则自动创建 mall_user

行为说明

  • mall_user 不存在:创建用户(随机占位手机号、随机密码等,与后台「商城用户」一致)。
  • 无论是否新用户:保证存在 mall_playx_user_asset 一条记录(MallPlayxUserAsset::ensureForMallUserplayx_user_id 默认 mall_{mall_user.id}(与 PlayX 真实 ID 冲突概率低)。
  • 签发 商城 token(类型 muser,非会员表 user),并签发 muser-refresh 刷新令牌。

返回(成功 data.userInfo

字段 类型 说明
id int mall_user.id
username string 用户名
nickname string username
playx_user_id string 资产表中的 playx_user_id(如 mall_12
token string 访问 H5 接口时携带
refresh_token string 调用 /api/common/refreshToken 时使用(类型 muser-refresh
expires_in int token 有效秒数

示例

curl -G 'http://localhost:1818/api/v1/temLogin' --data-urlencode 'username=demo_h5'

用户名含 + 等号时需 URL 编码(如 %2B60123456789)。


3.3 Token 验证(换 session

  • 方法:POST(推荐 GETtoken 亦可)
  • 路径:/api/v1/playx/verify-token

配置:本地验证 vs 远程 PlayX

  • 配置项:config/playx.phpverify_token_local_only(环境变量 PLAYX_VERIFY_TOKEN_LOCAL_ONLY,未设置时默认为 **1 / 开启本地验证)。
  • verify_token_local_only = true(默认)
    • 不请求 PlayX HTTP。
    • 仅接受商城临时登录 token类型 muser),校验 token 表后,根据 mall_usermall_playx_user_asset 写入 mall_playx_session
    • 返回的 data.user_idplayx_user_id(无资产记录时回退为 mall_user.id 字符串,一般 temLogin 后已有资产)。
  • verify_token_local_only = false(生产对接 PlayX
    • 需配置 playx.api.base_url,由商城向 PlayX 发起 POST 校验(见下文「远程模式」)。
    • 若未配置 base_url,返回 PlayX API not configured

请求参数

必填其一:

  • tokenBody 优先;session 兼容字段Query 也可传 token

返回(成功 data

字段 类型 说明
session_id string 写入 mall_playx_session
user_id string PlayX 用户 IDplayx_user_id,会话内与订单/推送一致)
username string 用户名
token_expire_at string ISO 字符串(服务端 date('c', expireAt)

失败:

  • token 为空HTTP 401msg=INVALID_TOKEN
  • 远程模式且 PlayX 未配置:msg=PlayX API not configured

示例(本地验证)

curl -X POST 'http://localhost:1818/api/v1/playx/verify-token' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'token=上一步TemLogin返回的token'

3.x 收货地址(mall_address

下面接口用于 H5 维护收货地址。鉴权同本章其他接口:携带 session_idtokenuser_id

3.x.1 地址列表

  • 方法:GET
  • 路径:/api/v1/playx/address/list

返回:data.list 为地址数组。

3.x.2 添加地址

  • 方法:POST
  • 路径:/api/v1/playx/address/add

Body

字段 必填 说明
phone 电话
region 地区(数组或逗号分隔字符串)
detail_address 详细地址
address 地址补充
default_setting 1 设为默认地址

3.x.3 修改地址(含设为默认)

  • 方法:POST
  • 路径:/api/v1/playx/address/edit

Bodyid 必填,其余字段按需传入更新。

3.x.4 删除地址

  • 方法:POST
  • 路径:/api/v1/playx/address/delete

Bodyid 必填。若删除默认地址,服务端会自动挑选一条剩余地址设为默认(如存在)。

远程模式(verify_token_local_only=false + 已配置 base_url

商城侧请求 URL${playx.api.base_url}${playx.api.token_verify_url}(默认路径 /api/v1/auth/verify-token)。

请求 Body商城侧发送——仅远程模式

字段 类型 必填 说明
request_id string 形如 mall_{uniqid}
token string 前端传入的 PlayX token

返回(期望)——仅远程模式

  • HTTP 状态码必须为 200
  • 且响应体中必须包含 user_id

响应(成功示例):

{
  "code": 1,
  "msg": "",
  "data": {
    "session_id": "7b1c....",
    "user_id": "U123",
    "username": "demo_user",
    "token_expire_at": "2026-04-01T12:00:00+00:00"
  }
}

3.4 用户资产Assets

  • 方法:GET
  • 路径:/api/v1/playx/assets

请求参数(鉴权)

以下任选其一即可(与 3.1 鉴权解析规则 一致):

  • session_id
  • token(或请求头 ba-token / token
  • user_id(纯数字为 mall_user.id,否则为 playx_user_id

返回(成功 data

若未找到资产:返回 0。

字段 类型 说明
locked_points int 待领取积分
available_points int 可用积分
today_limit int 今日可领取上限
today_claimed int 今日已领取
withdrawable_cash number(2) available_points * points_to_cash_ratio(保留 2 位)

示例

curl -G 'http://localhost:1818/api/v1/playx/assets' --data-urlencode 'token=上一步temLogin返回的token'

响应(示例):

{
  "code": 1,
  "msg": "",
  "time": 1712345678,
  "data": {
    "locked_points": 100,
    "available_points": 50,
    "today_limit": 200,
    "today_claimed": 80,
    "withdrawable_cash": 5.2
  }
}

3.5 领取Claim

  • 方法:POST
  • 路径:/api/v1/playx/claim

请求 Body

必填:

  • claim_request_id幂等键string唯一

鉴权:同 3.1session_id / token / user_id

返回(成功 data

用户资产 返回字段一致(资产快照)。

幂等:

  • claim_request_id 已存在:不会重复入账,直接返回当前资产快照

示例

curl -X POST 'http://localhost:1818/api/v1/playx/claim' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'claim_request_id=claim_001' \
  --data-urlencode 'token=上一步temLogin返回的token'

响应(首次领取,示例):

{
  "code": 1,
  "msg": "Claim success",
  "time": 1712345679,
  "data": {
    "locked_points": 60,
    "available_points": 90,
    "today_limit": 200,
    "today_claimed": 120,
    "withdrawable_cash": 9.0
  }
}

响应(幂等重复,示例:可能 msg 为空):

{
  "code": 1,
  "msg": "",
  "time": 1712345680,
  "data": {
    "locked_points": 60,
    "available_points": 90,
    "today_limit": 200,
    "today_claimed": 120,
    "withdrawable_cash": 9.0
  }
}

3.6 商品列表

  • 方法:GET
  • 路径:/api/v1/playx/items

请求参数

  • type(可选):BONUS | PHYSICAL | WITHDRAW

不传或空:返回 mall_item.status=1 且不过滤 type 的商品列表。

返回(成功 data

  • list:商品列表(直接返回 MallItem 的字段数组;包含扩展字段:amount/multiplier/category/category_title 等)

示例

请求:

curl -G 'http://localhost:1818/api/v1/playx/items' --data-urlencode 'type=WITHDRAW'

响应(示例):

{
  "code": 1,
  "msg": "",
  "time": 1712345685,
  "data": {
    "list": [
      {
        "id": 321,
        "title": "提现档位A",
        "type": 3,
        "score": 1000,
        "amount": 100.0,
        "multiplier": 1,
        "category": "withdraw",
        "category_title": "提现"
      }
    ]
  }
}

3.7 红利兑换Bonus Redeem

  • 方法:POST
  • 路径:/api/v1/playx/bonus/redeem

请求 Body

必填:

  • item_id:商品 ID要求 mall_item.type=BONUSstatus=1 鉴权:同 3.1session_id / token / user_id

返回(成功)

  • msgRedeem submitted, please wait about 10 minutes
  • data.order_id:订单 ID
  • data.statusPENDING

示例

curl -X POST 'http://localhost:1818/api/v1/playx/bonus/redeem' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'item_id=123' \
  --data-urlencode 'session_id=7b1c....'

响应(示例):

{
  "code": 1,
  "msg": "Redeem submitted, please wait about 10 minutes",
  "time": 1712345686,
  "data": {
    "order_id": 456,
    "status": "PENDING"
  }
}

3.8 实物兑换Physical Redeem

  • 方法:POST
  • 路径:/api/v1/playx/physical/redeem

请求 Body

必填:

  • item_id:商品 ID要求 mall_item.type=PHYSICALstatus=1
  • receiver_name:收货人
  • receiver_phone:收货电话
  • receiver_address:收货地址 鉴权:同 3.1session_id / token / user_id

返回(成功)

  • msgRedeem success
  • datanull

示例

curl -X POST 'http://localhost:1818/api/v1/playx/physical/redeem' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'item_id=200' \
  --data-urlencode 'receiver_name=张三' \
  --data-urlencode 'receiver_phone=18800001111' \
  --data-urlencode 'receiver_address=北京市朝阳区XX路XX号' \
  --data-urlencode 'session_id=7b1c....'

响应(示例):

{
  "code": 1,
  "msg": "Redeem success",
  "time": 1712345687,
  "data": null
}

3.9 提现申请Withdraw Apply

  • 方法:POST
  • 路径:/api/v1/playx/withdraw/apply

请求 Body

必填:

  • item_id:商品 ID要求 mall_item.type=WITHDRAWstatus=1 鉴权:同 3.1session_id / token / user_id

返回(成功)

  • msgWithdraw submitted, please wait about 10 minutes
  • data.order_id:订单 ID
  • data.statusPENDING

示例

curl -X POST 'http://localhost:1818/api/v1/playx/withdraw/apply' \
  -H 'Content-Type: application/x-www-form-urlencoded' \
  --data-urlencode 'item_id=321' \
  --data-urlencode 'session_id=7b1c....'

响应(示例):

{
  "code": 1,
  "msg": "Withdraw submitted, please wait about 10 minutes",
  "time": 1712345688,
  "data": {
    "order_id": 789,
    "status": "PENDING"
  }
}

3.10 订单列表

  • 方法:GET
  • 路径:/api/v1/playx/orders

请求参数(鉴权)

3.1session_id / token / user_id)。

返回(成功 data

  • list:订单列表(最多 100 条),并包含关联的 mallItem(关系对象)
  • 列表项中的 user_idPlayX 侧 playx_user_id(字符串),与 mall_playx_order.user_id 一致

示例

请求:

curl -G 'http://localhost:1818/api/v1/playx/orders' --data-urlencode 'token=上一步temLogin返回的token'

响应(示例,简化):

{
  "code": 1,
  "msg": "",
  "time": 1712345689,
  "data": {
    "list": [
      {
        "id": 456,
        "user_id": "U123",
        "type": "BONUS",
        "status": "PENDING",
        "mall_item_id": 123,
        "points_cost": 100,
        "amount": 10.0,
        "external_transaction_id": "BONUS_ORD2026....",
        "grant_status": "NOT_SENT",
        "mallItem": {
          "id": 123,
          "title": "每日红利",
          "type": 1
        }
      }
    ]
  }
}

3.11 同步额度(可选)

当前代码未实现并未注册路由:/api/v1/playx/sync-limit