Skip to content

投注数据推送回调 ​

VCT 平台批量向包网(Agent)推送投注、结算及修正流水。

说明

此接口由 VCT 平台调用包网(Agent),用于向包网系统推送或批量推送注单流水与报表数据。

注意(转账钱包模式重要事项): 在 Seamless(实时钱包)模式下,此接口是包网系统处理游戏资金变动的唯一通道。游戏期间的下注(BET)、结算(SETTLED)、额外派奖(BONUS)以及取消和回滚(CANCEL/ROLLBACK/REFUND/VOID)都会推送到此接口;包网必须按 status 对玩家主钱包执行幂等的实时扣款、加款或冲正。

环境地址 ​

环境Base URL
生产环境https://hub-panel-api.v7stech.com
测试环境https://hub-panel-api-dev.v7stech.com

接口信息 ​

属性值
路径POST /api/v1/callback/bet-push
调用方VCT 平台 → 包网 (Agent)

鉴权与签名 ​

统一 Header Token 规则见认证机制。本接口为批量注单,Body sign 使用 HMAC-SHA256(agent_api_key + "." + timestamp, agent_api_secret);Header 与 Body 的 timestamp 必须完全一致。

请求参数(VCT 发送) ​

参数名类型必填说明
operator_codestring是运营商编码
wagersarray是注单列表
wagers[].usernamestring是原始玩家用户名(已剔除 VCT 平台的前缀)
wagers[].currencystring是币种代码(如 MYR, VND, USD 等,用于精准定位玩家多币种钱包)
wagers[].session_idstring是VCT 游戏会话唯一 ID;同一会话的 BET、SETTLED 和修正日志使用同一个值
wagers[].bet_idstring是注单编号
wagers[].brand_guidstring是Brand 稳定唯一标识,与 /papi/v1/game/list、/papi/v1/game/providers 的 GUID 一致,用于关联 Brand
wagers[].brand_codestring是当前 t_brand.brand_code,不能作为全局唯一键
wagers[].brand_namestring是当前 t_brand.brand_name,用于显示
wagers[].game_codestring是游戏代码
wagers[].game_typestring是厂商原始类型,保留用于兼容;不能用于佣金分类
wagers[].game_genreinteger是从目录游戏取得的数字分类;无法唯一确认时为 0
wagers[].game_genre_namestring是2 Slot、3 Fish、4 Sport、5 Card、6 Live、7 Other;0 时为空字符串
wagers[].game_namestring是游戏名称
wagers[].bet_amountdecimal是本条流水包含的下注扣款金额
wagers[].valid_bet_amountdecimal是有效投注金额
wagers[].prize_amountdecimal是本条流水包含的派彩、奖金或退款加款金额
wagers[].win_lossdecimal是本条流水净额,正常流水按 prize_amount - bet_amount 计算;不一定等于整局最终盈亏
wagers[].statusstring是动作状态:BET / SETTLED / CANCEL / ROLLBACK / VOID / REFUND / BONUS
wagers[].bet_timestring是下注时间
wagers[].settle_timestring是结算时间
wagers[].round_idstring否统一回合/局号 ID。VCT 会将不同游戏商的局号映射至此字段,用于关联同一玩家、币种和会话中的 BET、SETTLED 及修正流水;实际关联时不要只使用 round_id。
wagers[].original_transaction_idstring否原始结算/下注交易 ID;当 status=BONUS 或取消操作时建议携带
signstring是签名
timestamplong是时间戳

Brand 身份与关联 ​

每条注单同时携带 brand_guid、brand_code、brand_name,三者从同一条有效 t_brand 主资料读取。Provider 与产品资料用于定位游戏关联的 Brand GUID;Product Code、Product Name 不能作为全局唯一键。相同 Code 或 Name、不同 GUID 的 Brand 必须分别保存。改名或修改编码保留 GUID,删除后重建会产生新 GUID。

产品可以确认 Brand,但不一定能确认具体桌台,因此 game_code、game_name 可以为空。Brand 关联缺失、已删除、存在歧义或 Provider 归属不符时,Hub 保留投送失败原因,不猜测 GUID。已投送的历史注单不会自动回填或补送。新增字段需要部署更新后的 Hub 后端才会生效。

game_genre 只从同一 Platform、Product、Game Code 匹配的目录游戏取得;若一个 Product 下所有游戏类型一致,也可返回该类型。混合类型、游戏编码不匹配或未整理时返回 0 与空名称,绝不从厂商 game_type 猜测。数字 0 的注单标记待核对,结算口径待双方确认。

/game/rates 已支持 brand_guid 精确筛选,使用注单中的 GUID 查询同一 Brand 的费率;按原业务日期传 as_of_date。原 brand 参数仅搜索当前主资料 Code / Name,不能保证唯一。

成功响应 ​

字段类型说明
receivedint成功接收条数
statusstring处理状态

推送范围建议 ​

  • 正常流水可能先推送 BET 再推送 SETTLED,也可能由一条同时包含下注和派彩金额的 SETTLED 表示
  • 默认推送 BONUS,表示额外奖金或独立赢分记录
  • CANCEL、ROLLBACK、REFUND、VOID 会通过此接口推送,用于冲正包网系统内原有的资金交易与报表结果
  • 包网正式仅需对接 /balance、/offline 和 /bet-push;取消与冲正动作会作为 bet-push 的 status 推送
  • 包网按 brand_guid 关联目录、注单归属与 Brand 佣金配置;brand_code、brand_name 用于显示,不能仅凭同名或同码合并 Brand。费率查询使用相同的 brand_guid 精确筛选

金额与玩家盈亏计算 ​

bet_amount 表示本条流水实际包含的下注扣款金额;prize_amount 表示本条流水实际包含的派彩、奖金或退款加款金额。

对于正常投注和结算流水:

text
本条流水净额 = prize_amount - bet_amount

正数表示玩家余额增加,负数表示玩家余额减少,0 表示本条流水没有产生净余额变化。包网报表若要显示整局玩家盈亏,必须汇总同一玩家、币种、session_id 和 round_id 下的相关正常流水:

text
整局玩家盈亏 = 所有相关记录的 prize_amount 合计
             - 所有相关记录的 bet_amount 合计

BET 与 SETTLED 分开推送 ​

有些游戏商先推送下注,再推送结算:

statusbet_amountprize_amount本条流水净额
BET1000-100
SETTLED0200+200

这两条属于同一局时,整局玩家盈亏为 200 - 100 = +100。因此,不能只用 SETTLED 行的金额作为整局盈亏。

下注与派彩合并为一条 SETTLED ​

有些游戏商只推送一条同时包含两个金额的 SETTLED:

statusbet_amountprize_amount整局玩家盈亏
SETTLED100200+100

这种情况下可以直接使用 prize_amount - bet_amount。不同游戏商的行拆法不同,但两个金额字段的含义不变。

status 与资金处理规则 ​

status含义常见金额形式包网处理
BET下注扣款bet_amount > 0,prize_amount = 0扣除 bet_amount
SETTLED正常结算可能只有 prize_amount,也可能两个金额都有扣除本条包含的 bet_amount,增加 prize_amount;两个金额都有时必须在同一笔原子交易中处理
BONUS额外奖金或独立赢分通常 bet_amount = 0,只有 prize_amount增加 prize_amount,并单独归类为奖金流水
REFUND退款通常只有 prize_amount增加退款金额,并将原交易标记为已退款
CANCEL / ROLLBACK / VOID取消、回滚或作废厂商之间可能不同,两个金额也可能都是 0根据 original_transaction_id 对原交易执行一次幂等冲正

action 是 Hub-System 内部使用的动作名称;包网在本接口中以 wagers[].status 处理同一语义。

修正流水说明 ​

CANCEL、ROLLBACK、VOID 和 REFUND 不是新的正常输赢。包网必须使用 original_transaction_id 定位原资金交易,检查是否已经冲正,并且只执行一次冲正。

修正流水中,厂商可能把原下注金额同时放在 bet_amount 作为参考;这不代表包网要再次扣款。退款或退回玩家的钱应以 prize_amount 表示。若两个金额都是 0,表示该修正没有余额变化,但仍应更新原交易的报表状态。修正类流水不要单独套用 prize_amount - bet_amount 来判断最终输赢。

示例请求 ​

正常结算注单 SETTLED ​

json
{
  "operator_code": "AG",
  "wagers": [
    {
      "username": "player001",
      "currency": "MYR",
      "session_id": "vct-session-uuid-001",
      "bet_id": "settle-20260706-0001",
      "brand_guid": "30ff77f5-0616-4ecc-a8a3-80e35fcaaf3e",
      "brand_code": "1007",
      "brand_name": "PG Soft",
      "game_code": "PG-SLOT-001",
      "game_type": "SLOT",
      "game_genre": 2,
      "game_genre_name": "Slot",
      "game_name": "Fortune Tiger",
      "bet_amount": 100.0,
      "valid_bet_amount": 100.0,
      "prize_amount": 200.0,
      "win_loss": 100.0,
      "status": "SETTLED",
      "bet_time": "2026-07-06T10:00:00+08:00",
      "settle_time": "2026-07-06T10:01:00+08:00",
      "round_id": "round-10001"
    }
  ],
  "sign": "demo-sign",
  "timestamp": 1783325100
}

额外奖金记录 BONUS ​

json
{
  "operator_code": "AG",
  "wagers": [
    {
      "username": "player001",
      "currency": "MYR",
      "session_id": "vct-session-uuid-001",
      "bet_id": "bonus-20260706-0001",
      "brand_guid": "30ff77f5-0616-4ecc-a8a3-80e35fcaaf3e",
      "brand_code": "1007",
      "brand_name": "PG Soft",
      "game_code": "PG-SLOT-001",
      "game_type": "SLOT",
      "game_genre": 2,
      "game_genre_name": "Slot",
      "game_name": "Fortune Tiger",
      "bet_amount": 0.0,
      "valid_bet_amount": 0.0,
      "prize_amount": 30.0,
      "win_loss": 30.0,
      "status": "BONUS",
      "bet_time": "2026-07-06T10:01:00+08:00",
      "settle_time": "2026-07-06T10:01:10+08:00",
      "round_id": "round-10001",
      "original_transaction_id": "settle-20260706-0001"
    }
  ],
  "sign": "demo-sign",
  "timestamp": 1783325160
}

示例响应 ​

json
{
  "received": 1,
  "status": "success"
}

推送数据逻辑与处理建议 ​

1. 实时钱包记账(极其重要) ​

  • 必须实时处理余额:包网按 status 对主钱包执行资金交易。BET 扣除 bet_amount;SETTLED 扣除本条包含的 bet_amount 并增加 prize_amount(如果 bet_amount 为 0,则只增加 prize_amount);BONUS 增加对应奖金;CANCEL / ROLLBACK / REFUND / VOID 依据 original_transaction_id 对原交易进行一次幂等冲正。
  • /offline 只用于关会话与最终对账,不能再根据 reclaimed_amount 对已由 bet-push 处理过的主钱包重复加款或扣款。

2. 幂等去重控制 ​

  • 包网系统应以交易唯一键(至少 wagers[].bet_id,并结合 status 与 original_transaction_id)进行幂等排重,避免网络重试造成重复扣款、加款或冲正。

3. 注单状态与修正逻辑 ​

  • 正常注单状态:BET(原始投注)、SETTLED(正常结算)、BONUS(红利或独立赢分)。
  • 修正注单状态:CANCEL / ROLLBACK / REFUND / VOID(注单取消或回退)。
  • 修正逻辑处理:当注单状态为修正状态时,推送数据会携带指向原注单的 original_transaction_id。包网必须定位原资金交易,完成一次幂等冲正,并同步更新报表状态;修正记录中的 bet_amount 可能只是原下注金额参考值,不应因此再次扣款。

4. 自动重试机制与响应代码 ​

  • 处理成功:包网处理完毕后,请返回 HTTP 200 状态码,并响应 {"received": 1, "status": "success"},VCT 队列收到后会将该笔推送任务标记为成功。
  • 重试保障:若包网侧数据库繁忙或网络短暂中断,应返回 HTTP 5xx 或直接超时。VCT 本地队列任务检测到失败或超时后,会启动自动重试策略,在随后的时间段内进行多次重试推送,确保流水日志零丢失。

游戏商来源映射 ​

游戏商回调路径请求格式
BG—不支持推送
GSCseamless/pushbetdataJSON,wagers 数组;支持 status=SETTLED / BONUS
SA—不支持推送(通过查询接口拉取)
WMwebhook(cmd=SendMemberReport)form-data,result 数组

AI 开发提示词(可直接复制) ​

text
请在当前包网项目中实现 VCT 投注数据回调 POST /api/v1/callback/bet-push。这是 Seamless 钱包实际扣款、派彩和冲正的资金入口。

实现要求:
1. 校验 Authorization 三段式 Token;Header 与 Body timestamp 必须一致。Body sign=HMAC-SHA256(agent_api_key + "." + timestamp, agent_api_secret),使用小写 hex 和常量时间比较。
2. 验证 operator_code 属于当前 Agent,wagers 必须是非空数组;逐条校验 username、currency、session_id、bet_id、status 和金额格式。
3. 使用 decimal/定点数,禁止 float 参与资金计算。每批请求在数据库事务中处理,成功提交后才返回 success。
4. 建立稳定幂等键,至少包含 Agent、bet_id、status,并结合 original_transaction_id;VCT 重试不得造成重复扣款、派彩或冲正。
5. BET 扣 bet_amount;SETTLED 扣本条 bet_amount 并加 prize_amount;BONUS 加 prize_amount;同一局可能 BET/SETTLED 分开,也可能合并,不能假设固定顺序。
6. CANCEL/ROLLBACK/REFUND/VOID 必须通过 original_transaction_id 定位原资金交易并只冲正一次;修正记录的 bet_amount 可能仅供参考,不能再次扣款。
7. 保存 hub session_id、round_id、brand_guid、brand_code、brand_name、game_code、game_type、game_name、bet/settle 时间及原始 JSON。按 brand_guid 关联目录和注单,不以 Code/Name 为唯一键;同名同码但 GUID 不同的 Brand 保持独立。历史缺少 GUID 的记录保留并标记归属待补,不猜测 GUID;钱包处理不变;费率查询使用 brand_guid 和原业务日期 as_of_date,保留既有计算规则。不要只用 round_id 做唯一键。
7a. 佣金使用数字 game_genre(2 Slot、3 Fish、4 Sport、5 Card、6 Live、7 Other),game_genre_name 只用于展示;旧 game_type 是厂商原始字段。game_genre=0 的注单标记待核对,不从旧字符串猜类型,不擅自计费。
8. 业务全部成功后返回 HTTP 200 和 {"received": 实际条数, "status":"success"}。任何一条未提交时不得虚报成功;暂时性故障返回 5xx 让 VCT 重试。
9. `/offline` 的 reclaimed_amount 不能再次变更已经由 bet-push 处理的主钱包。
10. 对乱序、重复、迟到日志保持幂等;同一 session 清除后到达的日志仍按交易规则处理并标记审计时间。
11. 日志脱敏 Secret、Token 和 sign,但保留 bet_id、session_id、status、事务结果和错误。
12. 增加测试:BET、拆分/合并 SETTLED、BONUS、四种修正、批量原子性、重复/乱序/迟到、金额精度、签名失败、数据库故障重试,以及同 Code/Name 不同 Brand GUID 的归属隔离。

请复用现有钱包账本、数据库事务、唯一约束和回调认证,不要另建一套余额真值。

VCT Gaming Integration Platform