17 KiB
playX 调用积分商城接口说明
本文档描述 playX 平台(或 playX 侧脚本/服务)如何调用积分商城已开放的 HTTP 接口:基础约定、推荐流程、鉴权方式、请求参数与返回结构。
实现依据:config/route.php、app/api/controller/v1/Playx.php、config/playx.php。
1. 基础约定
1.1 Base URL
将下列路径拼在积分商城对外域名之后,例如:
https://{商城域名}/api/v1/mall/dailyPush
(联调时请向商城方索取正式环境与测试环境地址。)
1.2 通用响应结构(JSON)
所有接口成功或失败,响应体均为:
| 字段 | 类型 | 说明 |
|---|---|---|
code |
int | 1 表示业务成功;0 表示业务失败 |
msg |
string | 提示信息(失败时为错误原因) |
time |
int | Unix 时间戳(秒) |
data |
object/array/null | 业务数据;失败时可能为 null |
部分错误场景会通过 HTTP 状态码区分(如 401),此时 code 仍为 0,请同时判断 HTTP 状态与 code。
成功示例:
{
"code": 1,
"msg": "",
"time": 1730000000,
"data": { }
}
失败示例:
{
"code": 0,
"msg": "错误原因",
"time": 1730000000,
"data": null
}
1.3 Content-Type
- 本文档中 POST 且带 JSON Body 的接口,请使用:
Content-Type: application/json。
1.4 多语言(响应文案)
可通过请求头 lang 控制返回文案语言:
| Header | 值 | 说明 |
|---|---|---|
lang |
zh / zh-cn |
返回中文(默认) |
lang |
en |
返回英文 |
2. 使用流程(推荐)
2.1 playX 服务端 → 商城:每日数据推送(主流程)
适用于 T+1 等业务数据由 playX 服务端主动推送到积分商城。
sequenceDiagram
participant PX as playX 服务端
participant M as 积分商城
Note over PX,M: 按约定配置 HMAC 密钥
PX->>M: POST /api/v1/mall/dailyPush(JSON Body)
M-->>PX: code=1, data.accepted / deduped
- 与商城方约定 商城 Base URL 与 HMAC(
X-Signature等)密钥。 - 按 §3 构造请求并推送。
- 根据返回
data.deduped判断是否为幂等重复推送。
2.2 用户侧(H5 / 内嵌页)→ 商城:会话与业务接口
以下接口多由 用户在浏览器内打开积分商城 H5 后调用,通过 session_id(先调 verifyToken 获取)或 token(商城 muser 类 token)标识用户,不一定由 playX 后端直接调用:
POST /api/v1/mall/verifyToken:用 playX token 换商城session_idGET /api/v1/mall/assets:查询资产POST /api/v1/mall/claim:领取积分GET /api/v1/mall/items:商品列表POST /api/v1/mall/bonusRedeem/physicalRedeem/withdrawApply:兑换与提现申请GET /api/v1/mall/orders:订单列表
若 playX 后端需要代替用户调用上述接口,须同样携带有效的 session_id 或 token,并遵守同一用户身份规则(见 §4 身份说明)。
3. playX 服务端推送:Daily Push
3.1 概要
| 项目 | 值 |
|---|---|
| 方法 | POST |
| 路径 | /api/v1/mall/dailyPush |
3.2 鉴权(按商城部署配置,可组合)
推荐方案:仅启用 HMAC(当前对接采用)
商城侧配置:设置环境变量 PLAYX_DAILY_PUSH_SECRET 为非空(启用 HMAC 校验)。
HMAC 签名(必填)
当商城配置 PLAYX_DAILY_PUSH_SECRET 非空时,需同时携带:
| Header | 说明 |
|---|---|
X-Request-Id |
请求 ID(建议与 Body 内可追溯字段一致) |
X-Timestamp |
Unix 时间戳(秒,字符串) |
X-Signature |
签名(十六进制小写或大写需与实现一致,以下为十六进制字符串) |
签名原文与计算:
canonical = X-Timestamp + "\n" + X-Request-Id + "\nPOST\n/api/v1/mall/dailyPush\n" + sha256(json_body)
expected = HMAC_SHA256( canonical , PLAYX_DAILY_PUSH_SECRET )
其中 json_body 为 实际发送的 JSON 原始字符串 计算出的 SHA256(十六进制);与 PHP hash('sha256', $rawBody) 一致。
校验:hash_equals(expected, X-Signature)。
Header 填写清单(HMAC 模式)
- 必填:
X-Request-Id、X-Timestamp、X-Signature
重要注意:json_body 必须与实际发送一致
为了保证签名可验通过:用于计算 sha256 的 json_body 必须是实际发送到 HTTP body 的原始 JSON 字符串(字节级一致)。
建议:在发送端先序列化 JSON 得到字符串 rawBody,用该 rawBody 做 sha256 与 HMAC,再把同一个 rawBody 作为请求 body 发送。
3.3 Body 参数(JSON)
/api/v1/mall/dailyPush 支持 两种入参格式(按字段自动识别):
格式 A:旧版单条上报(兼容)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
request_id |
string | 是 | 本次推送请求号;响应中原样返回 |
date |
string | 是 | 业务日期,格式 YYYY-MM-DD |
user_id |
string | 是 | playX 用户 ID(幂等键之一) |
username |
string | 否 | 展示名;用于同步/创建商城侧用户资产展示信息 |
yesterday_win_loss_net |
number | 否 | 昨日净输赢;小于 0 时按配置比例计入待领取保障金(locked_points) |
yesterday_total_deposit |
number | 否 | 昨日总充值;用于计算当日可领取上限等 |
lifetime_total_deposit |
number | 否 | 历史总充值(冗余入库) |
lifetime_total_withdraw |
number | 否 | 历史总提现(冗余入库) |
格式 B:新版批量上报(你图中格式)
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
report_date |
string/number | 是 | 报表日期;可以为 Unix 秒时间戳(如 1700000000)或 YYYY-MM-DD |
member |
array | 是 | 成员列表,每个成员包含一名 playX 用户数据 |
成员元素字段:
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
member_id |
string | 是 | playX 用户 ID(幂等键之一) |
login |
string | 否 | 用户展示名 |
yesterday_total_w |
number | 否 | 昨日净输赢;小于 0 才会累加到 locked_points |
yesterday_total_deposit |
number | 否 | 昨日总充值;用于计算 today_limit |
lty_deposit |
number | 否 | 历史总充值(冗余入库) |
lty_withdrawal |
number | 否 | 历史总提现(冗余入库) |
Body 填写要求(批量模式)
- 必须有:
report_date、member(数组且至少 1 个元素)、member[].member_id。 - 允许缺省:成员的
login/yesterday_total_w/yesterday_total_deposit/lty_deposit/lty_withdrawal;缺省时按0或空字符串处理。 - 日期:
report_date传 Unix 秒会自动转换成YYYY-MM-DD;如果直接传YYYY-MM-DD也支持。
3.4 幂等
- 幂等键:
user_id+date - 重复推送:不重复入账,返回
data.deduped = true
3.5 返回 data 字段
| 字段 | 类型 | 说明 |
|---|---|---|
request_id |
string | 与请求一致 |
accepted |
bool | 是否受理成功 |
deduped |
bool | 是否为重复推送(幂等命中) |
message |
string | 说明文案 |
格式 B:批量上报的返回补充
批量模式会在 data 中增加:results。
data.results 为数组,元素字段如下:
| 字段 | 类型 | 说明 |
|---|---|---|
user_id |
string | 对应成员的 member_id |
accepted |
bool | 是否受理成功 |
deduped |
bool | 该成员是否为重复推送 |
message |
string | ok 或 duplicate input |
HTTP 401:HMAC 不通过(签名缺失/不完整/校验失败)。
3.6 请求示例
curl -X POST 'https://{商城域名}/api/v1/mall/dailyPush' \
-H 'Content-Type: application/json' \
-H 'X-Request-Id: req_1700000000_123456' \
-H 'X-Timestamp: 1700000000' \
-H 'X-Signature: <按本文档 canonical 计算出的 HMAC_SHA256>' \
-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"
}
]
}
}
4. 身份说明(session_id / token / user_id)
以下接口通过 resolvePlayxAssetIdFromRequest 解析当前用户,优先级如下:
session_id(POST/GET):对应商城表mall_playx_session,未过期则映射到mall_playx_user_asset。- 若
session_id实际是muser类型 token(历史兼容),也会按 token 解析。 token(POST/GET 或标准鉴权头):商城 token 表内类型为会员或muser且未过期时,user_id为mall_playx_user_asset.id(资产表主键)。user_id(POST/GET):- 若纯数字:视为
mall_playx_user_asset.id; - 否则:按
playx_user_id查找资产行。
- 若纯数字:视为
无法解析身份时,通常返回 401 或参数错误提示。
5. 其他接口一览(前端联调版)
下列接口统一返回
code/msg/time/data;成功通常为code=1。
除verifyToken外,其余用户接口均需携带session_id或token(见 §4)。
5.0 POST /api/v1/mall/dailyPush(后端对后端)
用途:playX 按日推送用户资产基础数据到商城(前端一般不直接调用)。
请求示例:
{
"request_id": "report_20260430",
"rows": [
{
"user_id": "U10001",
"username": "demo_user",
"yesterday_total_deposit": 1000,
"yesterday_win_loss_net": -500
}
]
}
5.1 POST /api/v1/mall/verifyToken
用途:把 playX token 换成商城 session_id。
语言 lang(响应 msg 等多语言):
- 默认中文(
zh-cn)。 - 可通过 请求头
lang、Querylang或 表单/JSON 字段lang指定:zh/ZH/zh-cn→ 中文,en/EN→ 英文(与LoadLangPack规则一致)。
前端入参约定(重要):
- 调用本接口时 仅需
token(或兼容session);不要传request_id/request_date/ 商户字段(均由商城后端生成后请求上游)。 - 建议
Content-Type: application/json,Body:{"token":"..."}。若使用 form-data(如图二),请同样只传token(及可选lang);避免缺少token键名。 - 商城请求上游回调地址时:Body 含
merchant_code、request_id、token(对端必填merchant_code);X-Request-Signature与 angpow-imports 同源算法,canonical 为merchant_code=...&request_id=...&token=...。
请求示例:
{
"token": "eyJhbGciOi..."
}
带英文响应示例(Query):
POST /api/v1/mall/verifyToken?lang=en
Content-Type: application/json
{"token":"eyJhbGciOi..."}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"user_id": "U10001",
"username": "demo_user",
"token_expire_at": "2026-04-30T16:20:00+08:00"
}
}
5.2 GET /api/v1/mall/assets
用途:查询当前用户积分资产。
请求示例:
GET /api/v1/mall/assets?session_id=fc7f3e3f0d0f4cb29f66e4c8fbab4f66
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"locked_points": 120,
"available_points": 350,
"today_limit": 200,
"today_claimed": 80,
"withdrawable_cash": 35
}
}
5.3 POST /api/v1/mall/claim
用途:领取积分(幂等)。
请求示例:
{
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"claim_request_id": "claim_20260430_0001"
}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"locked_points": 60,
"available_points": 410,
"today_limit": 200,
"today_claimed": 140,
"withdrawable_cash": 41
}
}
5.4 GET /api/v1/mall/items
用途:获取商城商品列表(可按类型筛选)。
请求示例:
GET /api/v1/mall/items?type=BONUS
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"list": [
{
"id": 101,
"title": "10 MYR Bonus",
"type": "BONUS",
"points_cost": 1000
}
]
}
}
5.5 POST /api/v1/mall/bonusRedeem
用途:兑换红利商品。
请求示例:
{
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"item_id": 101
}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"order_id": "ORD202604300001",
"status": "PENDING"
}
}
5.6 POST /api/v1/mall/physicalRedeem
用途:兑换实物商品(需要地址)。
请求示例:
{
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"item_id": 202,
"address_id": 12
}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"order_id": "ORD202604300002",
"status": "PENDING"
}
}
5.7 POST /api/v1/mall/withdrawApply
用途:发起提现档位兑换申请。
请求示例:
{
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"item_id": 303
}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"order_id": "ORD202604300003",
"status": "PENDING"
}
}
5.8 GET /api/v1/mall/orders
用途:查询当前用户订单列表。
请求示例:
GET /api/v1/mall/orders?session_id=fc7f3e3f0d0f4cb29f66e4c8fbab4f66
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"list": [
{
"order_id": "ORD202604300001",
"status": "PENDING",
"item_title": "10 MYR Bonus"
}
]
}
}
5.9 GET /api/v1/mall/pointsLogs
用途:查询积分变动日志。
请求示例:
GET /api/v1/mall/pointsLogs?session_id=fc7f3e3f0d0f4cb29f66e4c8fbab4f66
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"list": [
{
"id": 9001,
"change_points": 50,
"type": "CLAIM",
"remark": "daily claim"
}
]
}
}
5.10 收货地址(mall_address)
用途:用户收货地址 CRUD。
5.10.1 GET /api/v1/mall/addressList
请求示例:
GET /api/v1/mall/addressList?session_id=fc7f3e3f0d0f4cb29f66e4c8fbab4f66
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"list": [
{
"id": 12,
"receiver_name": "Tom",
"phone": "0123456789",
"detail_address": "KLCC",
"default_setting": 1
}
]
}
}
5.10.2 POST /api/v1/mall/addressAdd
请求示例:
{
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"receiver_name": "Tom",
"phone": "0123456789",
"region": "Kuala Lumpur,KLCC",
"detail_address": "Tower A, 8F",
"default_setting": 1
}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": {
"id": 13
}
}
5.10.3 POST /api/v1/mall/addressEdit
请求示例:
{
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"id": 13,
"detail_address": "Tower B, 10F",
"default_setting": 1
}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": null
}
5.10.4 POST /api/v1/mall/addressDelete
请求示例:
{
"session_id": "fc7f3e3f0d0f4cb29f66e4c8fbab4f66",
"id": 13
}
成功响应示例:
{
"code": 1,
"msg": "Success",
"time": 1777533000,
"data": null
}
6. 配置项(供运维/对方技术对照)
| 环境变量 / 配置 | 作用 |
|---|---|
PLAYX_DAILY_PUSH_SECRET |
非空则 Daily Push 必须带合法 HMAC 头 |
PLAYX_VERIFY_TOKEN_LOCAL_ONLY |
为 true 时 verifyToken 不请求 playX 远程 |
PLAYX_ANGPOW_IMPORT_BASE_URL |
Angpow 推送等接口基地址;相对路径 verify-token 时亦作其基地址 |
PLAYX_TOKEN_VERIFY_URL |
完整 https:// URL:回调 Body merchant_code+request_id+token,签名明文同序;相对路径:拼基地址 + 商户四字段 |
PLAYX_ANGPOW_MERCHANT_CODE |
回调与相对路径 verify-token 均需 |
PLAYX_ANGPOW_IMPORT_AUTH_KEY |
回调与相对路径的 HMAC 密钥(与 angpow-imports 相同) |
7. 版本与变更
- 文档与仓库代码同步维护;接口路径以
config/route.php为准。 - 若后续升级鉴权策略(例如叠加 JWT),以部署环境变量与最新文档为准。