Transfer Wallet 运营商对接文档
PlayRouter Transfer Wallet(转账钱包)· 11 端点 · 零回调 · 2026-07-06 · Seamless Wallet 产品见 对应文档站 ↗
records/list 拉取——这是你知道玩家输赢的唯一渠道。④ 拿不到响应就同 idempotency_key 重发,恒安全(在同一区内)——没有任何"重发前先查单"的仪式。接入之旅:全貌一张图
整套对接只有一个方向:全部端点都是你调用归属服 {eu|sea|latam}.api.playrouter.io——划拨、启动、目录、对账。零回调:游戏期间我们不会调用你的任何接口,你不需要暴露任何服务。端点按「洋葱」分层:接通必须层就可以上线——7 个端点 + 0 个回调;查单两件推荐接(异常处理更从容),terminate 按需。下面每个端点的标题上都标了必须 / 可选。
| 层 | 端点 | 什么时候需要 |
|---|---|---|
| 必须 · 上线门槛 | sessions/create · games/list · providers/list · currencies transfers/create · wallet/balance · records/list | 第一天。认证套件只考这 7 个(+ 0 个回调) |
| 查单 | transfers/get · records/get · wallet/balances | pending 划拨轮询终态、客服按单号排障、厂商内多产品/场馆余额归集时(推荐,可后补) |
| 会话辅助 | sessions/terminate | 风控/自我排除要把人请出游戏时(best-effort) |
钱包模式与拓扑
转账钱包模式下,玩家在你系统里的余额和在厂商侧游戏钱包里的余额各自独立。玩家玩游戏前你先"上分"(把钱划进厂商侧游戏钱包),玩完"下分"取回。PlayRouter 是中间的统一转发层:一套 API、一套签名、一套幂等,替你对接所有转账形态的厂商。
三条你要提前知道的规则
| 规则 | 含义 |
|---|---|
| 逐厂商钱包 | 玩家在每家厂商各有一个游戏钱包。跨厂商换游戏 = 先从 A 家 withdraw、再向 B 家 deposit(两笔独立划拨)。 |
| 单币种钱包 | 每个 player_id 首次划拨/启动时确定币种,此后不可改。多币种玩家请拆多个 player_id(如 wang-123-brl / wang-123-usd)。 |
| 目录边界 | games/list 只含转账形态厂商。仅有 seamless 形态的厂商在本产品不可见——没有任何一方持有它们要调用的钱包。 |
/v1/transfer/…,seamless 面 /v1/seamless/…)——将来若升级 seamless,这 5 个端点切换只改前缀,密钥也是同一把(密钥账号级通用,2026-07-20 起):一把 pk_/sk_ 对两条产品线同时有效,升级 seamless 无需换钥。你能调用哪些端点取决于账号的产品开通状态,与密钥无关——体现在路径前缀上:未开通的面返回 403 product_not_enabled。五分钟快速开始
控制台注册 → 创建密钥 → 得 pk_test_… / sk_test_…(账号级,两条产品线通用)。沙箱与生产完全隔离。
ping 级验证:providers/list + currencies两个零参数端点(body 传 {}),验证签名代码是否正确,同时拿到厂商目录与币种精度表。
games/list 首次用响应头 X-Full-Dump-Url 的每日快照,日常用 updated_after 增量。
transfers/create(deposit) 划 100 进厂商钱包 → sessions/create 拿启动 URL → 玩家玩完 wallet/balance 看 transferable → transfers/create(withdraw) 取回。
定时拉 records/list(这是你知道输赢的唯一渠道),按 record_id 去重入库。到这里,7 个必须端点全部接完,可申请认证。
第一个请求(复制即跑)
三个核心概念(先建立心智模型)
整套 API 只依赖三个概念。用你熟悉的电商类比一次讲清,后面所有字段表都会变得好读。
transfer = 转账凭证(划拨单)
每次上分/下分是一张划拨单,transfer_id(trf_)是它的全局唯一编号。三态终局:completed / failed(带 reason)/ pending(轮询 transfers/get 等终态)。重发靠 idempotency_key(推荐 tf-{内部订单ID})——拿不到响应同 key 重发恒安全(在同一区内)。
record = 输赢流水(注单)
玩家在厂商侧玩的每一局,事后以一条记录出现在 records/list 里,record_id(rec_)是它的编号,也是你入库的去重键——转账产品没有 transaction 回调,rec_ 就是你这侧的"流水号"。这是你知道输赢的唯一渠道,按分钟级拉取。
逐厂商钱包 + 全盲期
玩家在每家厂商各有一个游戏钱包(划拨和查余额都要指定 provider)。钱划过去之后、拉到记录之前,你是全盲的——游戏期间零回调,余额问 wallet/balance、输赢等 records/list。这是转账形态的本质代价,换来的是零服务端成本。
附赠:transferable = 可取余额预览
wallet/balance 响应里的可划回金额(局内锁定部分不含)。支持的厂商给这个字段,下分前先看它,一次取准;不支持的厂商按 balance 试、按 reason 重试(见「上分 / 下分流程」的取回全部循环)。
全景时序:一次上分到下分的一生
四个角色:玩家在你的站点玩、游戏由厂商提供、PlayRouter 居中转发、你只发起调用。下图一次讲完上分、全盲游玩、下分与对账——注意中段:那里没有任何指向你的箭头,这就是零回调。
签名(必读 · 你唯一的安全动作)
本产品只有一个方向要签:你给每个请求签名、我们验(失败 = 401,语义正确且唯一)。零回调意味着没有验签义务、没有入站白名单、不需要维护 token——把请求签对,安全面就完整了。算法与 PlayRouter 全线产品逐字相同:HMAC-SHA256 对「时间戳 + 原始请求体」签名,装在两个固定请求头里。
给你的请求签名(三种语言)
code 告诉你错在哪一步:invalid_signature(v1 不匹配,九成是 body 被二次格式化)· invalid_timestamp(t 出 ±300 秒窗,查服务器时钟)· unknown_key(Key-Id 打错或环境不对)。这是配置故障:修好再发,不要重试轰炸;报障带上响应头 X-Request-Id。幂等与重试
全产品唯一要背的重试规则:拿不到响应(超时/断连/5xx),同一个 idempotency_key 原样重发,恒安全(在同一区内)。命中重放会返回原响应 + 响应头 Idempotency-Replayed: true;同 key 不同 body 会被 409 拒绝(防复制粘贴事故);键保留 7 天。
推荐派生方式
- 内部划拨订单先落库(write-ahead),拿到订单号
- 幂等键 =
tf-{内部订单ID}(确定性派生,天然防重) - 严禁每次重试重新生成随机键——那等于没有幂等
你不需要做的事
- 不需要背"哪些错误态可以重发"的清单
- 不需要重发前先调查单接口"确认状态"
- 不需要在单号里内嵌时间戳、凑格式、赶 5 分钟窗口
上分 / 下分流程
铁律一句话:上分先扣自己、后划厂商(失败退回);下分先划回来、确认成功再入账。顺序错了就是双花或丢分。
上分(deposit)
- 创建内部订单(状态"新建")
- 先扣你侧玩家主钱包——扣不动就停
- 调
transfers/create(type:"deposit") completed→ 订单完结;failed→ 退回主钱包扣款;pending→ 进异常队列,transfers/get轮询终态
下分(withdraw)
- 创建内部订单;先查
wallet/balance拿transferable(有此字段的厂商) - 调
transfers/create(type:"withdraw"),金额 ≤ transferable completed→ 此刻才给玩家主钱包入账;failed→ 按 reason 分支(枚举见「错误与 reason」);pending→ 轮询,终态前不入账
「取回全部」参考流程(我们有意不做 withdraw_all)
recall_id 必须每次取回新生成并先落库(同上文「推荐派生方式」):键保留 7 天,recall-{player}-{attempt} 这类下次还会再算出来的键,会让下一次取回撞上上一次的键——金额相同就直接重放上次的结果(上次是 completed,你就会再入账一次),金额不同则被 409 拒绝。
WAIT(处理中)怎么收尾transfers/get 按 ≥30 秒间隔轮询(1 小时后可降频);终态一定会给出(超过 1 小时我们会人工核对后落终态,无需你处理)。终态出来以后:
completed→ 此刻给玩家主钱包入账;需要的话再调一次recall_all(新的recall_id)取剩余。failed且 reason 是not_executed或provider_unavailable→ 资金没动、不入账;需要的话用新的recall_id再调一次recall_all。failed且 reason 是insufficient_funds、game_limit或player_in_game→ 不入账;稍后用新的recall_id再调一次recall_all(局内锁要等局结束)。- 其余 reason → 记录并转人工。
循环里出现的各 reason 含义与处置,见「错误与 reason」的枚举表。
方向 A · 你调我们(11 端点)
Base URL:https://{eu|sea|latam}.api.playrouter.io(沙箱 https://api.sandbox.playrouter.io,单区)。改用别的区不需要新账号或新密钥;数据按区存放、区与区不互通——旧区的划拨与注单记录留在旧区,照常可查。玩家已在某个区上分进游戏的余额,请在同一个区查询和取回,取回后再到新区上分。拿不到响应要重试时,也请留在同一个区:同一个 idempotency_key 只在同一区内去重,换到别的区重发会被当成一笔新请求再执行一次。路径第二段 = 钱包模式面:本产品全部端点都在 /v1/transfer/<域>/<动作> 下(如 /v1/transfer/transfers/create、/v1/transfer/currencies);seamless 产品的同名端点在 /v1/seamless/… 下。账号开通了哪一面才能调哪个前缀——未开通的面一律返回 403 product_not_enabled,与端点是否"公共"无关。两面共有的 5 个目录/会话端点字段逐字相同,切换只改前缀。
POST/v1/transfer/sessions/create 上线必须
启动游戏,真钱/试玩合一。转账模式注意:启动前先上分——余额 0 也能进游戏,但玩家会看到 0 余额。game_code 的厂商段(冒号前)决定厂商,具体钱包由 provider_product 决定(多产品线厂商)。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| player_id | string | real 必填 | ≤ 64 字符;你侧稳定玩家标识;demo 可省。不收 PII。单币种钱包:一个 player_id 一个币种 | "wang-123" |
| game_code | string | 必填 | <provider>:<游戏段>,与 games/list 同一把键。不透明键,原样回传:多产品线厂商(目前只有 db,DB Gaming)的游戏段形如 card-101(产品线-厂商游戏码),单产品线厂商的游戏段就是厂商游戏码原文;不要自行拆游戏段,产品维度用 provider_product 字段 | "pg:fortune-tiger" / "db:card-101" |
| currency | string | 必填 | real = 钱包币种(精确匹配永不降级;厂商 / 实例不收该币种 → 422 currency_not_supported,在建户 / 打厂商之前拒,如 saba 只登记 USD 时的 CNY;该币种平台侧暂时不可用时同码、fields.currency = temporarily unavailable,不要换币种、稍后重试);demo = 期望展示币种(不支持则静默降级厂商默认,不校验) | "BRL" |
| mode | string | 必填 | real | demo | "real" |
| ip | string | real 必填 | 玩家 IP,IPv4/IPv6 | "203.0.113.7" |
| locale | string | 可选 | ISO 639-1 小写;不支持静默降级 en | "pt" |
| device | string | 可选 | desktop | mobile | "mobile" |
| lobby_url | string | 可选 | 退出游戏返回地址 | "https://op.com/lobby" |
| deposit_url | string | 可选 | 游戏内"去充值"跳转;未提供时降级用 lobby_url | "https://op.com/cashier" |
| launch_mode | string | 可选 | url(默认)| html——HTML 直出(抗封锁);厂商不支持时声明降级 | "url" |
| session_payload | string | 可选 | ≤1024 字符透传串,出现在 records 关联与排障日志 | "wsess-8f2|ios" |
响应字段
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| session_id | string | 总是有 | 会话锚点(ses_),排障/终止用 | "ses_01H8XGJWBW" |
| url | string | 总是有 | 启动 URL 恒在(HTML 型厂商由我们包装成 URL)。拿到后立即打开、只用一次:链接有效期由游戏厂商决定,短的只有约 1 分钟,部分厂商的链接只能打开一次;玩家每次进游戏(含刷新页面、重新打开)都重新调用 sessions/create 取新链接,不要缓存复用 | "https://launch..." |
| html | string | 不一定有 | 仅 launch_mode:"html" 且厂商支持时出现;从你的自有域名伺服 | "<!DOCTYPE html>..." |
| expires_at | string | 总是有 | 启动 URL 最晚失效时刻(RFC 3339);实际有效期由游戏厂商决定、可能早得多(见 url 行),不要据此缓存复用 url | "2026-07-06T12:30:00.000Z" |
REQUEST
// 点「启动」
RESPONSE
//
- 422
game_not_available:游戏当前不对这个玩家开放(下架、地域限制、未到 released_at,或厂商拒绝该玩家进入)——重试同一请求不会成功,提示玩家换一款游戏。例外:fields.game_code=temporarily unavailable表示平台侧暂时不可用、游戏本身没有下架——稍后重试同一请求即可,你不需要做任何配置,也不要把游戏从大厅撤下。 - 422
demo_not_available:这款游戏不支持试玩。 - 502
provider_error:临时故障,稍后用同一请求重试。
POST/v1/transfer/games/list 上线必须
游戏目录:对象数组 + cursor 分页 + updated_after 增量。首次同步用响应头 X-Full-Dump-Url 的每日全量快照;链接下载失败时,改用不带 updated_after 的分页全量。目录只含转账形态厂商。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| cursor | string|null | 可选 | 黑盒游标:上页 next_cursor 原样传回;首页省略 | null |
| limit | integer | 可选 | 1–2000 | 500 |
| updated_after | string | 可选 | 增量同步:只拉此后变更(厂商下架也是一次变更,status 变 recalled;从目录消失的游戏不在增量里,见响应 status 说明) | "2026-07-01T00:00:00.000Z" |
| provider | string | 可选 | 按厂商过滤(单值),值来自本面 providers/list 的 code | "pg" |
| category | string | 可选 | 按品类过滤(live 为一等品类) | "slots" |
| currency | string | 可选 | 按支持币种过滤 | "BRL" |
category / currencies 字段在本地筛(这些字段变化时 updated_at 会刷新)。响应字段(game 对象)
| 字段 | 类型 | 出现 | 说明 |
|---|---|---|---|
| game_code | string | 总是有 | 全 API 同一把游戏键(<provider>:<游戏段>,不透明、原样回传;多产品线厂商如 db:card-101) |
| name | string | 总是有 | 官方展示名 |
| provider | string | 总是有 | 厂商代号(厂商族码,来自本面 providers/list 的 code)——转账模式下同时是钱包定位键 |
| provider_product | string | 不一定有 | 该游戏所属的厂商产品维度键——transfers/create 与 wallet/balance 同名参数的值域来源(多产品线厂商才出现;db 的产品线:live 真人 / hash 哈希 / card DB 棋牌 / boyacard 博雅棋牌 / fishing DB 捕鱼 / boyafishing 博雅捕鱼 / slots 电子 / scratch 刮刮乐 / lottery 彩票 / esports 电竞 / sports 体育;其它多产品厂商沿用既有子钱包语义)。不要自行拆 game_code 的游戏段来反推它 |
| category | string | 总是有 | 品类(live 是一等品类)。取值 = 游戏类型字典 17 码:sports, live, slots, lottery, card, poker, fishing, esports, virtual, originals, racing, cockfighting, hash, arcade, table, prediction, scratch;字典只增不改,未知值按「其它」兜底 |
| images.square | string | 不一定有 | 方图 URL——只在厂商提供时出现;缺省 = 厂商无图源,不编图 |
| images.landscape | string | 不一定有 | 横图 URL——同上 |
| locales | array | 总是有 | 支持语言(ISO 639-1 两字母,真数组)。厂商实例级:平台运营按厂商实例登记,同一实例下所有游戏同值,不保证每款游戏各异;未登记缺省 ["en"]。不在表内的 locale 启动时静默降级 en |
| currencies | array | 总是有 | 支持币种(ISO 4217 / 加密货币码,真数组)。厂商实例级:平台运营按厂商实例登记,同一实例下所有游戏同值,不保证每款游戏各异;未登记缺省 ["CNY"]。以此判断 sessions/create · transfers/create 该传什么币种;实例真正接受的币种以 422 currency_not_supported 为准(fields.currency = temporarily unavailable 的除外:那是平台侧暂时不可用,不代表实例不收)(目录里出现该实例不接受的币种属运营登记错误,我方告警修正;目录只列部分接受币种是正常经营选择) |
| devices | array | 总是有 | desktop / mobile |
| launch_modes | array | 总是有 | 启动形态能力:含 "html" 即支持 HTML 直出(抗封锁) |
| features | object | 不一定有 | demo / freespins / bonus_buy / jackpot 能力布尔——只在厂商目录给出能力信息时出现;缺省 = 未知,不编假 false(2026-09-19 起由「总是有」改为「不一定有」) |
| bet_levels | object | 不一定有 | 币种 → 合法投注面值(金额字符串数组),只在厂商提供时出现 |
| rtp | string | 不一定有 | RTP 百分数字符串,只在厂商提供时出现;已接 7 家厂商的目录接口均不含 RTP,缺省不编数 |
| volatility | string | 不一定有 | 波动率评级,厂商原值透传(不强行归一枚举) |
| released_at | string | 不一定有 | 发布时刻——此前启动返回 game_not_available |
| forbid_bonus_play | boolean | 不一定有 | true = 禁止用奖金资金游玩(自建奖金系统的合规输入) |
| status | string | 总是有 | active | recalled——目录只含运营已上架、且所属厂商(多产品线厂商按产品线)当前由平台开放的游戏;active = 厂商在售,recalled = 厂商已下架(下架也是一次变更,增量同步天然捕获)。运营关闭上架的游戏、平台停用的厂商(产品线)的游戏会直接从目录消失,这类消失不经 updated_after 增量下发,由我方商务另行通知;也可自行核对:厂商(产品线)停用时它会从 providers/list 中消失,单款游戏关闭上架可不带 updated_after 全量拉取比对。平台恢复该厂商后,其游戏重新出现、updated_at 随之刷新 |
| updated_at | string | 总是有 | 最后变更时刻——增量同步(updated_after)的锚点 |
REQUEST
// 点「拉取」
RESPONSE
//
POST/v1/transfer/providers/list 上线必须
厂商目录,每个厂商族一行(pg、db、pp、saba……)。请求空对象 {}。转账模式下 code 还是划拨/余额的 provider 参数取值。低频,日缓存。
响应字段(provider 对象)
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| code | string | 总是有 | 厂商族码——transfers / balance 的 provider 参数用它,全 API 的 provider 值都来自这里 | "pg" |
| name | string | 总是有 | 官方品牌展示名 | "PG Soft" |
| categories | array | 总是有 | 该厂商的品类 = 本面该族目录中(运营已上架)游戏 category 的去重集合;一个类目下最后一款下架即从此消失(可为空数组) | ["slots"] |
| currencies | array | 总是有 | 该厂商支持的币种 = 本面该族各实例登记的 currencies 的并集(运营按实例登记,未登记缺省 CNY,与 games/list 同源) | ["BRL","USD"] |
| status | string | 总是有 | active | disabled——目前恒为 active:列表只含本面当前开放的厂商族;厂商族整体停用时直接从列表消失、某条产品线停用时从 products 中消失(disabled 暂不下发) | "active" |
| products | array | 不一定有 | 多产品线厂商才出现:[{code, name}],供 lobby 分区与 provider_product 取值发现(transfers/create · wallet/balance · wallet/balances.products 的值域) | [{"code":"card","name":"DB Card"}] |
示例
REQUEST
// 点「发送」
RESPONSE
//
POST/v1/transfer/currencies 上线必须
币种目录 + 每币种 decimals——全 API 金额字符串的精度权威表。请求空对象 {}。没有 K 货币单位:IDR/VND/COP 型大面值币种直接按真实面值传,不需要 ÷1000 换算。
"0.00",如从未上分玩家的 balance)。判断「是否为零」「是否相等」时先解析成十进制数(Java BigDecimal.compareTo、Python Decimal、JS 用十进制库)再比较;amount == "0" 这类字符串比较会出错。响应字段(currency 对象)
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| code | string | 总是有 | 法币 ISO 4217 三字母;加密货币 3–4 位字母数字(如 USDT) | "BRL" |
| decimals | integer | 总是有 | 金额字符串小数位数 | 2 |
| type | string | 总是有 | fiat | crypto | "fiat" |
REQUEST
// 点「发送」
RESPONSE
//
POST/v1/transfer/transfers/create 上线必须
划拨:上分/下分合一,方向在 type,金额恒正。不需要预注册玩家——deposit 自动建户(上游要显式建户的厂商由我们内部代办)。业务结局不是 HTTP 错误:余额不足、局内锁都是 200 + status:"failed" + reason。从未上分(在该厂商尚无钱包)的玩家发起 withdraw 也是业务结局:200 + status:"failed" + reason:"insufficient_funds"(余额 0 不够下),不是 404——404 player_not_found 只在本平台从未见过该 player_id 时出现,且只发生在 wallet/balance · wallet/balances(见错误码目录)。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| player_id | string | 必填 | ≤ 64 字符;首笔划拨确定钱包币种 | "wang-123" |
| provider | string | 必填 | 钱去哪家 / 从哪家取回(厂商族码,来自本面 providers/list 的 code) | "pg" |
| provider_product | string | 多产品线厂商必填 | 钱进哪个产品线钱包。多产品线厂商必填(如 db),值取 games/list 回显的 provider_product 或 providers/list.products[].code;单产品线厂商省略。缺省 → 422 validation_failed(fields.provider_product = required);厂商已开通但值不是它的产品线(如 db + "bogus")→ 422 validation_failed(fields.provider_product = invalid);厂商族本身不在本面提供(未接入或已被平台停用)→ 403 provider_not_enabled。三者都不会挂单 | "card" |
| type | string | 必填 | deposit(上分)| withdraw(下分) | "deposit" |
| amount | string | 必填 | 恒正金额字符串,精度按 currencies。个别游戏厂商的接口能接受的小数位少于币种目录(例如最多 3 位),超出时 transfers/create 当场 422 validation_failed,fields.amount 写明上限(exceeds N decimals accepted by provider),不建单、资金未动;改成该位数以内重新发起即可 | "100.00" |
| currency | string | 必填 | 一致性防呆:与该玩家已锁定的钱包币种不符 → 422 currency_mismatch;厂商 / 实例本身不收该币种 → 422 currency_not_supported(两码分工见错误码目录) | "BRL" |
| idempotency_key | string | 必填 | 推荐 tf-{内部订单ID};拿不到响应同 key 重发恒安全(在同一区内) | "tf-ord-889231" |
响应字段(Transfer 对象;transfers/get 同形)
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| transfer_id | string | 总是有 | 划拨 ID(trf_),请持久化——transfers/get 的主键 | "trf_01H8XGJWBW" |
| player_id | string | 总是有 | 玩家标识回带 | "wang-123" |
| provider | string | 总是有 | 资金所在厂商(厂商族码,来自本面 providers/list 的 code) | "pg" |
| provider_product | string | 不一定有 | 生效的厂商产品维度键(多产品线厂商时出现)——钱实际进/出的产品线钱包,自记对账以此为准 | "card" |
| type | string | 总是有 | deposit | withdraw | "deposit" |
| amount | string | 总是有 | 划拨金额(恒正) | "100.00" |
| currency | string | 总是有 | 钱包币种 | "BRL" |
| status | string | 总是有 | completed | failed 终态不再变;pending 极少出现 → transfers/get 轮询(≥30s 间隔) | "completed" |
| reason | string | 不一定有 | 仅 failed 时出现;枚举见「错误与 reason」一节 | "insufficient_funds" |
| balance | string | 不一定有 | 划拨后(或紧随其后查到的)游戏钱包余额;completed 时通常带上,个别情况下可能缺省(不影响划拨结论)——需要当前余额请调 wallet/balance;failed 时给得出则附上 | "100.00" |
| transferable | string | 不一定有 | 可下分预览,厂商有此口径才出现 | "100.00" |
| created_at | string | 总是有 | 受理时刻(RFC 3339) | "2026-07-06T12:00:00.000Z" |
| completed_at | string | 不一定有 | 终态时刻——completed / failed 时出现,pending 时缺省 | "2026-07-06T12:00:00.180Z" |
REQUEST
// 点「发送」
RESPONSE
//
POST/v1/transfer/wallet/balance 上线必须
查玩家在指定厂商侧游戏钱包的余额。transferable(可下分余额)按厂商能力出现:有此口径的厂商透传,给不出的厂商缺省该字段——我们不编数。注意:玩家关闭游戏窗口 ≠ 本局结束,局内锁定余额要等结算。
从未上分的玩家不是错误:玩家在该厂商尚无钱包(首笔 deposit / 首次真钱启动才自动建户)→ 200 + balance:"0.00"(transferable 缺省)——0 是事实不是编数,别据此判定玩家不存在。404 player_not_found 只在本平台从未见过该 player_id 时出现:你从未用它发起过一次被受理的 transfers/create(返回 200,不论厂商、不论 status 是 completed 还是 failed),也从未用它成功建过真钱会话(sessions/create 200);一旦有过任一次,此后查任何厂商都不会再 404,最多是 0.00。被 4xx 拒绝的请求(422 validation_failed / currency_not_supported、403)在挂单之前就被拦下,不登记玩家。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| player_id | string | 必填 | ≤ 64 字符 | "wang-123" |
| provider | string | 必填 | 逐厂商钱包:查哪家指定哪家(厂商族码,来自本面 providers/list 的 code) | "pg" |
| provider_product | string | 多产品线厂商必填 | 查哪个产品线钱包的余额。多产品线厂商必填(如 db),值取 games/list 回显的 provider_product 或 providers/list.products[].code;单产品线厂商省略。缺省 → 422 validation_failed(fields.provider_product = required);厂商已开通但值不是它的产品线 → 422 validation_failed(fields.provider_product = invalid);厂商族本身不在本面提供(未接入或已被平台停用)→ 403 provider_not_enabled。语义同 transfers/create 同名字段 | "card" |
响应字段
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| player_id | string | 总是有 | 玩家标识回带 | "wang-123" |
| provider | string | 总是有 | 钱包所在厂商(厂商族码,来自本面 providers/list 的 code) | "pg" |
| provider_product | string | 不一定有 | 生效的厂商产品维度键(多产品线厂商时出现)——本快照属于哪个产品线钱包 | "card" |
| currency | string | 总是有 | 钱包币种(单币种钱包) | "BRL" |
| balance | string | 总是有 | 当前余额 | "95.00" |
| transferable | string | 不一定有 | 可下分预览;缺省 = 该厂商无此口径,按 balance 试错 + reason 重试 | "80.00" |
| as_of | string | 总是有 | 快照时刻 | "2026-07-06T12:00:00.000Z" |
REQUEST
// 点「查询」
RESPONSE
//
POST/v1/transfer/wallet/balances 可选
一次查玩家在同一厂商全部产品/场馆游戏钱包的余额。缺省扇出范围 = 该玩家在该厂商有过划拨记录的产品/场馆 ∪ 平台缺省产品;也可用 products 显式指定(值域 = games/list 回显的 provider_product,或 providers/list.products[].code)。按产品线拆分的厂商(如 db)用 products 指定要归集的产品线。单产品/无产品维度厂商退化为单行——等价 wallet/balance。
边界:厂商内归集。不解决跨厂商总资产——要看玩家全部厂商的资金,逐厂商各调一次;跨厂商合计(币种折算、时点语义)由你自己定义。
as_of(我们不假装这是同一时点的原子快照)。任何一行失败:该行 available=false(保留在列表里,不剔除)、顶层 partial=true、total_balance 缺省。切勿把可得行的 balance 求和当总资产——缺的那行可能正是钱所在的场馆。正确姿势:partial=true 时按行重试(用 products 指定失败行重查),全部可得后再用 total_balance。另:本端点较重(要逐个产品查询),勿高频轮询——同一玩家建议间隔 ≥30 秒;高频场景用 wallet/balance 点查目标产品。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| player_id | string | 必填 | ≤ 64 字符 | "wang-123" |
| provider | string | 必填 | 归集范围恒为单厂商(厂商族码,来自本面 providers/list 的 code) | "db" |
| products | string[] | 可选 | 显式扇出集(≤32 值,值域 = providers/list.products[].code);任何非法值(含厂商已开通但不是它的产品线,如 db + "bogus")→ 422 validation_failed(fields.products),不部分执行;厂商族本身不在本面提供(未接入或已被平台停用)→ 403 provider_not_enabled。缺省 = 划拨触达集 ∪ 平台缺省产品 | ["card", "live"] |
响应字段
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| player_id | string | 总是有 | 玩家标识回带 | "wang-123" |
| provider | string | 总是有 | 钱包所在厂商(厂商族码,来自本面 providers/list 的 code) | "db" |
| currency | string | 总是有 | 钱包币种(单币种钱包) | "BRL" |
| wallets | array | 总是有 | 逐产品/场馆一行;失败行保留(available=false),不剔除 | — |
| wallets[].provider_product | string | 不一定有 | 该行的厂商产品维度键(无维度厂商的单行不出) | "card" |
| wallets[].balance | string | 不一定有 | 该产品钱包余额;仅 available=true 时出现 | "95.00" |
| wallets[].transferable | string | 不一定有 | 可下分预览(厂商有此口径且行可得时) | "80.00" |
| wallets[].as_of | string | 总是有 | 本行取数时刻(逐行独立,非全响应统一时点) | "2026-07-06T12:00:00.000Z" |
| wallets[].available | boolean | 总是有 | false = 本行暂不可得(厂商不可达/超时/预算耗尽),balance 缺省 | true |
| total_balance | string | 不一定有 | 全部行可得时的合计。partial=true 时恒缺省——勿以可得行之和充总资产 | "97.00" |
| partial | boolean | 总是有 | true = 至少一行不可得;按行重试收敛 | false |
POST/v1/transfer/records/list 上线必须
转账模式下游戏期间你是全盲的——这个端点是你知道玩家输赢的唯一渠道,是主账本不是复核视图。定时批量拉取,按 record_id 去重入库。数据从各厂商拉取归一:新鲜度分钟级;可查窗口统一最近 1 个月(from 越界请求 422)。个别记录可能因平台侧处理延后出现,处理完成后自动补入、无需商户操作;补入的记录 recorded_at 为补入时刻,出现在该时刻所在的时间窗——按时间窗增量拉取不会漏,按 record_id 去重即可。顺序稳定但不保证按时间排。
from / to 比较的是每条记录的 recorded_at(进入 PlayRouter 的时刻),不是 started_at。改判追加的冲销 / 更正记录、体育结算记录、因厂商延迟晚到的记录,都出现在它们进入时刻所在的时间窗——按时间窗向前增量拉取不会漏行,无需回拉旧窗口。建议时间窗终点比当前时刻至少早 1 分钟(或相邻时间窗重叠 1 分钟,按 record_id 去重)。valid_bet(有效投注,已排除对押/刷水),不要用 bet。记录粒度因游戏类型而异:多数游戏一局一条;捕鱼/老虎机可能整段游玩合并一条;体育投注单与结算单各一条。source=adjustment、金额为被冲销记录的负值、ref_record_id 指向它);②更正记录(改判后的全量值、ref_record_id 同指原记录)。你按时间窗增量拉取天然拿到修正,不用回拉旧窗口;对 status=settled 的记录求和(Σwin−Σbet、Σvalid_bet)净额恒正确——负值就是为了让最朴素的求和也不出错。示例(原局赢 10 改判为输):原 {bet 10.00, win 20.00} → 追加 {bet -10.00, win -20.00, source adjustment, ref_record_id} 与 {bet 10.00, win 0.00, ref_record_id}。负值只出现在 source=adjustment 的冲销记录上,其余一切金额恒非负。unsettled 是体育型投注单的首见快照(bet=原注额、win=0、无 settled_at),首见后不再更新——结算时另追加一条 settled 全量结算记录(同 provider_record_id/round_id,「投注单与结算单各一条」说的就是这两条);canceled / refunded 记录金额保留原注额、只是事实快照——照单全收后务必按 status 过滤,别把作废单的 bet 加进流水。冲销记录的 status 与被冲销记录一致,同进同出。部分退款不用 refunded:以 settled + 调整后金额的更正记录下发(refunded 仅限全额退)。请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| from | string | 必填 | 开始时间(含),RFC 3339;比较记录的 recorded_at(进入本平台的时刻) | "2026-07-05T00:00:00.000Z" |
| to | string | 必填 | 结束时间(不含):from ≤ recorded_at < to | "2026-07-06T00:00:00.000Z" |
| cursor | string|null | 可选 | 黑盒游标,原样传回 | null |
| limit | integer | 可选 | 1–2000 | 2000 |
| player_id | string | 可选 | ≤ 64 字符;按玩家过滤(客诉排查免全量下载) | "wang-123" |
| provider | string | 可选 | 按厂商过滤(厂商族码,来自本面 providers/list 的 code) | "pg" |
响应字段(Record 对象;records/get 同形)
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| record_id | string | 总是有 | 唯一 ID(rec_)——去重主键、records/get 查询键 | "rec_01H8XGJWBW" |
| player_id | string | 总是有 | 玩家标识 | "wang-123" |
| provider | string | 总是有 | 厂商代号(厂商族码,来自本面 providers/list 的 code) | "pg" |
| provider_product | string | 不一定有 | 厂商产品维度键回显(多产品线厂商才出现,如 db 的 card)——按产品线对账用 | "card" |
| game_code | string | 总是有 | 游戏键,与目录一致(不透明键,原样回传,不要自行拆游戏段) | "pg:fortune-tiger" |
| category | string | 总是有 | 品类(值域同 games/list)。按记录的 game_code 查目录得到、入账时快照(日后类目改映不追溯);目录查不到该码时若该厂商实例只有一个品类(体育 / 真人类大厅厂商)则取它,否则为空串 ""——键恒在、不编 | "slots" |
| game_detail | string | 不一定有 | 可选。记录带有比游戏键更细的玩法信息(体育项目、桌台、彩种等)时给出其可读名称,只供显示;不要用作分组或关联键,分组请用 game_code / category。 | "Soccer" / "BaccaratClassic" |
| currency | string | 总是有 | 币种 | "BRL" |
| round_id | string | 总是有 | 厂商侧回合标识(归一后)。注意:单一钱包面(/v1/seamless/records/*)同名字段是我方回合 ID(rnd_,与钱包回调同值),两面含义不同,同时接两面时请分开处理 | "rnd_9f2k1" |
| bet | string | 总是有 | 原始投注额(未排除对押);仅冲销记录(source=adjustment)可为负 | "10.00" |
| valid_bet | string | 总是有 | 有效投注额——反水/杀率用它;冲销记录的负值使求和净额天然正确 | "10.00" |
| win | string | 总是有 | 派彩额。玩家输赢 = win − bet(可推导,不设差额字段;对负值冲销行同样成立) | "15.50" |
| source | string | 总是有 | game | freespin | promo | adjustment(补偿更正——含冲销记录:金额为负、恒带 ref_record_id;可增补) | "game" |
| status | string | 总是有 | unsettled | settled | canceled | refunded | "settled" |
| jackpot.win | string | 不一定有 | 仅该局含彩池派彩时出现(没有平铺恒 0 列) | "3.00" |
| provider_record_id | string | 不一定有 | 厂商侧原始单号——客诉排障时报给我们;改判时同一单号对应多条记录 | "8865512900" |
| ref_record_id | string | 不一定有 | 冲销/更正记录指向被冲销原记录的 record_id(2026-07-19 加法新增);原记录永不被修改或删除 | "rec_01H8XGJWBW" |
| session_id | string | 不一定有 | 能归属时给(ses_) | "ses_01H8XGJWBW" |
| started_at | string | 总是有 | 本局开始时间;合并型记录 = 进房时间(照厂商口径) | "2026-07-05T10:11:02.000Z" |
| settled_at | string | 不一定有 | 结算时间;unsettled 时缺省 | "2026-07-05T10:11:05.000Z" |
| recorded_at | string | 总是有 | 记录进入 PlayRouter 的时刻(2026-10-12 新增)——时间窗按它切;改判 / 结算 / 厂商延迟晚到的记录晚于 started_at | "2026-07-05T10:12:30.000Z" |
REQUEST
// 点「拉取」
RESPONSE
//
POST/v1/transfer/transfers/get 可选 · 推荐
按 transfer_id 或 idempotency_key 查单笔划拨,最近 1 个月在线可查(更早归档调取,与列表查询窗口同口径)。这不是重试的前置仪式——拿不到响应直接同 key 重发 create;本端点服务两个场景:pending 收尾轮询、运维排障反查。查无此单 404 transfer_not_found。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| transfer_id | string | 二选一 | trf_ 前缀 | "trf_01H8XGJWBW" |
| idempotency_key | string | 二选一 | 用创建时的幂等键反查 | "tf-ord-889231" |
响应 = { "data": Transfer },与 transfers/create 响应同一对象(不搞两套 schema)。
REQUEST
// 点「查询」
RESPONSE
//
POST/v1/transfer/records/get 可选 · 推荐
客诉单查:按 record_id 查单笔游戏记录,最近 1 个月在线可查(更早归档调取,与列表查询窗口同口径)——不用重拉整段列表定位那一条。响应在 Record 对象之外可选给 detail_url(厂商牌局详情页,给客服/玩家看的证据页);厂商给不出则缺省。查无此单 404 record_not_found。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| record_id | string | 必填 | rec_ 前缀(records/list 返回) | "rec_01H8XGJWBW" |
| locale | string | 可选 | 详情页语言;不支持降级 en | "pt" |
响应字段
| 字段 | 类型 | 出现 | 说明 | 示例 |
|---|---|---|---|---|
| (Record 全字段) | — | 总是有 | 与 records/list 同一对象 | — |
| detail_url | string | 不一定有 | 厂商牌局详情页链接;厂商无详情页则缺省(不编造) | "https://records...." |
REQUEST
// 点「查询」
RESPONSE
//
POST/v1/transfer/sessions/terminate 可选
尽力而为的踢出扇出(player_id 或 session_id 二选一)。能否踢出、踢出后玩家能否重登,效果因厂商而异。RG/自我排除的硬闸门在转账模式 = 拒绝该玩家后续 deposit(划拨在你手里)+ 我们对厂商侧封禁通道的扇出。注意:踢出不使游戏提前结算——局内锁定余额仍要等局结束才能下分。
请求字段
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
| player_id | string | 二选一 | ≤ 64 字符;终止该玩家全部活跃会话 | "wang-123" |
| session_id | string | 二选一 | 指名终止单个会话 | "ses_01H8XGJWBW" |
响应 = { "data": {} }(200 表示扇出已执行,不担保厂商侧踢出结果)。非资金、天然幂等,不带 idempotency_key。
REQUEST
// 点「终止」
RESPONSE
//
错误与 reason
两层分开记:HTTP 错误(传输/配置问题,body 为固定 ErrorResponse)和 reason(划拨的业务结局,藏在 200 的 status:"failed" 里,枚举见下表)。HTTP 层你只需要 4 个分支:
| HTTP | 动作 | 本产品会出现的 code |
|---|---|---|
| 2xx | 用 body(含 status:"failed" 的业务结局) | — |
| 429 | 按 Retry-After 重试 | rate_limited |
| 5xx / 超时 | 同 idempotency_key 重试 | internal_error / provider_error / service_unavailable(provider_timeout 为预留码,目前不会出现) |
| 其余 4xx | 终态:记日志等人修 | 配置或请求问题——逐码表见 附录 · 速查 |
reason 枚举(划拨的业务结局 · 统一所有厂商的失败形态)
只在 200 + status:"failed" 里出现——这不是错误,是合法业务答复;处置分支在「上分 / 下分流程」的取回全部循环里已写全。
| reason | 含义 | 你该做什么 |
|---|---|---|
| insufficient_funds | (下分)游戏钱包余额不足——通常是查询与取款之间玩家有一局结算了 | 重查 balance 再取 |
| game_limit | 该游戏局内禁划拨(斗地主/抢庄牛牛型对局游戏) | 提示玩家退出游戏,或等局结束重试 |
| player_in_game | 玩家正在游戏中,此时不能划拨 | 稍后重试(建议 ≥60s) |
| player_blocked | 玩家被厂商或风控封禁 | 终态;人工处理 |
| amount_out_of_range | 超出厂商单笔/余额上限(目前基本不出现:只在我方人工核对后落终态时可能给出) | 改金额后用新 idempotency_key 重新发起 |
| provider_unavailable | 厂商暂不可用(维护/故障)——资金未动 | 稍后用新 idempotency_key 重新发起(同 key 只会重放这次 failed) |
| provider_rejected | 厂商确定性拒绝(参数/单号/风控类,重试同样被拒) | 终态;记录并人工处理,带 X-Request-Id 报障 |
| not_executed | 这笔划拨确认未被执行——资金未动 | 终态,不会再变;上分退回主钱包扣款、下分不入账;可用新 idempotency_key 重新发起 |
附录 · 速查
写代码时贴在手边的两张表。逐字段权威以 playrouter-transfer-wallet-v1.openapi.yaml 为准。
ID 前缀约定
| 前缀 | 含义 |
|---|---|
| trf_ | 划拨(transfers/create 返回,transfers/get 的查询主键——请持久化) |
| rec_ | 游戏记录(records/list 去重主键、records/get 查询键) |
| rnd_ | 游戏回合(records 内的厂商回合标识,归一后) |
| ses_ | 游戏会话(sessions/create 返回) |
| req_ | 请求追踪(错误体 / 响应头 X-Request-Id) |
没有 txn_(零回调,无交易流——输赢在 rec_ 记录里);没有 cmp_(转账产品无活动模块)。
完整错误码目录(27 个)
与 Seamless 产品共用同一错误模型;转账专属 3 码已标注 ★。业务结局(余额不足、局内锁)不在此表——那是 200 + status:"failed" + reason,枚举见「错误与 reason」。
| HTTP | code | 触发场景 |
|---|---|---|
| 400 | malformed_request | body 非合法 JSON |
| 401 | invalid_signature | HMAC 对不上 |
| 401 | invalid_timestamp | t 出 ±300s 窗(重放或时钟漂移) |
| 401 | unknown_key | Key-Id 不存在 / 已摘除 |
| 403 | account_suspended | 账号被停用 |
| 403 | feature_not_enabled | 功能未对你开通(转账产品当前无可开通模块——预留码,词汇表统一保留) |
| 403 | provider_not_enabled | 本面当前不提供该厂商(或产品线)——未接入本面,或已被平台停用;以本面 providers/list 为准 |
| 403 | product_not_enabled | 产品线未开通——账号未开通 Transfer 面时,/v1/transfer/… 前缀下的全部端点(含 sessions / games / providers / currencies)均返本码;已开通的 seamless 面前缀不受影响(契约 v2:面由路径前缀承载) |
| 403 | ip_not_allowed | 来源 IP 不在你为该环境配置的白名单内(可选功能;名单为空不校验;无法判定来源 IP 时同码)——把服务器全部出口 IP(双栈含 v4 与 v6)加入 console「API settings」名单,约 30 秒生效 |
| 404 | not_found | 路径不存在 |
| 404 | game_not_found | game_code 不存在 |
| 404 | player_not_found ★ | 本平台从未见过该 player_id(你从未用它发起过一次被受理的 transfers/create——返回 200、不论 completed / failed——也从未用它成功建过真钱会话;被 4xx 拒的请求不登记玩家)——只在 wallet/balance · wallet/balances 出现。不是「在该厂商尚无钱包」:玩家已在平台登记、只是从未在该厂商上分 → balance 回 200 + balance:"0.00",withdraw 回 200 + status:"failed" + reason:"insufficient_funds"(用户裁决 2026-09-17) |
| 404 | transfer_not_found ★ | transfers/get 查无此单 |
| 404 | record_not_found | records/get 查无此记录 |
| 404 | session_not_found | 引用的会话不存在 |
| 409 | idempotency_key_reused | 同 key 不同 body——修 bug,绝不执行 |
| 413 | payload_too_large | 请求 body 超过大小上限——报文瘦身后重试 |
| 422 | validation_failed | 字段缺失 / 类型错 / 超限(fields 逐字段给出,含时间窗越界)。transfers/create 的 amount 小数位超过该厂商接口能接受的位数(个别厂商少于币种目录,例如最多 3 位)也返本码,fields.amount = exceeds N decimals accepted by provider——不建单、资金未动,改成该位数以内重新发起即可 |
| 422 | currency_not_supported | 平台 / 游戏 / 厂商不支持该币种。实例:saba 实例只登记 USD,CNY 上分或 real 启动 → currency_not_supported——处置是换成该厂商支持的币种(看 providers/list.currencies),不是换成玩家钱包币种。平台侧暂时不可用时 real 启动也返此码,fields.currency = temporarily unavailable(固定值,可按它程序判断)——此时不要换币种(钱包币种在首次划拨 / 首次真钱启动时锁定:换币种要么撞 currency_mismatch,要么把新玩家锁成错误币种),稍后重试同一请求即可;上下分不受影响。玩家钱包已锁定其它币种时先返 currency_mismatch |
| 422 | currency_mismatch ★ | 请求币种 ≠ 该玩家已锁定的钱包币种(单币种钱包防呆)。实例:玩家首笔划拨锁定 CNY 钱包后再发 USD 请求 → currency_mismatch,message 点名钱包币种("Wallet currency is CNY."),按它重发 |
| 422 | game_not_available | 游戏存在但当前不可用(下架 / 地域 / 未到 released_at),或厂商拒绝该玩家进入(如玩家账号被停用)——重试同一请求不会成功。平台侧暂时不可用时 sessions/create 也返此码,fields.game_code = temporarily unavailable(固定值,可按它程序判断)——游戏没有下架,不要从大厅撤下,稍后重试同一请求即可;上下分不受影响 |
| 422 | demo_not_available | demo 请求但游戏不支持 |
| 429 | rate_limited | 超配额——按 Retry-After 重试。配额按 API Key 计、以下限保证公布:每 key 每分钟至少 records/list 150 次(本面与单一钱包面的 records/list 两面合计)、transactions/list 60 次(单一钱包端点,跨产品面调用同受此档)、其余端点 1000 次(实际可能更高,下限只放宽不收紧);RateLimit-* 头按端点给出勿跨端点缓存,建议(非强制)按 RateLimit-Remaining 自适应节流;回补历史可联系临时提额 |
| 500 | internal_error | 我们的故障——同 idempotency_key 重试安全 |
| 502 | provider_error | 上游厂商故障(仅瞬态——上游的确定性拒绝会映射为对应 4xx 语义码,不会以 502 出现;收到 502 放心重试) |
| 503 | service_unavailable | 维护 / 过载 |
| 504 | provider_timeout | 预留码,目前不会出现;如遇到,同 idempotency_key 重试即可 |
划拨业务结局 reason 速查(8 个 · 只在 200 + status:"failed" 出现,正文「错误与 reason」为准)
| reason | 含义 | 你该做什么 |
|---|---|---|
| insufficient_funds | (下分)游戏钱包余额不足 | 重查 balance 再取 |
| game_limit | 该游戏局内禁划拨 | 等局结束重试 |
| player_in_game | 玩家正在游戏中,此时不能划拨 | 稍后重试(建议 ≥60s) |
| player_blocked | 玩家被厂商或风控封禁 | 终态;人工处理 |
| amount_out_of_range | 超出厂商单笔/余额上限(目前基本不出现) | 改金额后换新 key 重新发起 |
| provider_unavailable | 厂商暂不可用(资金未动) | 稍后换新 key 重新发起 |
| provider_rejected | 厂商确定性拒绝(重试同样被拒) | 终态;人工处理 |
| not_executed | 这笔划拨确认未被执行(资金未动) | 终态,不会再变;退回 / 不入账,可换 key 重新发起 |
status 全枚举:completed · pending(≥30s 轮询 transfers/get 至终态)· failed(上表 reason)。
404 也用于存在但不属于你的资源(越权响应与"不存在"不可分辨——防跨商户枚举探测);403 只表示功能 / 厂商未开通类主体级权限,不涉及具体资源。
FAQ
为什么没有"一键取回全部"(withdraw_all)?
因为它是我们给不出的承诺:"全部"只有在钱包静止时才有确定值,而没有任何厂商保证跨局静止(玩家关窗 ≠ 局结束)。诚实的答案是「取回全部」参考循环——你写一次,全厂商通用,每一步的失败原因都有统一 reason 可分支。
划拨超时没拿到响应,我该重发还是先查单?
直接同 idempotency_key 重发,恒安全(在同一区内)——命中会重放原响应并带 Idempotency-Replayed: true 头。transfers/get 是给 pending 收尾和排障用的,不是重试的前置步骤。
status:"pending" 多久出现一次?要怎么处理?
极少(表示这笔划拨仍在确认中,我方会给出终态)。出现时进你的异常订单队列,用 transfers/get 以 ≥30 秒间隔轮询,终态必然落到 completed 或 failed;终态前不要给玩家主钱包入账。时限承诺:pending 超过 1 小时未收敛即转我方人工介入(我方核对后落终态,无需你处理),终态仍通过 transfers/get 给出;受理后如确认这笔划拨未被执行,会以 failed / not_executed 结束(通常在受理后十余分钟内);资金未动:上分退回主钱包扣款、下分不入账,可换新的 idempotency_key 重新发起;这一结论是终态,不会再变。你侧轮询可在 1 小时后降频,不必更密。另:极少数情况下(厂商暂不可用)划拨会直接答 failed / provider_unavailable,上下分皆然;这笔首发还在进行时你同 key 重发或查单,可能先看到 pending、随后变为 failed / provider_unavailable。这一笔资金未动、之后也不会再被执行,按 failed 处置(上分退回主钱包扣款、下分不入账),稍后用新的 idempotency_key 重新发起即可。
玩家换游戏(跨厂商)时余额怎么办?
逐厂商钱包:先 withdraw 从 A 家取回、确认 completed,再 deposit 到 B 家。同厂商内换游戏不需要划拨。建议在玩家离开某厂商游戏时自动触发「取回全部」流程,避免余额长期停在厂商侧。
为什么 records/list 是必须?我能不能不接?
不能。转账模式下游戏期间我们不回调你——玩家输赢、有效投注、彩池派彩全部只能从 records/list 拉。不接它你就没有账本,反水、风控、财务对账都无从谈起。
transferable 缺省的厂商怎么安全下分?
按 balance 发起 withdraw,失败时看 reason:insufficient_funds 重查再取(余额刚变了)、game_limit / player_in_game 等局结束或稍后重试。「取回全部」参考循环已覆盖这些分支。
大面值币种(IDR/VND/COP)要除以 1000 吗?
不要。没有 K 货币单位——金额是字符串十进制,按 /v1/transfer/currencies 公布的 decimals 直接传真实面值。如果你的系统里有 ÷1000/×1000 的换算层,接入时请去掉,那是对账事故的高发源。
以后想升级 Seamless Wallet(单一钱包)要重接吗?
目录/会话/币种 5 个端点(sessions/create·terminate、games/list、providers/list、currencies)字段逐字相同,只是路径前缀不同(/v1/transfer/… → /v1/seamless/…),切换只改前缀。变化:撤掉 transfers / wallet 两组,改为实现 5 个钱包回调;records 两端点单一钱包面也有(/v1/seamless/records/list · get),字段同名,但 round_id、valid_bet 的含义不同、资金对账改用 transactions/list——见单一钱包文档 records 一节。签名、错误模型、幂等机制不变。
下载与资源
⬇ 转账产品 · OpenAPI 3.1(playrouter-transfer-wallet-v1.openapi.yaml) ⬇ 本页 Markdown 版 · for LLM(playrouter-transfer-docs.llm.md)OpenAPI 文件可直接导入 Postman / Insomnia 生成请求集合,11 端点自包含(含签名 / 幂等 / 错误说明),可直接生成客户端 SDK 桩。Markdown 版与本页内容一致,专供投喂 AI 编码助手。