Slot Provider API v1 接入文档
文档类型:B2B Slot 游戏供应商 / 单钱包接入
API 版本:v1
文档版本:1.0.0
状态:生产环境设计基线
最后更新:2026-08-30
目录
- 文档说明
- 系统角色与整体架构
- 核心设计原则
- 环境与基础地址
- 接入前需要交换的资料
- 通用请求规范
- 金额、币种与精度
- 身份认证与 HMAC 签名
- 幂等、重试与并发控制
- 游戏 Session 生命周期
- Operator → Provider API
- Provider → Operator Wallet API
- Round 与 Transaction 生命周期
- Free Spins API
- Bonus Buy
- Jackpot 扩展
- 游戏历史、Replay 与对账
- 错误码规范
- 超时、重试与故障恢复
- 安全要求
- 数据库与账本建议
- 第三方标准接入流程
- 完整单局调用示例
- 异常场景处理
- 联调测试用例
- 上线检查清单
- 版本兼容策略
- 合规与责任边界
- 参考资料
1. 文档说明
本规范用于第三方 Casino、游戏平台、游戏聚合平台或其他 Operator 接入本 Slot Game Provider。
本系统采用 Seamless Wallet(单钱包) 模式:
- 玩家账户及真实余额由 Operator 保存。
- Provider 不持有玩家真实主钱包余额。
- 玩家进入游戏后,Provider 通过 Operator 提供的 Wallet API 查询余额。
- 每次下注由 Provider 调用 Operator 的
bet接口实时扣款。 - 每次中奖由 Provider 调用 Operator 的
win接口实时加款。 - 发生异常时通过
refund/rollback/cancel恢复资金。 - 所有资金交易必须具有唯一
transaction_id,并进行严格幂等处理。
本规范同时定义:
- 游戏列表
- 游戏启动
- Demo 游戏
- Session
- 玩家钱包
- Bet
- Win
- Refund
- Rollback
- Free Spins
- Bonus Buy
- Jackpot 扩展
- Round 查询
- Transaction 查询
- Replay
- HMAC 签名
- 幂等
- 超时重试
- 错误码
- 联调与上线要求
2. 系统角色与整体架构
2.1 角色定义
| 名称 | 说明 |
|---|---|
| Operator | 接入本 Provider 的第三方赌场、游戏平台或聚合商 |
| Provider | 本老虎机游戏供应商 |
| Player | Operator 的最终玩家 |
| Game Client | Provider 提供的 H5 / Web 游戏客户端 |
| Game Server | Provider 的游戏逻辑、RNG、Round、派奖服务器 |
| Operator Wallet | Operator 提供的钱包接口 |
| Backoffice | Provider / Operator 的后台管理系统 |
2.2 标准架构
┌─────────────────────┐
│ Operator │
│ │
│ User / Wallet / KYC │
└──────────┬──────────┘
│
│ POST /v1/game/launch
▼
┌─────────────────────┐
│ Provider API │
│ │
│ Session / Games │
└──────────┬──────────┘
│
│ game_url
▼
┌─────────────────────┐
│ Game Client │
│ H5/Web │
└──────────┬──────────┘
│
│ Spin
▼
┌─────────────────────┐
│ Game Server │
│ RNG / Round / Payout│
└──────────┬──────────┘
│
│ balance / bet / win / refund
▼
┌─────────────────────┐
│ Operator Wallet │
└─────────────────────┘3. 核心设计原则
3.1 服务器间调用(Server-to-Server)
所有涉及资金、Session 创建、Free Spins、运营配置的接口必须由服务器调用服务器。
禁止:
浏览器 → Provider Management API
浏览器 → Operator Wallet API
Game Client → Operator Wallet API必须:
Operator Backend → Provider API
Provider Game Server → Operator Wallet API3.2 游戏客户端不决定开奖结果
以下内容必须由 Provider Game Server 计算:
- RNG
- Reels
- Symbols
- Win Lines / Ways
- Multiplier
- Scatter
- Free Spins
- Bonus
- Jackpot
- 最终 payout
Game Client 只负责:
- 展示
- 动画
- 音效
- 用户操作
- 将 Spin 指令提交给 Provider Game Server
3.3 资金以 Operator Wallet 为最终账本
Provider 的游戏交易表是游戏账本和审计记录。
Operator 的钱包余额是玩家资金最终权威来源。
3.4 所有资金操作必须可重放
网络超时不代表交易失败。
任何 bet、win、refund、rollback 请求都可能重复到达。
因此:
相同
transaction_id的重复请求必须返回第一次成功处理后的结果,绝不能再次扣款或加款。
4. 环境与基础地址
建议提供至少两个完全隔离的环境。
4.1 沙箱环境(Sandbox)
Provider API:
https://sandbox-api.provider.example
Game:
https://sandbox-game.provider.example
Backoffice:
https://sandbox-bo.provider.example4.2 生产环境(Production)
Provider API:
https://api.provider.example
Game:
https://game.provider.example
Backoffice:
https://bo.provider.example4.3 API 版本
所有 Provider API 路径必须带版本:
/v1/...例如:
POST /v1/game/launch
GET /v1/games
GET /v1/rounds/{round_id}重大不兼容升级使用:
/v2/5. 接入前需要交换的资料
5.1 Provider 提供给 Operator
operator_id
api_key
api_secret
provider_api_url
game_domain
provider_callback_ips
supported_currencies
supported_languages
API documentation
sandbox credentials5.2 Operator 提供给 Provider
operator_id
wallet_url
wallet_callback_secret
allowed_currencies
allowed_countries
operator_callback_ips
return_url
brand_id(可选)示例:
operator_id: casino_001
wallet_url: https://api.operator.com/provider-wallet/v1
currency: USD, EUR, USDT6. 通用请求规范
6.1 Content-Type
Content-Type: application/json
Accept: application/json统一使用 UTF-8。
6.2 时间格式
业务时间字段使用 ISO 8601 UTC:
2026-08-30T02:30:15.123ZHMAC 请求头中的时间使用 Unix Timestamp 秒:
17880570156.3 ID 格式
建议所有 ID 为 String。
示例:
operator_id = casino_001
player_id = 100086
session_id = ses_01K...
round_id = rnd_01K...
transaction_id = txn_01K...
game_id = slot_super_ace
campaign_id = fsp_01K...不要假设第三方的 player_id 一定是数字。
7. 金额、币种与精度
7.1 禁止使用浮点数计算真钱
禁止:
const balance = 0.1 + 0.2;资金必须使用:
- Decimal
- BigDecimal
- BCMath
- Decimal.js
- 数据库 DECIMAL
- 或整数最小单位
7.2 本协议金额格式
为了兼容 Fiat 与 Crypto,本规范使用 十进制字符串:
{
"amount": "10.00",
"currency": "USD"
}USDT:
{
"amount": "10.123456",
"currency": "USDT"
}禁止:
{
"amount": 10.123456
}7.3 币种代码
优先使用 ISO 4217:
USD
EUR
GBP
SGD
JPYCrypto 可配置:
USDT
USDC
BTC
ETHOperator 与 Provider 必须提前配置每种币种最大精度。
例如:
| Currency | Decimals |
|---|---|
| USD | 2 |
| EUR | 2 |
| JPY | 0 |
| USDT | 6 |
| BTC | 8 |
8. 身份认证与 HMAC 签名
建议两个方向使用不同密钥。
8.1 Operator → Provider
请求头:
X-Operator-Id: casino_001
X-API-Key: pk_live_xxxxxxxxx
X-Timestamp: 1788057015
X-Nonce: 7f0a39c80d72406d98a95ec10630aebb
X-Signature: v1=54c9...签名字符串:
{timestamp}.{nonce}.{raw_request_body}算法:
HMAC-SHA256(signing_string, api_secret)最后:
X-Signature = "v1=" + lowercase_hex_digest8.2 Provider → Operator Wallet
请求头:
X-Provider-Id: provider_001
X-Operator-Id: casino_001
X-Timestamp: 1788057015
X-Nonce: a83f7e2bd9d64d9386f36cc4b48382ba
X-Signature: v1=12df...使用 Operator 为当前接入分配的:
wallet_callback_secret签名方式相同:
timestamp + "." + nonce + "." + raw_body8.3 验签要求
接收方必须:
- 读取原始 HTTP Body。
- 检查
X-Timestamp。 - 检查
X-Nonce。 - 根据 Secret 重新计算 HMAC-SHA256。
- 使用 constant-time comparison。
- 验签成功后才能 JSON decode。
- Nonce 在有效时间窗口内不得重复。
不要:
JSON decode
→ 重新 JSON encode
→ 再计算签名因为字段顺序和空格变化可能导致签名不同。
8.4 防重放时间窗口(Replay Window)
建议:
±300 秒超过范围:
401 Unauthorized错误:
{
"code": "INVALID_TIMESTAMP",
"message": "Request timestamp is outside the allowed window."
}9. 幂等、重试与并发控制
9.1 transaction_id
所有资金交易必须有全局唯一:
transaction_id例如:
txn_bet_01K...
txn_win_01K...
txn_refund_01K...9.2 重复请求
第一次:
Balance = 100
BET = 10处理后:
Balance = 90Provider 没收到响应,5 秒后重试相同:
transaction_id = txn_bet_001Operator 必须返回:
{
"code": "OK",
"transaction_id": "txn_bet_001",
"balance": "90.00",
"currency": "USD"
}不能再次扣款。
9.3 请求内容(Payload)不一致
如果相同 transaction_id 第二次请求:
第一次:
{
"transaction_id": "txn_bet_001",
"amount": "10.00"
}第二次:
{
"transaction_id": "txn_bet_001",
"amount": "20.00"
}必须拒绝:
409 Conflict{
"code": "IDEMPOTENCY_CONFLICT",
"message": "Transaction already exists with different payload."
}9.4 数据库事务
Wallet 侧建议:
BEGIN
SELECT player balance FOR UPDATE
检查 transaction_id
INSERT wallet_transaction
UPDATE player balance
COMMIT必须避免:
先查余额
→ 不加锁
→ 两个请求同时扣款10. 游戏 Session 生命周期
标准流程:
CREATED
↓
ACTIVE
↓
EXPIRED / CLOSED建议 Session:
单次启动 URL 有效时间:30~120 秒
游戏 Session TTL:30~120 分钟具体值可按 Operator 配置。
Session 至少保存:
session_id
operator_id
player_id
game_id
currency
language
country
ip
user_agent
created_at
expires_at
status重要:
Session 过期后禁止创建新的 Bet,但已经成功创建的 Round 对应的 Win / Refund / Rollback 必须继续允许结算。
否则可能造成玩家已扣款但无法派奖。
11. Operator → Provider API
11.1 获取游戏列表
GET /v1/gamesQuery:
type=slot
status=active
page=1
page_size=100Response:
{
"code": "OK",
"data": {
"items": [
{
"game_id": "slot_super_ace",
"name": "Super Ace",
"type": "slot",
"provider": "YOUR_PROVIDER",
"rtp": "96.50",
"volatility": "high",
"reels": 5,
"rows": 3,
"pay_type": "243_ways",
"demo_supported": true,
"free_spins_supported": true,
"bonus_buy_supported": true,
"jackpot_supported": false,
"languages": ["en", "zh-CN", "th"],
"currencies": ["USD", "EUR", "USDT"],
"status": "active",
"thumbnail": "https://cdn.provider.example/games/slot_super_ace.png"
}
],
"page": 1,
"page_size": 100,
"total": 1
}
}11.2 获取单个游戏
GET /v1/games/{game_id}Response:
{
"code": "OK",
"data": {
"game_id": "slot_super_ace",
"name": "Super Ace",
"type": "slot",
"rtp": "96.50",
"volatility": "high",
"status": "active"
}
}11.3 启动真钱游戏
POST /v1/game/launchRequest:
{
"player_id": "100086",
"game_id": "slot_super_ace",
"currency": "USD",
"language": "en",
"country": "SG",
"return_url": "https://operator.example/casino",
"device": "mobile",
"platform": "web",
"metadata": {
"brand_id": "brand_001"
}
}字段:
| Field | Required | Description |
|---|---|---|
| player_id | Yes | Operator 玩家唯一 ID |
| game_id | Yes | Provider 游戏 ID |
| currency | Yes | 当前 Session 币种 |
| language | Yes | UI 语言 |
| country | Recommended | ISO 3166-1 alpha-2 |
| return_url | No | 离开游戏返回地址 |
| device | No | mobile / desktop / tablet |
| platform | No | web / app |
| metadata | No | 第三方扩展参数 |
Response:
{
"code": "OK",
"data": {
"session_id": "ses_01K4N7A6S0...",
"game_url": "https://game.provider.example/play?t=eyJ...",
"expires_at": "2026-08-30T03:00:00Z"
}
}game_url 安全要求
- URL 应包含短期 Token。
- 不直接暴露 API Secret。
- 不直接暴露 Wallet Secret。
- Token 应绑定 Session。
- Token 应设置过期时间。
- 最好一次启动生成一个新的 URL。
11.4 启动 Demo 游戏
POST /v1/game/demoRequest:
{
"game_id": "slot_super_ace",
"language": "en",
"country": "SG",
"device": "mobile"
}Response:
{
"code": "OK",
"data": {
"game_url": "https://game.provider.example/demo?t=eyJ...",
"expires_at": "2026-08-30T03:00:00Z"
}
}Demo 不允许产生真实 Wallet Transaction。
11.5 获取 Session
GET /v1/sessions/{session_id}Response:
{
"code": "OK",
"data": {
"session_id": "ses_001",
"player_id": "100086",
"game_id": "slot_super_ace",
"currency": "USD",
"status": "active",
"created_at": "2026-08-30T01:00:00Z",
"expires_at": "2026-08-30T02:00:00Z"
}
}11.6 主动关闭 Session
POST /v1/sessions/{session_id}/closeRequest:
{
"reason": "operator_logout"
}关闭后:
- 禁止创建新 Bet。
- 已存在未完成 Round 仍允许结算 Win / Refund。
12. Provider → Operator Wallet API
Operator 必须实现以下接口。
假设:
WALLET_URL=https://api.operator.example/provider-wallet/v112.1 查询余额
POST {WALLET_URL}/balanceRequest:
{
"operator_id": "casino_001",
"player_id": "100086",
"session_id": "ses_001",
"game_id": "slot_super_ace",
"currency": "USD"
}Response:
{
"code": "OK",
"player_id": "100086",
"balance": "1000.00",
"currency": "USD"
}规则
- 只能返回 Session 币种的余额。
- Currency 不匹配必须报错。
- 不要自动进行货币转换。
balance必须为字符串。
12.2 Bet 扣款
POST {WALLET_URL}/betRequest:
{
"operator_id": "casino_001",
"player_id": "100086",
"session_id": "ses_001",
"game_id": "slot_super_ace",
"round_id": "rnd_001",
"transaction_id": "txn_bet_001",
"amount": "10.00",
"currency": "USD",
"bet_type": "NORMAL",
"is_free_spin": false,
"is_bonus_buy": false,
"created_at": "2026-08-30T01:10:00.000Z"
}Response:
{
"code": "OK",
"transaction_id": "txn_bet_001",
"balance": "990.00",
"currency": "USD"
}余额不足:
422 Unprocessable Entity{
"code": "INSUFFICIENT_FUNDS",
"message": "Insufficient player balance.",
"balance": "5.00",
"currency": "USD"
}Provider 规则
如果 Bet 未获得明确成功响应:
不得认为下注成功,不得生成不可恢复的最终派奖状态。
Provider 应进行安全重试或交易状态查询。
12.3 Win 派奖
POST {WALLET_URL}/winRequest:
{
"operator_id": "casino_001",
"player_id": "100086",
"session_id": "ses_001",
"game_id": "slot_super_ace",
"round_id": "rnd_001",
"transaction_id": "txn_win_001",
"ref_transaction_id": "txn_bet_001",
"amount": "25.00",
"currency": "USD",
"win_type": "NORMAL",
"round_finished": true,
"created_at": "2026-08-30T01:10:01.000Z"
}Response:
{
"code": "OK",
"transaction_id": "txn_win_001",
"balance": "1015.00",
"currency": "USD"
}0 Win
建议允许:
{
"amount": "0.00",
"round_finished": true
}也可由双方约定 0 Win 不调用钱包,但 Provider 自己必须正确关闭 Round。
Session 已过期
如果 Bet 曾成功:
Operator 不得因为 Session 已过期而拒绝对应 Win。
12.4 Refund
用于返还一个已经成功的 Bet。
POST {WALLET_URL}/refundRequest:
{
"operator_id": "casino_001",
"player_id": "100086",
"session_id": "ses_001",
"game_id": "slot_super_ace",
"round_id": "rnd_001",
"transaction_id": "txn_refund_001",
"ref_transaction_id": "txn_bet_001",
"amount": "10.00",
"currency": "USD",
"reason": "game_round_failed",
"round_finished": true
}Response:
{
"code": "OK",
"transaction_id": "txn_refund_001",
"balance": "1000.00",
"currency": "USD"
}12.5 Rollback
Rollback 用于撤销一个已处理资金交易。
POST {WALLET_URL}/rollbackRequest:
{
"operator_id": "casino_001",
"player_id": "100086",
"session_id": "ses_001",
"game_id": "slot_super_ace",
"round_id": "rnd_001",
"transaction_id": "txn_rollback_001",
"ref_transaction_id": "txn_win_001",
"currency": "USD",
"reason": "settlement_correction"
}Response:
{
"code": "OK",
"transaction_id": "txn_rollback_001",
"balance": "990.00",
"currency": "USD"
}Refund 与 Rollback 区别
推荐语义:
| API | 用途 |
|---|---|
| refund | 返还一个 Bet 的全部或部分金额 |
| rollback | 反向撤销指定原交易 |
| cancel | 可选高级接口,用于 Round / Transaction 级取消 |
如果希望协议更简单,v1 可以只保留:
/bet
/win
/refund将 Rollback 作为 v1.1 扩展。
12.6 可选 Cancel API
POST {WALLET_URL}/cancelRequest:
{
"operator_id": "casino_001",
"player_id": "100086",
"game_id": "slot_super_ace",
"round_id": "rnd_001",
"transaction_id": "txn_cancel_001",
"ref_transaction_id": "txn_bet_001",
"cancel_type": "TRANSACTION",
"currency": "USD"
}cancel_type:
TRANSACTION
BET
ROUND13. Round 与 Transaction 生命周期
13.1 普通 Spin
ROUND CREATED
│
▼
BET
│
├── Lose ──► WIN amount=0 / close round
│
└── Win
│
▼
WIN
│
▼
ROUND FINISHED13.2 Free Spins
一个付费 Spin 可能触发多个后续 Game Action:
Round
│
├─ BET
│
├─ Base Win
│
├─ Free Spin #1 Win
│
├─ Free Spin #2 Win
│
├─ ...
│
└─ Final Win / round_finished=true你可以采用:
模式 A:一个 Round 包含整个 Free Spins Feature
适合:
触发 Free Spins
→ 10 次免费旋转
→ 最终整体结算模式 B:每次 Free Spin 一个 Sub Round
字段增加:
{
"parent_round_id": "rnd_001"
}无论采用哪一种:
文档和报表必须能够把所有子交易关联回原始付费 Round。
13.3 交易类型(Transaction Type)
推荐:
BET
WIN
REFUND
ROLLBACK
JACKPOT_WIN
JACKPOT_CONTRIBUTION
BONUS_BUY14. Free Spins API
Free Spins 是 Operator 给玩家发放的促销权益,不等同于老虎机内部自然触发的 Free Spin Feature。
14.1 创建 Free Spins
POST /v1/free-spinsRequest:
{
"campaign_id": "campaign_operator_20260830_001",
"player_id": "100086",
"game_id": "slot_super_ace",
"currency": "USD",
"spin_count": 20,
"bet_amount": "1.00",
"valid_from": "2026-08-30T00:00:00Z",
"valid_until": "2026-09-06T23:59:59Z"
}Response:
{
"code": "OK",
"data": {
"free_spin_id": "fsp_01K...",
"status": "active",
"remaining_spins": 20
}
}14.2 查询 Free Spins
GET /v1/free-spins/{free_spin_id}Response:
{
"code": "OK",
"data": {
"free_spin_id": "fsp_01K...",
"player_id": "100086",
"game_id": "slot_super_ace",
"spin_count": 20,
"used_spins": 5,
"remaining_spins": 15,
"total_win": "12.50",
"currency": "USD",
"status": "active"
}
}14.3 取消 Free Spins
POST /v1/free-spins/{free_spin_id}/cancelRequest:
{
"reason": "campaign_cancelled"
}已消费的 Spin 不回滚,除非双方另有约定。
15. Bonus Buy
如果游戏支持 Bonus Buy:
游戏信息返回:
{
"bonus_buy_supported": true
}Bet Callback:
{
"transaction_id": "txn_bb_001",
"round_id": "rnd_001",
"amount": "100.00",
"currency": "USD",
"bet_type": "BONUS_BUY",
"is_bonus_buy": true
}Operator 可按品牌或司法辖区禁用 Bonus Buy。
Provider 应支持 Operator 级配置:
bonus_buy_enabled = false禁用时 Game Client 不显示 Bonus Buy UI。
16. Jackpot 扩展
如未来支持 Progressive Jackpot,建议不要破坏基础 Bet/Win 结构。
Bet:
{
"transaction_id": "txn_bet_001",
"amount": "10.00",
"jackpot": {
"jackpot_id": "jp_mega",
"contribution": "0.10"
}
}Jackpot Win:
{
"transaction_id": "txn_jpwin_001",
"ref_transaction_id": "txn_bet_001",
"amount": "100000.00",
"currency": "USD",
"win_type": "JACKPOT",
"jackpot": {
"jackpot_id": "jp_mega"
}
}Jackpot 最好使用独立账本。
17. 游戏历史、Replay 与对账
17.1 查询 Round
GET /v1/rounds/{round_id}Response:
{
"code": "OK",
"data": {
"round_id": "rnd_001",
"operator_id": "casino_001",
"player_id": "100086",
"game_id": "slot_super_ace",
"currency": "USD",
"total_bet": "10.00",
"total_win": "25.00",
"status": "finished",
"started_at": "2026-08-30T01:10:00Z",
"finished_at": "2026-08-30T01:10:01Z",
"replay_url": "https://replay.provider.example/r/rnd_001?t=..."
}
}17.2 Round Transaction
GET /v1/rounds/{round_id}/transactionsResponse:
{
"code": "OK",
"data": [
{
"transaction_id": "txn_bet_001",
"type": "BET",
"amount": "10.00",
"currency": "USD",
"status": "success"
},
{
"transaction_id": "txn_win_001",
"type": "WIN",
"amount": "25.00",
"currency": "USD",
"status": "success"
}
]
}17.3 查询 Transaction
GET /v1/transactions/{transaction_id}Response:
{
"code": "OK",
"data": {
"transaction_id": "txn_bet_001",
"round_id": "rnd_001",
"player_id": "100086",
"game_id": "slot_super_ace",
"type": "BET",
"amount": "10.00",
"currency": "USD",
"status": "success",
"created_at": "2026-08-30T01:10:00Z"
}
}17.4 游戏活动报表(Gaming Activity Report)
推荐:
GET /v1/reports/gaming-activityQuery:
from=2026-08-30T00:00:00Z
to=2026-08-30T23:59:59Z
player_id=100086
game_id=slot_super_ace
page=1
page_size=100每行必须至少包含:
transaction_id
round_id
player_id
game_id
type
amount
currency
status
created_at
ref_transaction_id17.5 Replay
Provider 建议提供 Round Replay。
Replay 应可以展示:
游戏名称
Round ID
Bet
Win
时间
Reel / Symbol 结果
Multiplier
Free Spins
Bonus
最终 payoutReplay URL 必须:
- 签名。
- 有过期时间。
- 只读。
- 不允许产生任何资金交易。
18. 错误码规范
18.1 HTTP 状态码
| Status | Meaning |
|---|---|
| 200 | 成功 |
| 400 | 参数错误 |
| 401 | 鉴权或签名失败 |
| 403 | 无权限 / IP 不允许 |
| 404 | 资源不存在 |
| 409 | 幂等冲突 / 状态冲突 |
| 422 | 业务拒绝,例如余额不足 |
| 429 | Rate Limit |
| 500 | 服务内部错误 |
| 502 | 上游服务异常 |
| 503 | 临时不可用 |
18.2 标准业务错误码
OK
INVALID_REQUEST
INVALID_SIGNATURE
INVALID_TIMESTAMP
INVALID_NONCE
INVALID_API_KEY
OPERATOR_NOT_FOUND
OPERATOR_DISABLED
IP_NOT_ALLOWED
PLAYER_NOT_FOUND
PLAYER_DISABLED
GAME_NOT_FOUND
GAME_DISABLED
GAME_NOT_ALLOWED
SESSION_NOT_FOUND
SESSION_EXPIRED
SESSION_CLOSED
SESSION_CURRENCY_MISMATCH
INVALID_CURRENCY
CURRENCY_NOT_SUPPORTED
INVALID_AMOUNT
BET_LIMIT_EXCEEDED
INSUFFICIENT_FUNDS
ROUND_NOT_FOUND
ROUND_ALREADY_FINISHED
ROUND_STATE_CONFLICT
TRANSACTION_NOT_FOUND
DUPLICATE_TRANSACTION
IDEMPOTENCY_CONFLICT
FREE_SPIN_NOT_FOUND
FREE_SPIN_EXPIRED
FREE_SPIN_ALREADY_CANCELLED
RATE_LIMITED
TEMPORARY_UNAVAILABLE
INTERNAL_ERROR错误格式:
{
"code": "INSUFFICIENT_FUNDS",
"message": "Insufficient player balance.",
"request_id": "req_01K..."
}Production 环境不要返回:
SQL
数据库密码
Stack Trace
Secret
内部服务器路径19. 超时、重试与故障恢复
真钱系统必须假设任何网络请求都有以下可能:
请求根本没到
请求到了但响应丢了
对方已经成功处理但你认为失败
响应到了但你的服务宕机
重复发送
乱序到达19.1 钱包超时
推荐:
connect timeout: 2 秒
request timeout: 5 秒最终值双方联调确认。
19.2 重试策略
资金请求推荐:
0s
1s
3s
10s
30s
1m
5m不要无限高速重试。
必须保持:
同一个 transaction_id
同一个 payload19.3 待处理状态(Pending)
Provider 内部 Transaction 状态:
CREATED
PENDING
SUCCESS
FAILED
REVERSED超时不能直接标记为:
FAILED更安全:
PENDING然后重试 / 查询确认。
20. 安全要求
Production 最低要求:
20.1 传输安全
HTTPS TLS 1.2+禁止 HTTP。
20.2 API 密钥
Secret:
- 只能保存于服务端。
- 禁止放 Game Client。
- 禁止放前端 JS。
- 禁止写入 Git。
- 禁止出现在日志。
- 必须支持轮换。
20.3 IP 白名单
双方建议提供固定出口 IP。
Provider → Operator Wallet:
Operator allowlist Provider IPOperator → Provider:
Provider allowlist Operator IPIP Allowlist 只能作为第二层安全,不应替代 HMAC。
20.4 请求限流
示例:
Management API: 100 req/s / Operator
Launch API: 300 req/s / Operator
Wallet: 按容量规划,不应使用过低限制影响 Spin返回:
429 Too Many Requests
Retry-After: 120.5 日志
每个请求至少记录:
request_id
operator_id
endpoint
transaction_id
round_id
player_id
status
latency
timestamp必须脱敏:
api_secret
callback_secret
Authorization
完整 Token21. 数据库与账本建议
21.1 operators
id
operator_id
name
api_key_hash
api_secret_encrypted
wallet_url
wallet_callback_secret_encrypted
status
allowed_ips
created_at
updated_at21.2 games
id
game_id
name
type
rtp
volatility
status
free_spins_supported
bonus_buy_supported
jackpot_supported
created_at
updated_at21.3 game_sessions
id
session_id
operator_id
player_id
game_id
currency
language
status
ip
created_at
expires_at
closed_at21.4 game_rounds
id
round_id
operator_id
player_id
session_id
game_id
currency
total_bet
total_win
status
rng_reference
started_at
finished_at
created_at
updated_at21.5 game_transactions
id
transaction_id
ref_transaction_id
round_id
session_id
operator_id
player_id
game_id
type
amount
currency
request_payload_hash
status
wallet_response
retry_count
created_at
updated_at关键索引:
UNIQUE(transaction_id)
INDEX(round_id)
INDEX(operator_id, player_id)
INDEX(created_at)21.6 不可变账本
推荐额外维护不可变交易流水:
ledger_entries一旦记账:
不 UPDATE 原资金含义,而是通过新的反向 Transaction 修正。
例如:
BET -10
ROLLBACK +10而不是删除 BET。
这样方便:
- 财务审计
- Operator 对账
- 争议处理
- 游戏监管审计
22. 第三方标准接入流程
阶段 1:商务 / 技术资料
Operator 提供:
Company / Project
Technical contact
wallet_url
callback IP
supported currenciesProvider 提供 Sandbox Credential。
阶段 2:Operator 实现 Wallet
Operator 实现:
POST /balance
POST /bet
POST /win
POST /refund阶段 3:Provider 验证 Wallet
测试:
余额
正常下注
余额不足
普通中奖
0 中奖
重复 Bet
重复 Win
Refund
超时
错误签名
Session 过期后的 Win阶段 4:启动游戏
Operator 实现:
GET /games
POST /game/launch拿到:
game_urliframe / redirect 打开游戏。
阶段 5:财务对账
双方比较:
Round
Bet
Win
Refund
GGR公式:
GGR = Total Bet - Total Win退款 / 回滚需要按实际财务口径计算。
阶段 6:正式上线
通过 Checklist 后:
Sandbox
↓
Production Credential
↓
小流量
↓
全量23. 完整单局调用示例
玩家:
player_id = 100086
balance = 1000 USD进入游戏:
POST /v1/game/launchProvider 返回:
{
"session_id": "ses_001",
"game_url": "https://game.provider.example/play?t=..."
}游戏读取余额:
Provider
↓
POST Operator /balance返回:
{
"balance": "1000.00",
"currency": "USD"
}玩家选择:
Bet = 10 USDProvider 创建:
round_id = rnd_001
transaction_id = txn_bet_001调用:
POST /betOperator:
1000 - 10 = 990返回:
{
"code": "OK",
"balance": "990.00"
}Bet 成功后 Provider Game Server 计算结果:
Win = 25 USD创建:
transaction_id = txn_win_001调用:
POST /winOperator:
990 + 25 = 1015返回:
{
"code": "OK",
"balance": "1015.00"
}Round:
total_bet = 10
total_win = 25
status = FINISHED玩家界面显示:
BALANCE 1015.00
WIN 25.0024. 异常场景处理
24.1 Bet 成功,但 Provider 没收到响应
实际 Operator:
100 → 90Provider:
HTTP timeoutProvider 必须使用相同:
transaction_id重试。
Operator 发现已处理,返回原结果:
{
"code": "OK",
"balance": "90.00"
}24.2 Win 成功,但响应丢失
相同原则。
禁止创建新的 Win transaction_id 来“再试一次”。
否则会重复派奖。
24.3 Bet 被拒绝
如果:
INSUFFICIENT_FUNDSProvider:
- 不创建有效 Round 结果。
- 不调用 Win。
- Game Client 显示余额不足。
- 可刷新 Balance。
24.4 Bet 成功后游戏服务器崩溃
Provider 必须能够通过数据库任务恢复:
找到已成功 BET
但是 ROUND 未 FINISHED根据保存的 Round/RNG 状态:
- 恢复游戏结算;
- 或安全 Refund。
绝不能留下永久扣款未结算。
24.5 Win 在 Session 过期后到达
只要对应 Bet 已成功:
WIN 必须继续处理不要返回:
SESSION_EXPIRED24.6 同一 transaction_id 不同金额
拒绝:
409 IDEMPOTENCY_CONFLICT并报警。
24.7 Wallet 长时间不可用
Game 应进入:
TEMPORARY_UNAVAILABLE建议停止接受新的真钱 Spin。
已有资金交易放入可靠重试队列。
25. 联调测试用例
第三方上线前必须至少通过以下测试。
| ID | Case | Expected |
|---|---|---|
| T001 | 获取游戏列表 | 200 |
| T002 | 正常启动游戏 | 返回 game_url |
| T003 | 无效 game_id | GAME_NOT_FOUND |
| T004 | 无效签名 | 401 |
| T005 | 过期 Timestamp | 401 |
| T006 | Balance | 返回正确余额 |
| T007 | 正常 Bet | 扣款一次 |
| T008 | 余额不足 | INSUFFICIENT_FUNDS |
| T009 | 重复 Bet | 不重复扣款 |
| T010 | 相同 TX 不同金额 | 409 |
| T011 | 正常 Win | 加款一次 |
| T012 | 重复 Win | 不重复派奖 |
| T013 | 0 Win | Round 正常结束 |
| T014 | Refund | 恢复余额 |
| T015 | 重复 Refund | 不重复退款 |
| T016 | Session 过期后 Bet | 拒绝 |
| T017 | Session 过期后已有 Round Win | 必须结算 |
| T018 | Wallet Timeout | Provider 安全重试 |
| T019 | Free Spins 创建 | 成功 |
| T020 | Free Spins 取消 | 成功 |
| T021 | Round 查询 | 数据一致 |
| T022 | Transaction 查询 | 数据一致 |
| T023 | Replay | 正确展示 |
| T024 | 并发 Bet | 无超扣 |
| T025 | Currency mismatch | 拒绝 |
| T026 | IP 非白名单 | 403 |
26. 上线检查清单
Provider
Operator
财务
27. 版本兼容策略
v1 内新增字段:
接收方必须忽略自己不认识的可选字段。
例如未来增加:
{
"new_feature": {}
}旧版本不应因为未知字段直接失败。
以下变化属于 Breaking Change:
- 删除字段
- 修改字段语义
- 修改金额单位
- 修改签名算法
- 修改必填字段
- 修改 HTTP Method
- 修改 endpoint
这些变化必须:
/v228. 合规与责任边界
真钱游戏属于高度监管业务。
正式上线前,应根据目标司法辖区确认:
- 游戏供应商许可要求
- Operator 许可要求
- RNG / Game Certification
- RTP Certification
- 游戏规则披露
- 年龄限制
- Responsible Gaming
- AML / KYC
- 制裁与地区限制
- 数据保护
- 财务审计与记录保留
Provider API 应支持按 Operator / Country 禁用:
Game
Bonus Buy
Jackpot
Currency
Promotion本技术规范本身不替代任何司法辖区的牌照、认证或法律意见。
29. 参考资料
本规范的整体结构参考了公开的现代游戏供应商、Seamless Wallet 和 Aggregator 接入设计思想,并重新整理为适合自建 Slot Provider 的独立协议。
公开参考:
7SoftTech Seamless API
https://documentation.7softtech.net/VeliGames Integration / Seamless Wallet API
https://doc.velitech.games/
https://doc.velitech.games/wallet-apiThe Aggregator API
https://docs.aggregator.gg/The Aggregator - Wallet Callback Integration Guide
https://docs.aggregator.gg/guides/wallet-callbacks/
这些资料常见且值得借鉴的设计包括:
- Provider API 与 Wallet Callback 分离
- Server-to-Server
- HMAC-SHA256
- Raw Body 签名
- Timestamp / Nonce / IP Allowlist
- transaction_id 幂等
- Bet / Win / Refund 生命周期
- Session → Round → Transaction
- Replay / Reporting
- OpenAPI 作为机器可读接口契约
附录 A:推荐端点总表
Operator → Provider
GET /v1/games
GET /v1/games/{game_id}
POST /v1/game/launch
POST /v1/game/demo
GET /v1/sessions/{session_id}
POST /v1/sessions/{session_id}/close
POST /v1/free-spins
GET /v1/free-spins/{free_spin_id}
POST /v1/free-spins/{free_spin_id}/cancel
GET /v1/rounds/{round_id}
GET /v1/rounds/{round_id}/transactions
GET /v1/transactions/{transaction_id}
GET /v1/reports/gaming-activityProvider → Operator
POST {WALLET_URL}/balance
POST {WALLET_URL}/bet
POST {WALLET_URL}/win
POST {WALLET_URL}/refund
POST {WALLET_URL}/rollback # 可选
POST {WALLET_URL}/cancel # 可选附录 B:推荐对象关系
Operator
│
├── Player
│
└── Session
│
└── Game
│
└── Round
│
├── BET Transaction
├── WIN Transaction
├── WIN Transaction
└── REFUND / ROLLBACK附录 C:建议后续配套文件
正式对外提供 SDK 时,建议本 Markdown 文档之外同时维护:
slot-provider-api-v1.md
openapi.yaml
postman_collection.json
sandbox-guide.md
error-codes.md
changelog.md
examples/
php/
nodejs/
python/
java/最重要的是维护:
openapi.yaml将其作为接口 Schema 的唯一权威来源,Markdown 则用于人工阅读。
文档结束