跳转到正文

Slot Provider API v1 接入文档

文档类型:B2B Slot 游戏供应商 / 单钱包接入
API 版本:v1
文档版本:1.0.0
状态:生产环境设计基线
最后更新:2026-08-30


目录

  1. 文档说明
  2. 系统角色与整体架构
  3. 核心设计原则
  4. 环境与基础地址
  5. 接入前需要交换的资料
  6. 通用请求规范
  7. 金额、币种与精度
  8. 身份认证与 HMAC 签名
  9. 幂等、重试与并发控制
  10. 游戏 Session 生命周期
  11. Operator → Provider API
  12. Provider → Operator Wallet API
  13. Round 与 Transaction 生命周期
  14. Free Spins API
  15. Bonus Buy
  16. Jackpot 扩展
  17. 游戏历史、Replay 与对账
  18. 错误码规范
  19. 超时、重试与故障恢复
  20. 安全要求
  21. 数据库与账本建议
  22. 第三方标准接入流程
  23. 完整单局调用示例
  24. 异常场景处理
  25. 联调测试用例
  26. 上线检查清单
  27. 版本兼容策略
  28. 合规与责任边界
  29. 参考资料

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本老虎机游戏供应商
PlayerOperator 的最终玩家
Game ClientProvider 提供的 H5 / Web 游戏客户端
Game ServerProvider 的游戏逻辑、RNG、Round、派奖服务器
Operator WalletOperator 提供的钱包接口
BackofficeProvider / Operator 的后台管理系统

2.2 标准架构

text
┌─────────────────────┐
│      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、运营配置的接口必须由服务器调用服务器。

禁止:

text
浏览器 → Provider Management API
浏览器 → Operator Wallet API
Game Client → Operator Wallet API

必须:

text
Operator Backend → Provider API
Provider Game Server → Operator Wallet API

3.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 所有资金操作必须可重放

网络超时不代表交易失败。

任何 betwinrefundrollback 请求都可能重复到达。

因此:

相同 transaction_id 的重复请求必须返回第一次成功处理后的结果,绝不能再次扣款或加款。


4. 环境与基础地址

建议提供至少两个完全隔离的环境。

4.1 沙箱环境(Sandbox)

text
Provider API:
https://sandbox-api.provider.example

Game:
https://sandbox-game.provider.example

Backoffice:
https://sandbox-bo.provider.example

4.2 生产环境(Production)

text
Provider API:
https://api.provider.example

Game:
https://game.provider.example

Backoffice:
https://bo.provider.example

4.3 API 版本

所有 Provider API 路径必须带版本:

text
/v1/...

例如:

http
POST /v1/game/launch
GET  /v1/games
GET  /v1/rounds/{round_id}

重大不兼容升级使用:

text
/v2/

5. 接入前需要交换的资料

5.1 Provider 提供给 Operator

text
operator_id
api_key
api_secret
provider_api_url
game_domain
provider_callback_ips
supported_currencies
supported_languages
API documentation
sandbox credentials

5.2 Operator 提供给 Provider

text
operator_id
wallet_url
wallet_callback_secret
allowed_currencies
allowed_countries
operator_callback_ips
return_url
brand_id(可选)

示例:

text
operator_id: casino_001
wallet_url: https://api.operator.com/provider-wallet/v1
currency: USD, EUR, USDT

6. 通用请求规范

6.1 Content-Type

http
Content-Type: application/json
Accept: application/json

统一使用 UTF-8。

6.2 时间格式

业务时间字段使用 ISO 8601 UTC:

text
2026-08-30T02:30:15.123Z

HMAC 请求头中的时间使用 Unix Timestamp 秒:

text
1788057015

6.3 ID 格式

建议所有 ID 为 String。

示例:

text
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 禁止使用浮点数计算真钱

禁止:

javascript
const balance = 0.1 + 0.2;

资金必须使用:

  • Decimal
  • BigDecimal
  • BCMath
  • Decimal.js
  • 数据库 DECIMAL
  • 或整数最小单位

7.2 本协议金额格式

为了兼容 Fiat 与 Crypto,本规范使用 十进制字符串

json
{
  "amount": "10.00",
  "currency": "USD"
}

USDT:

json
{
  "amount": "10.123456",
  "currency": "USDT"
}

禁止:

json
{
  "amount": 10.123456
}

7.3 币种代码

优先使用 ISO 4217:

text
USD
EUR
GBP
SGD
JPY

Crypto 可配置:

text
USDT
USDC
BTC
ETH

Operator 与 Provider 必须提前配置每种币种最大精度。

例如:

CurrencyDecimals
USD2
EUR2
JPY0
USDT6
BTC8

8. 身份认证与 HMAC 签名

建议两个方向使用不同密钥。

8.1 Operator → Provider

请求头:

http
X-Operator-Id: casino_001
X-API-Key: pk_live_xxxxxxxxx
X-Timestamp: 1788057015
X-Nonce: 7f0a39c80d72406d98a95ec10630aebb
X-Signature: v1=54c9...

签名字符串:

text
{timestamp}.{nonce}.{raw_request_body}

算法:

text
HMAC-SHA256(signing_string, api_secret)

最后:

text
X-Signature = "v1=" + lowercase_hex_digest

8.2 Provider → Operator Wallet

请求头:

http
X-Provider-Id: provider_001
X-Operator-Id: casino_001
X-Timestamp: 1788057015
X-Nonce: a83f7e2bd9d64d9386f36cc4b48382ba
X-Signature: v1=12df...

使用 Operator 为当前接入分配的:

text
wallet_callback_secret

签名方式相同:

text
timestamp + "." + nonce + "." + raw_body

8.3 验签要求

接收方必须:

  1. 读取原始 HTTP Body。
  2. 检查 X-Timestamp
  3. 检查 X-Nonce
  4. 根据 Secret 重新计算 HMAC-SHA256。
  5. 使用 constant-time comparison。
  6. 验签成功后才能 JSON decode。
  7. Nonce 在有效时间窗口内不得重复。

不要:

text
JSON decode
→ 重新 JSON encode
→ 再计算签名

因为字段顺序和空格变化可能导致签名不同。

8.4 防重放时间窗口(Replay Window)

建议:

text
±300 秒

超过范围:

http
401 Unauthorized

错误:

json
{
  "code": "INVALID_TIMESTAMP",
  "message": "Request timestamp is outside the allowed window."
}

9. 幂等、重试与并发控制

9.1 transaction_id

所有资金交易必须有全局唯一:

text
transaction_id

例如:

text
txn_bet_01K...
txn_win_01K...
txn_refund_01K...

9.2 重复请求

第一次:

text
Balance = 100
BET = 10

处理后:

text
Balance = 90

Provider 没收到响应,5 秒后重试相同:

text
transaction_id = txn_bet_001

Operator 必须返回:

json
{
  "code": "OK",
  "transaction_id": "txn_bet_001",
  "balance": "90.00",
  "currency": "USD"
}

不能再次扣款。

9.3 请求内容(Payload)不一致

如果相同 transaction_id 第二次请求:

第一次:

json
{
  "transaction_id": "txn_bet_001",
  "amount": "10.00"
}

第二次:

json
{
  "transaction_id": "txn_bet_001",
  "amount": "20.00"
}

必须拒绝:

http
409 Conflict
json
{
  "code": "IDEMPOTENCY_CONFLICT",
  "message": "Transaction already exists with different payload."
}

9.4 数据库事务

Wallet 侧建议:

text
BEGIN

SELECT player balance FOR UPDATE

检查 transaction_id

INSERT wallet_transaction

UPDATE player balance

COMMIT

必须避免:

text
先查余额
→ 不加锁
→ 两个请求同时扣款

10. 游戏 Session 生命周期

标准流程:

text
CREATED

ACTIVE

EXPIRED / CLOSED

建议 Session:

text
单次启动 URL 有效时间:30~120 秒
游戏 Session TTL:30~120 分钟

具体值可按 Operator 配置。

Session 至少保存:

text
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 获取游戏列表

http
GET /v1/games

Query:

text
type=slot
status=active
page=1
page_size=100

Response:

json
{
  "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 获取单个游戏

http
GET /v1/games/{game_id}

Response:

json
{
  "code": "OK",
  "data": {
    "game_id": "slot_super_ace",
    "name": "Super Ace",
    "type": "slot",
    "rtp": "96.50",
    "volatility": "high",
    "status": "active"
  }
}

11.3 启动真钱游戏

http
POST /v1/game/launch

Request:

json
{
  "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"
  }
}

字段:

FieldRequiredDescription
player_idYesOperator 玩家唯一 ID
game_idYesProvider 游戏 ID
currencyYes当前 Session 币种
languageYesUI 语言
countryRecommendedISO 3166-1 alpha-2
return_urlNo离开游戏返回地址
deviceNomobile / desktop / tablet
platformNoweb / app
metadataNo第三方扩展参数

Response:

json
{
  "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 游戏

http
POST /v1/game/demo

Request:

json
{
  "game_id": "slot_super_ace",
  "language": "en",
  "country": "SG",
  "device": "mobile"
}

Response:

json
{
  "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

http
GET /v1/sessions/{session_id}

Response:

json
{
  "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

http
POST /v1/sessions/{session_id}/close

Request:

json
{
  "reason": "operator_logout"
}

关闭后:

  • 禁止创建新 Bet。
  • 已存在未完成 Round 仍允许结算 Win / Refund。

12. Provider → Operator Wallet API

Operator 必须实现以下接口。

假设:

text
WALLET_URL=https://api.operator.example/provider-wallet/v1

12.1 查询余额

http
POST {WALLET_URL}/balance

Request:

json
{
  "operator_id": "casino_001",
  "player_id": "100086",
  "session_id": "ses_001",
  "game_id": "slot_super_ace",
  "currency": "USD"
}

Response:

json
{
  "code": "OK",
  "player_id": "100086",
  "balance": "1000.00",
  "currency": "USD"
}

规则

  • 只能返回 Session 币种的余额。
  • Currency 不匹配必须报错。
  • 不要自动进行货币转换。
  • balance 必须为字符串。

12.2 Bet 扣款

http
POST {WALLET_URL}/bet

Request:

json
{
  "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:

json
{
  "code": "OK",
  "transaction_id": "txn_bet_001",
  "balance": "990.00",
  "currency": "USD"
}

余额不足:

http
422 Unprocessable Entity
json
{
  "code": "INSUFFICIENT_FUNDS",
  "message": "Insufficient player balance.",
  "balance": "5.00",
  "currency": "USD"
}

Provider 规则

如果 Bet 未获得明确成功响应:

不得认为下注成功,不得生成不可恢复的最终派奖状态。

Provider 应进行安全重试或交易状态查询。


12.3 Win 派奖

http
POST {WALLET_URL}/win

Request:

json
{
  "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:

json
{
  "code": "OK",
  "transaction_id": "txn_win_001",
  "balance": "1015.00",
  "currency": "USD"
}

0 Win

建议允许:

json
{
  "amount": "0.00",
  "round_finished": true
}

也可由双方约定 0 Win 不调用钱包,但 Provider 自己必须正确关闭 Round。

Session 已过期

如果 Bet 曾成功:

Operator 不得因为 Session 已过期而拒绝对应 Win。


12.4 Refund

用于返还一个已经成功的 Bet。

http
POST {WALLET_URL}/refund

Request:

json
{
  "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:

json
{
  "code": "OK",
  "transaction_id": "txn_refund_001",
  "balance": "1000.00",
  "currency": "USD"
}

12.5 Rollback

Rollback 用于撤销一个已处理资金交易。

http
POST {WALLET_URL}/rollback

Request:

json
{
  "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:

json
{
  "code": "OK",
  "transaction_id": "txn_rollback_001",
  "balance": "990.00",
  "currency": "USD"
}

Refund 与 Rollback 区别

推荐语义:

API用途
refund返还一个 Bet 的全部或部分金额
rollback反向撤销指定原交易
cancel可选高级接口,用于 Round / Transaction 级取消

如果希望协议更简单,v1 可以只保留:

text
/bet
/win
/refund

将 Rollback 作为 v1.1 扩展。


12.6 可选 Cancel API

http
POST {WALLET_URL}/cancel

Request:

json
{
  "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

text
TRANSACTION
BET
ROUND

13. Round 与 Transaction 生命周期

13.1 普通 Spin

text
ROUND CREATED


BET

     ├── Lose ──► WIN amount=0 / close round

     └── Win


          WIN


     ROUND FINISHED

13.2 Free Spins

一个付费 Spin 可能触发多个后续 Game Action:

text
Round

 ├─ BET

 ├─ Base Win

 ├─ Free Spin #1 Win

 ├─ Free Spin #2 Win

 ├─ ...

 └─ Final Win / round_finished=true

你可以采用:

模式 A:一个 Round 包含整个 Free Spins Feature

适合:

text
触发 Free Spins
→ 10 次免费旋转
→ 最终整体结算

模式 B:每次 Free Spin 一个 Sub Round

字段增加:

json
{
  "parent_round_id": "rnd_001"
}

无论采用哪一种:

文档和报表必须能够把所有子交易关联回原始付费 Round。


13.3 交易类型(Transaction Type)

推荐:

text
BET
WIN
REFUND
ROLLBACK
JACKPOT_WIN
JACKPOT_CONTRIBUTION
BONUS_BUY

14. Free Spins API

Free Spins 是 Operator 给玩家发放的促销权益,不等同于老虎机内部自然触发的 Free Spin Feature。


14.1 创建 Free Spins

http
POST /v1/free-spins

Request:

json
{
  "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:

json
{
  "code": "OK",
  "data": {
    "free_spin_id": "fsp_01K...",
    "status": "active",
    "remaining_spins": 20
  }
}

14.2 查询 Free Spins

http
GET /v1/free-spins/{free_spin_id}

Response:

json
{
  "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

http
POST /v1/free-spins/{free_spin_id}/cancel

Request:

json
{
  "reason": "campaign_cancelled"
}

已消费的 Spin 不回滚,除非双方另有约定。


15. Bonus Buy

如果游戏支持 Bonus Buy:

游戏信息返回:

json
{
  "bonus_buy_supported": true
}

Bet Callback:

json
{
  "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 级配置:

text
bonus_buy_enabled = false

禁用时 Game Client 不显示 Bonus Buy UI。


16. Jackpot 扩展

如未来支持 Progressive Jackpot,建议不要破坏基础 Bet/Win 结构。

Bet:

json
{
  "transaction_id": "txn_bet_001",
  "amount": "10.00",
  "jackpot": {
    "jackpot_id": "jp_mega",
    "contribution": "0.10"
  }
}

Jackpot Win:

json
{
  "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

http
GET /v1/rounds/{round_id}

Response:

json
{
  "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

http
GET /v1/rounds/{round_id}/transactions

Response:

json
{
  "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

http
GET /v1/transactions/{transaction_id}

Response:

json
{
  "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)

推荐:

http
GET /v1/reports/gaming-activity

Query:

text
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

每行必须至少包含:

text
transaction_id
round_id
player_id
game_id
type
amount
currency
status
created_at
ref_transaction_id

17.5 Replay

Provider 建议提供 Round Replay。

Replay 应可以展示:

text
游戏名称
Round ID
Bet
Win
时间
Reel / Symbol 结果
Multiplier
Free Spins
Bonus
最终 payout

Replay URL 必须:

  • 签名。
  • 有过期时间。
  • 只读。
  • 不允许产生任何资金交易。

18. 错误码规范

18.1 HTTP 状态码

StatusMeaning
200成功
400参数错误
401鉴权或签名失败
403无权限 / IP 不允许
404资源不存在
409幂等冲突 / 状态冲突
422业务拒绝,例如余额不足
429Rate Limit
500服务内部错误
502上游服务异常
503临时不可用

18.2 标准业务错误码

text
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

错误格式:

json
{
  "code": "INSUFFICIENT_FUNDS",
  "message": "Insufficient player balance.",
  "request_id": "req_01K..."
}

Production 环境不要返回:

text
SQL
数据库密码
Stack Trace
Secret
内部服务器路径

19. 超时、重试与故障恢复

真钱系统必须假设任何网络请求都有以下可能:

text
请求根本没到
请求到了但响应丢了
对方已经成功处理但你认为失败
响应到了但你的服务宕机
重复发送
乱序到达

19.1 钱包超时

推荐:

text
connect timeout: 2 秒
request timeout: 5 秒

最终值双方联调确认。

19.2 重试策略

资金请求推荐:

text
0s
1s
3s
10s
30s
1m
5m

不要无限高速重试。

必须保持:

text
同一个 transaction_id
同一个 payload

19.3 待处理状态(Pending)

Provider 内部 Transaction 状态:

text
CREATED
PENDING
SUCCESS
FAILED
REVERSED

超时不能直接标记为:

text
FAILED

更安全:

text
PENDING

然后重试 / 查询确认。


20. 安全要求

Production 最低要求:

20.1 传输安全

text
HTTPS TLS 1.2+

禁止 HTTP。

20.2 API 密钥

Secret:

  • 只能保存于服务端。
  • 禁止放 Game Client。
  • 禁止放前端 JS。
  • 禁止写入 Git。
  • 禁止出现在日志。
  • 必须支持轮换。

20.3 IP 白名单

双方建议提供固定出口 IP。

Provider → Operator Wallet:

text
Operator allowlist Provider IP

Operator → Provider:

text
Provider allowlist Operator IP

IP Allowlist 只能作为第二层安全,不应替代 HMAC。

20.4 请求限流

示例:

text
Management API: 100 req/s / Operator
Launch API: 300 req/s / Operator
Wallet: 按容量规划,不应使用过低限制影响 Spin

返回:

http
429 Too Many Requests
Retry-After: 1

20.5 日志

每个请求至少记录:

text
request_id
operator_id
endpoint
transaction_id
round_id
player_id
status
latency
timestamp

必须脱敏:

text
api_secret
callback_secret
Authorization
完整 Token

21. 数据库与账本建议

21.1 operators

text
id
operator_id
name
api_key_hash
api_secret_encrypted
wallet_url
wallet_callback_secret_encrypted
status
allowed_ips
created_at
updated_at

21.2 games

text
id
game_id
name
type
rtp
volatility
status
free_spins_supported
bonus_buy_supported
jackpot_supported
created_at
updated_at

21.3 game_sessions

text
id
session_id
operator_id
player_id
game_id
currency
language
status
ip
created_at
expires_at
closed_at

21.4 game_rounds

text
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_at

21.5 game_transactions

text
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

关键索引:

sql
UNIQUE(transaction_id)
INDEX(round_id)
INDEX(operator_id, player_id)
INDEX(created_at)

21.6 不可变账本

推荐额外维护不可变交易流水:

text
ledger_entries

一旦记账:

不 UPDATE 原资金含义,而是通过新的反向 Transaction 修正。

例如:

text
BET      -10
ROLLBACK +10

而不是删除 BET。

这样方便:

  • 财务审计
  • Operator 对账
  • 争议处理
  • 游戏监管审计

22. 第三方标准接入流程

阶段 1:商务 / 技术资料

Operator 提供:

text
Company / Project
Technical contact
wallet_url
callback IP
supported currencies

Provider 提供 Sandbox Credential。

阶段 2:Operator 实现 Wallet

Operator 实现:

text
POST /balance
POST /bet
POST /win
POST /refund

阶段 3:Provider 验证 Wallet

测试:

text
余额
正常下注
余额不足
普通中奖
0 中奖
重复 Bet
重复 Win
Refund
超时
错误签名
Session 过期后的 Win

阶段 4:启动游戏

Operator 实现:

text
GET /games
POST /game/launch

拿到:

text
game_url

iframe / redirect 打开游戏。

阶段 5:财务对账

双方比较:

text
Round
Bet
Win
Refund
GGR

公式:

text
GGR = Total Bet - Total Win

退款 / 回滚需要按实际财务口径计算。

阶段 6:正式上线

通过 Checklist 后:

text
Sandbox

Production Credential

小流量

全量

23. 完整单局调用示例

玩家:

text
player_id = 100086
balance = 1000 USD

进入游戏:

http
POST /v1/game/launch

Provider 返回:

json
{
  "session_id": "ses_001",
  "game_url": "https://game.provider.example/play?t=..."
}

游戏读取余额:

text
Provider

POST Operator /balance

返回:

json
{
  "balance": "1000.00",
  "currency": "USD"
}

玩家选择:

text
Bet = 10 USD

Provider 创建:

text
round_id = rnd_001
transaction_id = txn_bet_001

调用:

http
POST /bet

Operator:

text
1000 - 10 = 990

返回:

json
{
  "code": "OK",
  "balance": "990.00"
}

Bet 成功后 Provider Game Server 计算结果:

text
Win = 25 USD

创建:

text
transaction_id = txn_win_001

调用:

http
POST /win

Operator:

text
990 + 25 = 1015

返回:

json
{
  "code": "OK",
  "balance": "1015.00"
}

Round:

text
total_bet = 10
total_win = 25
status = FINISHED

玩家界面显示:

text
BALANCE 1015.00
WIN 25.00

24. 异常场景处理

24.1 Bet 成功,但 Provider 没收到响应

实际 Operator:

text
100 → 90

Provider:

text
HTTP timeout

Provider 必须使用相同:

text
transaction_id

重试。

Operator 发现已处理,返回原结果:

json
{
  "code": "OK",
  "balance": "90.00"
}

24.2 Win 成功,但响应丢失

相同原则。

禁止创建新的 Win transaction_id 来“再试一次”。

否则会重复派奖。


24.3 Bet 被拒绝

如果:

text
INSUFFICIENT_FUNDS

Provider:

  • 不创建有效 Round 结果。
  • 不调用 Win。
  • Game Client 显示余额不足。
  • 可刷新 Balance。

24.4 Bet 成功后游戏服务器崩溃

Provider 必须能够通过数据库任务恢复:

text
找到已成功 BET
但是 ROUND 未 FINISHED

根据保存的 Round/RNG 状态:

  • 恢复游戏结算;
  • 或安全 Refund。

绝不能留下永久扣款未结算。


24.5 Win 在 Session 过期后到达

只要对应 Bet 已成功:

text
WIN 必须继续处理

不要返回:

text
SESSION_EXPIRED

24.6 同一 transaction_id 不同金额

拒绝:

text
409 IDEMPOTENCY_CONFLICT

并报警。


24.7 Wallet 长时间不可用

Game 应进入:

text
TEMPORARY_UNAVAILABLE

建议停止接受新的真钱 Spin。

已有资金交易放入可靠重试队列。


25. 联调测试用例

第三方上线前必须至少通过以下测试。

IDCaseExpected
T001获取游戏列表200
T002正常启动游戏返回 game_url
T003无效 game_idGAME_NOT_FOUND
T004无效签名401
T005过期 Timestamp401
T006Balance返回正确余额
T007正常 Bet扣款一次
T008余额不足INSUFFICIENT_FUNDS
T009重复 Bet不重复扣款
T010相同 TX 不同金额409
T011正常 Win加款一次
T012重复 Win不重复派奖
T0130 WinRound 正常结束
T014Refund恢复余额
T015重复 Refund不重复退款
T016Session 过期后 Bet拒绝
T017Session 过期后已有 Round Win必须结算
T018Wallet TimeoutProvider 安全重试
T019Free Spins 创建成功
T020Free Spins 取消成功
T021Round 查询数据一致
T022Transaction 查询数据一致
T023Replay正确展示
T024并发 Bet无超扣
T025Currency mismatch拒绝
T026IP 非白名单403

26. 上线检查清单

Provider

Operator

财务


27. 版本兼容策略

v1 内新增字段:

接收方必须忽略自己不认识的可选字段。

例如未来增加:

json
{
  "new_feature": {}
}

旧版本不应因为未知字段直接失败。

以下变化属于 Breaking Change:

  • 删除字段
  • 修改字段语义
  • 修改金额单位
  • 修改签名算法
  • 修改必填字段
  • 修改 HTTP Method
  • 修改 endpoint

这些变化必须:

text
/v2

28. 合规与责任边界

真钱游戏属于高度监管业务。

正式上线前,应根据目标司法辖区确认:

  • 游戏供应商许可要求
  • Operator 许可要求
  • RNG / Game Certification
  • RTP Certification
  • 游戏规则披露
  • 年龄限制
  • Responsible Gaming
  • AML / KYC
  • 制裁与地区限制
  • 数据保护
  • 财务审计与记录保留

Provider API 应支持按 Operator / Country 禁用:

text
Game
Bonus Buy
Jackpot
Currency
Promotion

本技术规范本身不替代任何司法辖区的牌照、认证或法律意见。


29. 参考资料

本规范的整体结构参考了公开的现代游戏供应商、Seamless Wallet 和 Aggregator 接入设计思想,并重新整理为适合自建 Slot Provider 的独立协议。

公开参考:

  1. 7SoftTech Seamless API
    https://documentation.7softtech.net/

  2. VeliGames Integration / Seamless Wallet API
    https://doc.velitech.games/
    https://doc.velitech.games/wallet-api

  3. The Aggregator API
    https://docs.aggregator.gg/

  4. 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

text
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-activity

Provider → Operator

text
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:推荐对象关系

text
Operator

  ├── Player

  └── Session

       └── Game

            └── Round

                 ├── BET Transaction
                 ├── WIN Transaction
                 ├── WIN Transaction
                 └── REFUND / ROLLBACK

附录 C:建议后续配套文件

正式对外提供 SDK 时,建议本 Markdown 文档之外同时维护:

text
slot-provider-api-v1.md
openapi.yaml
postman_collection.json
sandbox-guide.md
error-codes.md
changelog.md

examples/
  php/
  nodejs/
  python/
  java/

最重要的是维护:

text
openapi.yaml

将其作为接口 Schema 的唯一权威来源,Markdown 则用于人工阅读。


文档结束