余额查询回调
VCT 平台在处理游戏启动请求时,查询玩家在包网(Agent)的可用余额。
说明
此接口由 VCT 平台在玩家请求启动游戏、尚未确认进入游戏前调用,用于查询包网(Agent)的可用余额并建立本次启动的临时 launch_pending 记录。包网(Agent)需实现此接口供 VCT 平台调用。
/balance 返回成功只表示余额查询和启动准备成功,不表示玩家已经进入游戏。只有 VCT 后续返回 code=0、非空 game_url 且确认同一 session_id 后,才能视为本次游戏可进入。
环境地址
| 环境 | Base URL |
|---|---|
| 生产环境 | https://hub-panel-api.v7stech.com |
| 测试环境 | https://hub-panel-api-dev.v7stech.com |
接口信息
| 属性 | 值 |
|---|---|
| 路径 | POST /api/v1/callback/balance |
| 调用方 | VCT 平台 → 包网 (Agent) |
鉴权与签名
统一 Header Token 规则见认证机制。本接口的 Body sign 使用 HMAC-SHA256(username + "." + timestamp, agent_api_secret);Header 与 Body 的 timestamp 必须完全一致。
请求参数(VCT 发送)
| 参数名 | 类型 | 必填 | 说明 |
|---|---|---|---|
username | string | 是 | 玩家用户名 |
currency | string | 是 | 货币代码 |
session_id | string | 是 | Hub 为本次游戏启动生成的唯一会话 ID |
game_id | string | 是 | Hub 游戏目录的游戏 GUID;可从已同步目录反查 Brand |
provider | string | 否 | Provider 代码,仅用于辅助核对 |
brand_guid | string | 是 | Hub Brand 稳定唯一标识,用于关联和审计 |
brand_code | string | 是 | Brand 当前业务编码,用于审计显示 |
brand_name | string | 是 | Brand 当前显示名称,用于审计显示 |
sign | string | 是 | 请求签名 |
timestamp | long | 是 | 请求时间戳 |
会话、游戏与 Brand 定位
包网必须优先以 session_id + game_id 定位本次余额请求,再通过已同步游戏目录的 game_id 反查 brand_guid。provider 只用于交叉核对,不能单独作为游戏、会话或 Brand 的唯一键。Hub 提供的 brand_guid 用于关联和审计;brand_code、brand_name 是本次请求的显示快照,不能据此合并不同 GUID 的 Brand。
响应字段
| 字段 | 类型 | 必填 | 说明 |
|---|---|---|---|
status | string | 是 | 处理状态:success(成功)/ player_not_found(玩家不存在) / error(系统错误) |
balance | decimal | 是 | 玩家当前可用余额(仅当 status 为 success 时有效) |
currency | string | 是 | 货币代码(当 status 为 success 时必填) |
username | string | 是 | 玩家用户名(当 status 为 success 时必填) |
示例请求
json
{
"username": "player001",
"currency": "MYR",
"session_id": "vct-session-uuid-001",
"game_id": "hub-game-guid-001",
"provider": "gsc",
"brand_guid": "3d3e51ba-1a7d-47b8-9dc8-3b9d99ef68fc",
"brand_code": "YB",
"brand_name": "YB Brand",
"sign": "9a2f64d0bcfa829...",
"timestamp": 1783324700
}示例响应
成功响应
json
{
"status": "success",
"username": "player001",
"currency": "MYR",
"balance": 100.00
}玩家不存在 (拦截登录)
json
{
"status": "player_not_found"
}校验逻辑与处理建议
1. 强鉴权校验
- 必须先校验
Authorization,不能只校验 Body 的sign。 agent_api_key只能匹配当前 Agent 对应的agent_api_secret,不能轮询或尝试多组 Secret。- Header timestamp 与 Body timestamp 不一致时必须拒绝。
2. 强状态校验
- 必须返回 status:包网系统返回的响应中必须包含
status字段。 - 拒绝进入游戏:若
status缺失,或其值不为"success"(例如为"player_not_found"、"error"等),VCT 平台会立即终止游戏加载流程并抛出登录异常。这避免了非合法或不存在的玩家进入游戏系统引起后续额度回收下分失败。
3. 账号状态校验建议
- 包网系统在接收到
/balance查询时,建议对玩家账号的状态(如是否冻结、是否处于限制状态等)进行评估。如状态异常导致玩家不能进行游戏,可直接返回{"status": "player_not_found"}或{"status": "error"}从而阻止游戏启动。
游戏商来源映射
| 游戏商 | 回调路径 | 请求格式 |
|---|---|---|
| BG | open.operator.user.balance | JSON-RPC 2.0(sn/sign/random) |
| GSC | seamless/balance | JSON(operator_code/sign/request_time) |
| SA | GetUserBalance | 加密 URL-encoded body |
| WM | webhook(cmd=CallBalance) | form-data(cmd/signature/user) |
AI 开发提示词(可直接复制)
text
请在当前包网项目中实现 VCT 余额查询回调 POST /api/v1/callback/balance。
这是 VCT 调用包网的服务端接口。请求包含 username、currency、session_id、game_id、provider、brand_guid、brand_code、brand_name、sign、timestamp。
实现要求:
1. 校验 Authorization: Bearer {agent_api_key}.{timestamp}.{header_signature},header_signature=HMAC-SHA256(agent_api_key + "." + timestamp, agent_api_secret),使用小写 hex。
2. Header Token timestamp 必须与 Body timestamp 完全相同并在允许时效内;使用常量时间比较签名,失败立即返回 401/业务错误。
3. 校验 Body sign=HMAC-SHA256(username + "." + timestamp, agent_api_secret)。不得尝试其他 Agent 的 Secret。
4. 按 username + currency 精确查询玩家钱包,并检查玩家、币种和账号状态;使用 decimal 类型处理金额。
5. 以 session_id + game_id 唯一定位本次启动;原样保存 session_id,并以 Agent + username + currency + session_id 建立唯一的 launch_pending 记录。由 game_id 在已同步目录反查 brand_guid;provider 仅辅助校验。保存 Hub 提供的 brand_guid、brand_code、brand_name 审计快照,不按 Code/Name 合并 Brand。
6. 成功返回 status=success、balance 和 currency;玩家不存在或不可启动时返回 player_not_found/error,阻止后续启动。
7. /balance 成功只代表启动准备完成,不得记录 enter_game,也不得永久冻结资金;等待游戏启动接口确认同一 session_id。
8. 相同 session_id 的重复请求必须幂等,不能重复锁余额或创建记录。
9. 日志不得记录 Agent Secret、完整 Token 或完整签名;记录 session_id、username、currency 和结果即可。
10. 增加测试:Header 签名、Body 签名、timestamp 不一致/过期、玩家不存在、币种不匹配、冻结账号、重复请求和 decimal 精度。
请先复用项目现有认证、钱包查询、事务和错误响应格式,完成路由、Service、幂等存储与测试。