XAgent 单一钱包 API 文档 V3.0
前言
对接流程
- 提供相应信息,联系我方在UAT环境给您开户
- 提供您的服务器 IP 用以添加服务器 IP 白名单。
- 若您的接口也设置有白名单, 我方会提供服务器 IP 用以添加访问您的接口的白名单。
- 开户完成,我方提供publicKey、businessAccount、site等其他参数,和游戏后台地址
- 根据您的游戏需求,我方提供相对应的游戏编码表,对接用
- 根据文档,您需要将我方需要的接口开发完毕,提供出来
- 根据游戏编码表,将游戏相关数据(名称、编码、封面素材等)在您的平台创建出来
- 通过接口文档开始对接接口
- 接口对接完毕,联调测试无误
- 正式环境准备接入,我方商务介入,与您洽谈商务事项
- 正式环境开户完毕,切换接口地址和参数
- 您提供IP白名单,游戏后台配置白名单
- 正式环境预运营与验收
- 接入完毕,正式上线
对接说明
我方所有接口参数入参 , 大小写敏感 (不会忽略大小写) , 请注意传值
对于您提供的所有接口的参数入参 , 也需要大小写敏感 (不忽略大小写)
在您的WEB / H5 / APP 平台,配置好游戏入口后,用户点击游戏入口,调用我方提供的用户注册/登录接口, 传入account、游戏编码、gameType等参数
成功后,取到接口返回值,其中url字段,就是携带了该用户登录态token的form表单 或 url 链接
通过访问、内嵌url字段,即可跳转进入游戏本体内部
您需要取用户的唯一ID作为account,按照一定的规则,拼接好,传入接口
我方会在游戏内不同的场景,调用您提供的接口进行 下单、结算、更新结算等操作
您可在我方提供的游戏控制台(后台),创建不同的代理线路,每条线路可配置独立的RTP配置,每条线路的用户也是分割独立的。
我方在给您开户时,会帮您创建好一条默认的代理线路供您使用,后续若需要更多,可自行去后台添加
您还可以在后台创建您的子代理,将不同的代理线路分配给您的子代理管理,并附带 子代理后台,可查看分配给该子代理的相关游戏数据、用户订单记录、报表、调整RTP参数等。
白名单限制
我方的接口域名 , 以及给您开设的游戏后台 , 均有设置IP白名单限制 , 若未进行配置 , 则无法调用接口 / 访问后台 , 所以在对接开始之前 , 需要您提供如下IP信息给我方进行预配置:
您各环境的服务器的IP地址
您需要访问游戏后台的设备IP地址
同时若您的接口也设置有白名单限制, 在调用您提供的接口之前 , 我方也会提供各环境服务器IP给您预配置 , 确保对接流程顺畅
我方提供的接口
域名
UAT环境:https://xagent-open-api-uat-hh.ncfc.cc
正式环境:联系商务人员获取
调用前准备
Headers:
| 参数名称 | 参数值 | 是否必须 | 示例 | 备注 |
|---|---|---|---|---|
| Content-Type | application/json | 是 | application/json | |
| businessAccount | 我方提供的总代唯一标识 | 是 | ballGame | |
| site | XAgent商户后台中的代理线路标识 | 是 | default | 若无另行设定,带入default即可 |
参数加解密示例:
// 加密示例
/**
* @param jsonString json字串,格式示例:{"field_1":"value_1","field_2":"value_2"}
* @param publicKey 公钥,格式示例:MIGfMA0GCSqGSIb3DQEBAQUAA4GNADC....
* @return 加密后的请求参数,包含加密后的数据字段
* @throws Exception 加密过程中可能抛出的异常
*/
public static Map<String, String> encryptRequestBody(String jsonString, String publicKey) throws Exception {
// 将json字符串转换为字节数组
byte[] data = jsonString.getBytes(StandardCharsets.UTF_8);
// 通过Base64解码获取公钥字节数组
byte[] keyBytes = Base64.getDecoder().decode(publicKey);
// 使用公钥字节数组创建X509EncodedKeySpec对象
X509EncodedKeySpec x509KeySpec = new X509EncodedKeySpec(keyBytes);
// 使用KeyFactory生成公钥对象
KeyFactory keyFactory = KeyFactory.getInstance("RSA"); // 加密算法
Key publicK = keyFactory.generatePublic(x509KeySpec);
// 初始化Cipher对象,用于RSA加密
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.ENCRYPT_MODE, publicK);
int inputLen = data.length;
ByteArrayOutputStream out = new ByteArrayOutputStream();
int offSet = 0;
byte[] cache;
// 对数据进行分段加密,每次加密块的大小不超过MAX_ENCRYPT_BLOCK
int MAX_ENCRYPT_BLOCK = 117; // RSA加密的最大块大小,PKCS1填充方式下为117字节
while (inputLen - offSet > 0) {
int len = Math.min(MAX_ENCRYPT_BLOCK, inputLen - offSet);
cache = cipher.doFinal(data, offSet, len);
out.write(cache);
offSet += len;
}
// 获取加密后的字节数组
byte[] encryptedData = out.toByteArray();
out.close();
// 将加密后的字节数组进行Base64编码,转换为字符串
String base64String = Base64.getEncoder().encodeToString(encryptedData);
// 创建一个Map,将Base64编码后的加密数据作为参数放入Map中
Map<String, String> encryptParam = new HashMap<>();
encryptParam.put("data", base64String);
// 返回包含加密数据的Map
return encryptParam;
}
public static void main(String[] args) throws Exception {
String account = "用户名";
String password = "password";
// 手動拼接 JSON
String jsonString = "{"
+ "\"account\":\"" + account + "\","
+ "\"password\":\"" + password + "\""
+ "}";
System.out.println(jsonString);
String base64PublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...'; // 替換為你的 base64 公鑰內容
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, encryptRequestBody( jsonString , base64PublicKey ));
Request request = new Request.Builder()
.url("your-api-endpoint")
.method("POST", body )
.addHeader("businessAccount", "我方提供的总代唯一标识")
.addHeader("site", "XAgent 商户后台中的代理线路标识")
.addHeader("Content-Type", "application/json")
.build();
Response response = client.newCall(request).execute();
}
// 解密示例
public class RSAPublicDecrypt {
public static void main(String[]args)throws Exception {
String pubKeyPem = "-----BEGIN PUBLIC KEY-----\n" +
"MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCioAIV3Npz1K8H4L+r4E2DCptp\n" +
"MJHeD09qzAyh244+dkWRqod7u0G+JMQp2EJ50MEf/zmNsprtRET5HAaM2zG6TAIL\n" +
"7hQLuUj/cDXLLWS+MvFIhjruR2xj//F7EQNJBPxE/CVcCzZQB7WDlH+aMYeCP+/y\n" +
"DNINBEMF9KTM+0b6qwIDAQAB\n" +
"-----END PUBLIC KEY-----";
String encryptedBase64 = "RKgVABPFCq5jaOaR/nWzSkB1CDjtPP7Cs7KKlIs/LYePsTQM12NpaR+ph3TlMkOphSxcO4pchvOI+gwF/XuaYs9LLW/r3ikmgoGF4AzZdKMYx50fAECMM1SZeVBu10KqZx7dF0hDdhBNr+2gLJwletW9bkcBCRRBJG1NrtZUXPGBBV/u+hL2uTSKrzUT46JZkLz2XllZMGtcwYn9ioBF0R1usob7mvVHU74Nktwh+6n2M+lUwJFXD0/GWrJy8stv/QZtUxjrmRkKHK9xGmtzx2oLi1Is/5bsPb5VJaTTfi9u2qWgvwndhDMe2OuGSliaileMW3xwXB3wFCtaC5UoYg==";
// 轉換公鑰 PEM -> byte[]
String cleanPem = pubKeyPem.replaceAll("-----\\w+ PUBLIC KEY-----", "").replaceAll("\\s", "");
byte[]keyBytes = Base64.getDecoder().decode(cleanPem);
// 建立公鑰物件
KeyFactory keyFactory = KeyFactory.getInstance("RSA");
PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(keyBytes));
// 設定 Cipher 模式為 RSA 公鑰解密,PKCS1 Padding
Cipher cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
cipher.init(Cipher.DECRYPT_MODE, publicKey);
// 解密分段處理
byte[]encryptedBytes = Base64.getDecoder().decode(encryptedBase64);
int chunkSize = 128; // 1024-bit RSA
StringBuilder decrypted = new StringBuilder();
for (int i = 0; i < encryptedBytes.length; i += chunkSize) {
byte[]chunk = new byte[chunkSize];
System.arraycopy(encryptedBytes, i, chunk, 0, chunkSize);
byte[]decryptedChunk = cipher.doFinal(chunk);
decrypted.append(new String(decryptedChunk, "UTF-8"));
}
System.out.println(decrypted.toString().trim());
}
}
// 加密示例:
<?php
// 假設 json 資料與 base64 公鑰字串
$jsonString = json_encode([
'account'=> '用户名',
'password'=> 'password'
]);
$base64PublicKey = 'MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A...'; // 替換為你的 base64 公鑰內容
// 1. 將 base64 公鑰解碼並封裝成 PEM 格式
$pubKeyFormatted = "-----BEGIN PUBLIC KEY-----\n" .
chunk_split($base64PublicKey, 64, "\n") .
"-----END PUBLIC KEY-----";
// 2. 載入公鑰
$publicKey = openssl_pkey_get_public($pubKeyFormatted);
if (!$publicKey) {
die("公鑰格式錯誤");
}
// 3. 將 JSON 字串轉為位元組(UTF-8)
$data = $jsonString;
// 4. RSA 1024-bit 公鑰 -> 明文限制 117 bytes (PKCS1 padding)
$chunkSize = 117;
$offset = 0;
$encrypted = '';
while ($offset < strlen($data)) {
$chunk = substr($data, $offset, $chunkSize);
$encryptedChunk = '';
if (!openssl_public_encrypt($chunk, $encryptedChunk, $publicKey, OPENSSL_PKCS1_PADDING)) {
die("加密失敗");
}
$encrypted .= $encryptedChunk;
$offset += $chunkSize;
}
// 5. 最終結果:Base64 編碼後輸出
$encryptedBase64 = base64_encode($encrypted);
echo "加密結果(Base64):\n" . $encryptedBase64;
// HTTP POST 请求函数
function httpPost($encryptedBase64) {
$url = 'your-api-endpoint'; // 替换为您的API接口地址
$options = array(
'http' => array(
'header' => "businessAccount: 我方提供的总代唯一标识\r\n" .
"site: XAgent 商户后台中的代理线路标识\r\n" .
"Content-Type: application/json\r\n",
'method' => 'POST',
'content' => json_encode([
'data'=> $encryptedBase64
])
)
);
$context = stream_context_create($options);
$result = file_get_contents($url, false, $context);
return $result;
}
?>
// 解密示例:
<?php
$pubKeyFormatted = <<<EOD
-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCioAIV3Npz1K8H4L+r4E2DCptp
MJHeD09qzAyh244+dkWRqod7u0G+JMQp2EJ50MEf/zmNsprtRET5HAaM2zG6TAIL
7hQLuUj/cDXLLWS+MvFIhjruR2xj//F7EQNJBPxE/CVcCzZQB7WDlH+aMYeCP+/y
DNINBEMF9KTM+0b6qwIDAQAB
-----END PUBLIC KEY-----
EOD;
// 取得公鑰資源
$publicKey = openssl_pkey_get_public($pubKeyFormatted);
if (!$publicKey) {
die("❌ 無法讀取公鑰格式,請檢查 PEM 是否正確\n");
}
// 加密內容(base64 編碼的 RSA "加密" 結果)
$encryptedBase64 = "RKgVABPFCq5jaOaR/nWzSkB1CDjtPP7Cs7KKlIs/LYePsTQM12NpaR+ph3TlMkOphSxcO4pchvOI+gwF/XuaYs9LLW/r3ikmgoGF4AzZdKMYx50fAECMM1SZeVBu10KqZx7dF0hDdhBNr+2gLJwletW9bkcBCRRBJG1NrtZUXPGBBV/u+hL2uTSKrzUT46JZkLz2XllZMGtcwYn9ioBF0R1usob7mvVHU74Nktwh+6n2M+lUwJFXD0/GWrJy8stv/QZtUxjrmRkKHK9xGmtzx2oLi1Is/5bsPb5VJaTTfi9u2qWgvwndhDMe2OuGSliaileMW3xwXB3wFCtaC5UoYg==";
// 將 base64 還原為二進位資料
$encrypted = base64_decode($encryptedBase64);
$chunkSize = 128; // 對應 1024-bit RSA
$decryptedAll = '';
for ($i = 0; $i < strlen($encrypted); $i += $chunkSize) {
$chunk = substr($encrypted, $i, $chunkSize);
$partialDecrypted = '';
$success = openssl_public_decrypt($chunk, $partialDecrypted, $publicKey, OPENSSL_PKCS1_PADDING);
if (!$success) {
echo "❌ 解密失敗於區塊 $i\n";
exit;
}
$decryptedAll .= $partialDecrypted;
}
echo "✅ 解密成功:\n";
echo $decryptedAll . "\n";
?>
// 加密示例:
import base64
from json import dumps
import requests
from Crypto.Cipher import PKCS1_v1_5
from Crypto.PublicKey import RSA
def rsa_encrypt_chunked(data: bytes, public_key_pem: str) -> bytes:
"""
使用 RSA 公钥 (PKCS#1) 分段加密数据。
:param data: 需要加密的原始数据 (bytes)
:param public_key_pem: 公钥字符串 (PEM 格式)
:return: 加密后的原始 bytes (未进行 Base64 编码)
"""
key = RSA.importKey(public_key_pem)
cipher_rsa = PKCS1_v1_5.new(key)
def get_rsa_chunk_size(public_key_pem: str) -> int:
"""
计算 RSA 加密时单次最大加密数据的大小。
:param public_key_pem: 公钥字符串 (PEM 格式)
:return: 可加密的最大字节数
"""
key = RSA.importKey(public_key_pem)
key_bits = key.size_in_bits() # 获取密钥的位数
key_bytes = key_bits // 8 # 转换为字节
return key_bytes - 11 # PKCS#1 v1.5 需要扣除 11 字节填充
offset = 0
encrypted_data = b""
chunk_size = get_rsa_chunk_size(public_key_pem) # 计算分块大小
while offset < len(data):
chunk = data[offset: offset + chunk_size] # 获取当前分块数据
encrypted_chunk = cipher_rsa.encrypt(chunk) # 使用 RSA 加密
encrypted_data += encrypted_chunk # 拼接加密后的数据
offset += chunk_size # 移动偏移量
return encrypted_data
if __name__ == "__main__":
# 业务账号唯一标识
business_account = "我方提供的总代唯一标识"
# 代理线路标识
site = "XAgent 商户后台中的代理线路标识"
# RSA 公钥
public_key_str = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
-----END PUBLIC KEY-----"""
# 需要加密的参数
payload = {"account": "用户名", "password": "password"}
data_bytes = dumps(payload).encode("utf-8") # 将字典转换为 JSON 并编码为字节
# 分段加密数据
encrypted_bytes = rsa_encrypt_chunked(data_bytes, public_key_str)
# 对加密数据进行 Base64 编码
encrypted_b64 = base64.b64encode(encrypted_bytes).decode("utf-8")
# 发送请求的参数
encrypt_param = {"data": encrypted_b64}
# 请求头
headers = {
"Content-Type": "application/json",
"businessAccount": business_account,
"site": site
}
# 接口地址
url = "https://xxxx.xxx.xxxx.xxxx/v3/xxxxx/xxxx/xxxx"
# 发送 POST 请求
response = requests.post(url, json=encrypt_param, headers=headers)
print("Response:", response.text)
// 解密示例:
import base64
from base64 import b64decode
from Crypto.PublicKey import RSA
from Crypto.Cipher import PKCS1_v1_5
pub_key_pem = """-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCioAIV3Npz1K8H4L+r4E2DCptp
MJHeD09qzAyh244+dkWRqod7u0G+JMQp2EJ50MEf/zmNsprtRET5HAaM2zG6TAIL
7hQLuUj/cDXLLWS+MvFIhjruR2xj//F7EQNJBPxE/CVcCzZQB7WDlH+aMYeCP+/y
DNINBEMF9KTM+0b6qwIDAQAB
-----END PUBLIC KEY-----"""
encrypted_b64 = "RKgVABPFCq5jaOaR/nWzSkB1CDjtPP7Cs7KKlIs/LYePsTQM12NpaR+ph3TlMkOphSxcO4pchvOI+gwF/XuaYs9LLW/r3ikmgoGF4AzZdKMYx50fAECMM1SZeVBu10KqZx7dF0hDdhBNr+2gLJwletW9bkcBCRRBJG1NrtZUXPGBBV/u+hL2uTSKrzUT46JZkLz2XllZMGtcwYn9ioBF0R1usob7mvVHU74Nktwh+6n2M+lUwJFXD0/GWrJy8stv/QZtUxjrmRkKHK9xGmtzx2oLi1Is/5bsPb5VJaTTfi9u2qWgvwndhDMe2OuGSliaileMW3xwXB3wFCtaC5UoYg=="
key = RSA.import_key(pub_key_pem)
cipher = PKCS1_v1_5.new(key)
encrypted_bytes = b64decode(encrypted_b64)
chunk_size = 128
decrypted = b''
for i in range(0, len(encrypted_bytes), chunk_size):
chunk = encrypted_bytes[i:i+chunk_size]
decrypted += cipher.decrypt(chunk, None)
print("✅ 解密結果:")
print(decrypted.decode("utf-8").strip())
// 加密示例:
package main
import (
"bytes"
"crypto/rand"
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/json"
"encoding/pem"
"fmt"
"net/http"
)
func main() {
// 参数
param := map[string]string{
"account": "用户名",
"password": "password",
}
// JSON 编码
jsonData, err := json.Marshal(param)
if err != nil {
fmt.Println("JSON Marshal error:", err)
return
}
// RSA 加密
publicKey := `-----BEGIN PUBLIC KEY-----
your-public-key-here
-----END PUBLIC KEY-----`
encodedData, err := rsaEncrypt(jsonData, publicKey)
if err != nil {
fmt.Println("RSA Encryption error:", err)
return
}
// Base64 编码
base64String := base64.StdEncoding.EncodeToString(encodedData)
fmt.Println("encoded:", base64String)
// 构建请求参数
encryptParam := map[string]string{
"data": base64String,
}
// 调用接口
req, err := http.NewRequest("POST", "your-api-endpoint", encryptParam)
if err != nil {
fmt.Println("HTTP Post error:", err)
}
// 设置请求头
req.Header.Set("Content-Type", "application/json")
req.Header.Set("site", "XAgent 商户后台中的代理线路标识")
req.Header.Set(businessAccount", "我方提供的总代唯一标识")
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
fmt.Println("HTTP Post get response error:", err)
}
fmt.Println("Response:", resp)
}
// 解密示例:
package main
import (
"crypto/rsa"
"crypto/x509"
"encoding/base64"
"encoding/pem"
"fmt"
"math/big"
)
func main() {
publicKeyPEM := `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCioAIV3Npz1K8H4L+r4E2DCptp
MJHeD09qzAyh244+dkWRqod7u0G+JMQp2EJ50MEf/zmNsprtRET5HAaM2zG6TAIL
7hQLuUj/cDXLLWS+MvFIhjruR2xj//F7EQNJBPxE/CVcCzZQB7WDlH+aMYeCP+/y
DNINBEMF9KTM+0b6qwIDAQAB
-----END PUBLIC KEY-----`
encryptedBase64 := "RKgVABPFCq5jaOaR/nWzSkB1CDjtPP7Cs7KKlIs/LYePsTQM12NpaR+ph3TlMkOphSxcO4pchvOI+gwF/XuaYs9LLW/r3ikmgoGF4AzZdKMYx50fAECMM1SZeVBu10KqZx7dF0hDdhBNr+2gLJwletW9bkcBCRRBJG1NrtZUXPGBBV/u+hL2uTSKrzUT46JZkLz2XllZMGtcwYn9ioBF0R1usob7mvVHU74Nktwh+6n2M+lUwJFXD0/GWrJy8stv/QZtUxjrmRkKHK9xGmtzx2oLi1Is/5bsPb5VJaTTfi9u2qWgvwndhDMe2OuGSliaileMW3xwXB3wFCtaC5UoYg=="
// Decode public key
block, _ := pem.Decode([]byte(publicKeyPEM))
if block == nil {
panic("❌ 無法解析 PEM 公鑰")
}
pubInterface, err := x509.ParsePKIXPublicKey(block.Bytes)
if err != nil {
panic("❌ 公鑰格式錯誤: " + err.Error())
}
pubKey := pubInterface.(*rsa.PublicKey)
// Base64 decode
encryptedBytes, err := base64.StdEncoding.DecodeString(encryptedBase64)
if err != nil {
panic("❌ base64 解析錯誤")
}
keySize := pubKey.Size() // 128 bytes for 1024-bit RSA
var decrypted []byte
for i := 0; i < len(encryptedBytes); i += keySize {
chunk := encryptedBytes[i : i+keySize]
// 解密公式:明文 = (密文 ^ e) mod n
c := new(big.Int).SetBytes(chunk)
m := new(big.Int).Exp(c, big.NewInt(int64(pubKey.E)), pubKey.N)
plain := m.Bytes()
// 若解出來不足 key size 長度,補 0
if len(plain) < keySize {
padding := make([]byte, keySize-len(plain))
plain = append(padding, plain...)
}
// 手動去除 PKCS#1 v1.5 padding
if plain[0] == 0x00 && plain[1] == 0x01 {
// 找到 0x00 作為分隔符號
idx := 2
for idx < len(plain) && plain[idx] == 0xFF {
idx++
}
if idx < len(plain) && plain[idx] == 0x00 {
decrypted = append(decrypted, plain[idx+1:]...)
} else {
panic("❌ Padding 格式錯誤")
}
} else {
panic("❌ 非預期 padding 起始位元")
}
}
fmt.Println("✅ 解密成功:")
fmt.Println(string(decrypted))
}
// 加密示例:
const crypto = require('crypto');
const axios = require('axios');
// 参数
const param = {
account: '用户名',
password: 'password'
};
// JSON 编码
const jsonData = JSON.stringify(param);
// RSA 加密
const publicKey = `-----BEGIN PUBLIC KEY-----
your-public-key-here
-----END PUBLIC KEY-----`;
const buffer = Buffer.from(jsonData, 'utf8');
const encryptedData = crypto.publicEncrypt(publicKey, buffer);
// Base64 编码
const base64String = encryptedData.toString('base64');
console.log("encoded: " + base64String);
// 构建请求参数
const encryptParam = {
data: base64String
};
// 调用接口
var endpoint = 'your-api-endpoint';
let config = {
method: 'post',
maxBodyLength: Infinity,
url: endpoint,
headers: {
'businessAccount': '我方提供的总代唯一标识',
'site': 'XAgent 商户后台中的代理线路标识',
'Content-Type': 'application/json'
},
data : encryptParam
};
axios.request(config)
.then((response) => {
console.log(JSON.stringify(response.data));
}
// 解密示例:
const crypto = require('crypto');
// ▶ 公鑰 PEM 格式
const publicKey = `-----BEGIN PUBLIC KEY-----
MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCioAIV3Npz1K8H4L+r4E2DCptp
MJHeD09qzAyh244+dkWRqod7u0G+JMQp2EJ50MEf/zmNsprtRET5HAaM2zG6TAIL
7hQLuUj/cDXLLWS+MvFIhjruR2xj//F7EQNJBPxE/CVcCzZQB7WDlH+aMYeCP+/y
DNINBEMF9KTM+0b6qwIDAQAB
-----END PUBLIC KEY-----`;
// ▶ 加密後的 Base64 字串
const base64EncodedData = `RKgVABPFCq5jaOaR/nWzSkB1CDjtPP7Cs7KKlIs/LYePsTQM12NpaR+ph3TlMkOphSxcO4pchvOI+gwF/XuaYs9LLW/r3ikmgoGF4AzZdKMYx50fAECMM1SZeVBu10KqZx7dF0hDdhBNr+2gLJwletW9bkcBCRRBJG1NrtZUXPGBBV/u+hL2uTSKrzUT46JZkLz2XllZMGtcwYn9ioBF0R1usob7mvVHU74Nktwh+6n2M+lUwJFXD0/GWrJy8stv/QZtUxjrmRkKHK9xGmtzx2oLi1Is/5bsPb5VJaTTfi9u2qWgvwndhDMe2OuGSliaileMW3xwXB3wFCtaC5UoYg==`;
// ▶ 將 base64 字串轉為 Buffer(二進位資料)
const encryptedBuffer = Buffer.from(base64EncodedData, 'base64');
// ▶ RSA 金鑰長度為 1024 bits(每次解密 128 bytes)
const chunkSize = 128;
let decryptedResult = '';
for (let i = 0; i < encryptedBuffer.length; i += chunkSize) {
const chunk = encryptedBuffer.slice(i, i + chunkSize);
try {
const decrypted = crypto.publicDecrypt(
{
key: publicKey,
padding: crypto.constants.RSA_PKCS1_PADDING
},
chunk
);
decryptedResult += decrypted.toString('utf8');
} catch (err) {
console.error(`❌ 解密失敗於區塊 ${i}:`, err.message);
process.exit(1);
}
}
console.log('✅ 解密成功:');
console.log(decryptedResult);
- API请求方式为:application/json.
- 需要将我方提供的2个固定值,添加在请求头中,header key为 site和businessAccount
- 您需要将请求体使用公钥 (publicKey) 进行RSA加密,然后把加密后的byte数组转为Base64字符串,最后组装为 {"data":"加密后的Base64字符串"} 格式的json提交给接口
- http返回对象中 code为返回码 200=正常,数据在data中.当code不为200时,message为错误信息.
- 请求示例
- 例 XAgent服务器域名为 https://xagent-open-api-uat.ncfc.cc
- 某个接口的地址为 /v3/single/act
- 商户端公钥为 MIGfMA0GCSqGSIb3DQEBAQUAA4GNADC...
- 业务参数json数据 {"field_1":"value_1","field_2":"value_2"}
- 先对业务参数RSA加密得到密文 Os977UOvhnqN+0xY4YBg95vlBpaKmgWAHnTa...
- 设置请求头 businessAccount site content-type
- 对密文base64编码后,构建统一的请求参数实体 {"data":"Os977UOvhnqN+0xY4YBg95vlBpaKmgWAHnTa..."}
- 使用post提交方式请求 https://xagent-open-api-uat.ncfc.cc/v3/single/act
- 得到响应数据 {"code":200,"message":"success","data":{"field_a":"value_a","field_b":"value_b"}}
- 判断code是否为200, 若为200, 则强烈建议商户端对响应数据进行验签, 不是200则不会有签名值, 签名值从响应头 signature 中获取得到
- 将Body中的数据拼接上公钥得到 {"code":200,"message":"success","data":{"field_a":"value_a","field_b":"value_b"}}MIGfMA0GCSqGSIb3DQEBAQUAA4GNADC...
- 将拼接好的字符串通过MD5算法得到信息摘要, 再与响应头中的签名值进行比较, 若一致则响应数据是安全的
- 之后再根据业务参数进行后续的业务逻辑判断
用户注册 / 登录(游戏入口)
接口路径
POST /v3/single/user/login
接口描述
于会员登入游戏时调用此接口, 请求此接口 注册/登录用户, 并同时获取带用户token的URL入口, account必须唯一。
场馆
如需对接 XG 场馆,需要实现此接口。
请求参数
Body:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| account | string | Y | 玩家帐号 (只支持(2~13)位小写字符或数字) ^[a-z0-9]{2,8}$ |
| password | string | Y | 帐号密码 (不超过20字符) |
| gameType | string | Y | 游戏类别代码 (参考附录) |
| isMobile | bool | Y | 是否为手机端 |
| gameCode | string | Y | 游戏编码, 具体游戏的编码 |
| lang | string | Y | 语言类型 (参考附录) |
| coin | string | Y | 货币类型 (参考附录) |
| line | string | N | 线路, 部分场馆支持, 如支持的则用这个值填充三方的“线路/站点”体系的必填参数, 不传则为默认值 |
| lobby | string | N | 大厅地址, 部分场馆支持, 比如从场馆游戏页面回跳到商户的页面, 如支持的则用这个值填充三方的“大厅地址/玩家IP”体系的必填参数, 不传则为空 |
| userIP | string | N | 玩家IP, 如支持的则用这个值填充三方的“大厅地址/玩家IP”体系的必填参数, 不传则为空 |
# input sample
curl --location 'https://xagent-open-api-uat-hh.ncfc.cc/v3/single/user/login' \
--header 'businessAccount: testaccount' \
--header 'site: default' \
--header 'Content-Type: application/json' \
--data '{
"data":"afafCuR6SHzSHFMjOEm44FdKkDPL9KMpeJEVfeolaUFI6RDHRlpL+BDRYGnniSHcEeKycmaKblh0w5fH8xVMTrssep1VmlSuIDd6VZJX+LQgWpjs7ExpAK4aD9O1NqssfcYbgtVUAzuAanbk3AStWtp8MFi7X7jkzm5WeeuCkX8tgXt3CEBfczlegzKiLZoYhdobLXbBaMo0auj8ZxWiQobnP4vL2Q/19sd0kIzkaYgryYpDa4e9PbR2QMwnowXOgfJ5hYh//+YAybgGq1NzHfc4N2AWK3QGFk2H8rHqVMgnyBeTBSE+hWqyXauDfl4yq43rGU+MqekEB0Dz2utY3A=="
}'
// input sample
{
"account": "68111111",
"password": "123456",
"gameType": "xg_electronic",
"isMobile": true,
"gameCode": "123",
"lang": "zh",
"coin": "cny",
"line": "default",
"lobby": "https://h111.xg.io/zh-CN/",
"userIP": "39.123.252.45"
}
返回数据
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| code | number | 必须 | 200 | 错误码,调用成功为200,失败为其他值,见错误码定义 | |
| message | string | 非必须 | 错误码不为200时,此字段展示错误信息 | ||
| data | object | 非必须 | 具体数据字段,见data数据定义 | *备注:* 具体数据内容 |
// response
{
"code": 200,
"data": {
"url": "https://xxxxxxxx",
"urlType": 1
},
"message": "success"
}
data 数据:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| urlType | int | Y | url类型 [1:直接跳转的url 2:自动跳转的from表单] |
| url | string | Y | 进入游戏地址 |
获取历史注单
接口路径
POST /v3/single/bet/betting
接口描述
查询游戏历史注单的接口 (一次调用最多返回5000条数据)
场馆
如需对接 XG 场馆,需要实现此接口。
请求参数
Body:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别代码 (参考附录) |
| startTimestampMs | string | Y | 开始时间戳 |
| endTimestampMs | string | Y | 结束时间戳, 开始与结束时间不能超过12个小时 |
| pageIndex | string | Y | 页码 |
# input sample
curl --location 'https://xagent-open-api-uat-hh.ncfc.cc/v3/single/bet/betting' \
--header 'businessAccount: testaccount' \
--header 'site: default' \
--header 'Content-Type: application/json' \
--data '{
"data":"SNQQ39/jXIZkpmq16SK4ujLLVNnrbjM4KZ/LV0xJrcwbzyQRN1SuPvOMP5D8jtP5LGrs4cGjzSbD6MHThlUsPSEdplPa9yxnSzKXKGcoGtXgpqNryEY10iCQEJaFN0Cw43+u83jBUle6hPryf5Rj5fn9jLilumaTQYQeRLj1u20="
}'
// input sample
{
"gameType": "xg_electronic",
"startTimestampMs": "1735660800000",
"endTimestampMs": "1735704000000",
"pageIndex": "1"
}
返回数据
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| code | number | 必须 | 错误码,调用成功为200,失败为其他值,见错误码定义 | ||
| message | string | 非必须 | 错误码不为200时,此字段展示错误信息 | ||
| data | String | 非必须 | 具体数据字段,见下方data数据定义 |
data数据:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| pageIndex | string | Y | 页码 |
| pageTotal | string | Y | 总页数 |
| bets | BetItemModel[] | Y | 历史注单集合 |
// response
{
"code": 200,
"message": "success",
"data": {
"pageIndex": "1",
"pageTotal": "1",
"bets": [
{
"betNoVenue": "BET202501010001",
"account": "testuser001",
"coin": "usd",
"gameType": "pg_electronic",
"gameCode": "demo_001",
"betAmount": 50.00,
"validAmount": 50.00,
"netWinningAmount": -20.00,
"betTimestampMs": 1735661200000,
"settlementTimestampMs": 1735664800000,
"isTrial": false,
"betState": 1,
"settlementState": 4,
"extend": {
"roundId": "R20250101001",
"tableId": "T01"
}
}
]
}
}
BetItemModel:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| betNoVenue | string | Y | 场馆注单号 |
| account | string | Y | 玩家账号 |
| coin | string | Y | 币种 (参考附录) |
| gameType | string | Y | 游戏类别 (参考附录) |
| gameCode | string | Y | 游戏编码 |
| betAmount | decimal | Y | 投注金额 |
| validAmount | decimal | Y | 有效投注 |
| netWinningAmount | decimal | Y | 净输赢 |
| betTimestampMs | long | Y | 下注时间戳 |
| settlementTimestampMs | long | Y | 结算时间戳 |
| isTrial | bool | Y | 是否试玩注单 |
| betState | int | Y | 注单状态 (参考附录) |
| settlementState | int | Y | 结算状态 (参考附录) |
| extend | object | Y | 注单扩展信息, 不同类别的注单的扩展信息有所差异 (参考附录) |
| site | string | Y | XAgent商户后台中的代理线路标识 |
获取游戏列表
接口路径
POST /v3/single/game/list-gamecode
接口描述
获取游戏列表的接口
场馆
如需对接 XG 场馆,需要实现此接口。
请求参数
Body:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别代码 (参考附录) |
# input sample
curl --location 'https://xagent-open-api-uat-hh.ncfc.cc/v3/single/game/list-gamecode' \
--header 'businessAccount: testaccount' \
--header 'site: default' \
--header 'Content-Type: application/json' \
--data '{
"data":"G4HEngPlnZ85x449qYvOsqeV2KjlgXTAjmWF2tUjRFSuOiVMvtFnxvEIwqEz7a1QCUrqaBPKWCOnAUs+OAkv61vApOhI9gZ9pU1o5fy7V+g0Q9Y4WYlD48chxr5KwFI5E9peTJaUaje+n50YBOgFhzKhfN3muQeJbEMIdYWB42A="
}'
// input sample
{
"gameType": "pg_electronic"
}
返回数据
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| code | number | 必须 | 错误码,调用成功为200,失败为其他值,见错误码定义 | ||
| message | string | 必须 | 错误码不为200时,此字段展示错误信息 | ||
| data | GameCodeList[] | 必须 | 游戏集合 (参考附录) |
// response
{
"code": 200,
"message": "success",
"data": [
{
"gameType": "pg_electronic",
"gameCode": "demo_001",
"gameNameEnus": "Demo Slot 1",
"gameNamePtbr": "Demo Slot 1 PT",
"gameNameZhcn": "示範老虎機 1",
"isEnable": true,
"logoUrl": "https://demo.example.com/logo/demo_001.png",
"remark": "熱門遊戲"
}
]
}
获取游戏类别列表
接口路径
POST /v3/single/game/list-gametype
接口描述
获取游戏类别列表的接口
场馆:
如需对接 XG 场馆,需要实现此接口。
请求参数
Body:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| coin | string | Y | 货币类型 (参考附录) |
# input sample
curl --location 'https://xagent-open-api-uat-hh.ncfc.cc/v3/single/game/list-gametype' \
--header 'businessAccount: testaccount' \
--header 'site: default' \
--header 'Content-Type: application/json' \
--data '{
"data":"JWBtLQ47oLSCHOYr+UaXwMZEdkw/s3moTstrFBFAwzukvW0lh57aeVXEqjLjMXxHOnObn/QmnMlUUygBSgCSlRY9J5T6HevQ2F5TmM4ESlRN1v1WeF++RKLSkuk45aOl2XywB9DcpVV8O9aorsByuhZ4MSUgo8fhePty3EnFN3w="
}'
// input sample
{
"coin": "usd"
}
返回数据
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| code | number | 必须 | 错误码,调用成功为200,失败为其他值,见错误码定义 | ||
| message | string | 必须 | 错误码不为200时,此字段展示错误信息 | ||
| data | GameTypeList[] | 必须 | 游戏类别集合 (数据结构参考附录) |
// response
{
"code": 200,
"message": "success",
"data": [
{
"gameType": "pg_electronic",
"name": "PocketGames 電子",
"isEnable": true
}
]
}
PG游戏馆会员踢线接口
接口路径
POST /v3/single/game/pgKickOut
接口描述
PG游戏专用,踢会员下线接口,调用后会员会被强制下线处理
请求参数
Body:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| account | string | Y | 玩家帐号 |
| gameType | string | Y | 游戏类别代码 (参考附录) |
# input sample
curl --location 'https://xagent-open-api-uat-hh.ncfc.cc/v3/single/game/pgKickOut' \
--header 'businessAccount: testaccount' \
--header 'site: default' \
--header 'Content-Type: application/json' \
--data '{
"data":"jAmvMbJ4ZgPt6GDnp9x0jAirH2qr3RiVLPXqm5xX+t2LzuY6lx9FttA7pA/iRksJXpvRuDfJouKSo3VtcjKkeV6qg39Ft1b8+yVdnZNjwC+peir7AMUbcx/61Unx6zTqt1K0n4RX89NGd7Y/kt9gYjShZQLtceqc0NR1FypJe34="
}'
// input sample
{
"account": "testuser001",
"gameType": "pg_electronic"
}
返回数据
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| code | number | 必须 | 错误码,调用成功为200,失败为其他值,见错误码定义 | ||
| message | string | 必须 | 错误码不为200时,此字段展示错误信息 |
// response
{
"code": 200,
"message": "success"
}
PG游戏馆查看订单详情
接口路径
POST /v3/single/game/pgSnapshot
接口描述
PG游戏专用,可查看某个会员某个PG游戏订单的详细游戏截图详情,调用接口后以URL的形式返回,直接访问即可查看
请求参数
Body:
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| account | string | Y | 玩家帐号 |
| gameType | string | Y | 游戏类别代码 (参考附录) |
| gameCode | string | Y | 游戏代码 (参考附录) |
| orderNo | string | Y | 订单编号 |
# input sample
curl --location 'https://xagent-open-api-uat-hh.ncfc.cc/v3/single/game/pgSnapshot' \
--header 'businessAccount: testaccount' \
--header 'site: default' \
--header 'Content-Type: application/json' \
--data '{
"data":"Z2R6/LFNXDvne7A2hXDx8WF6rTXZmihVIu1ZtoI9KIykueP5DFRX4VWeP0CZUXVxTLTlrx6Vr8xGk7O/G8RtEhqjDDx4Zka3wN0t19rIRsJyB3xMdBxBqHW8M6qk9Ou7IcFt+S0/PnkceEZjPdEDRWBs5bNQwSZ6x+mjKNSnA88="
}'
// input sample
{
"account": "testuser001",
"gameType": "pg_electronic",
"gameCode": "demo_001",
"orderNo": "ORDER20250101001"
}
返回数据
| 名称 | 类型 | 是否必须 | 默认值 | 备注 | 其他信息 |
|---|---|---|---|---|---|
| code | number | 必须 | 错误码,调用成功为200,失败为其他值,见错误码定义 | ||
| message | string | 必须 | 错误码不为200时,此字段展示错误信息 | ||
| data | string | 必须 | 游戏订单详情页面的URL,直接访问即可查看 |
// response
{
"code": 200,
"message": "success",
"data": "https://demo.example.com/snapshot/ORDER20250101001"
}
您需要提供的接口及要求说明
接入准备与说明
请求参数示例
统一的请求数据结构:
{ "data":"具体某个接口的参数为json字符串并进行RSA加密" }
我方在请求前, 会根据不同接口要求的参数, 组装参数, 然后将参数对象进行json序列化, 然后赋值给data字段。
data字段加密规则:根据RSA公钥进行解密即可
返回参数示例
您需要包装的响应参数为Json格式的数据,响应Json数据模板如下:
统一的响应数据结构:
{ "code": 200, "message":"错误消息", "data":"具体某个接口的参数为json 无需加密直接返回" }
需要注意: 此处您还需要组装包装一个参数到responseHeader里 具体规则如下:
responseHeader
Key:signature
value:您包装的所有返回结果的JSON (data不须再字符串化 见示例) + publicKey 然后MD5加密
例如:
所有返回结果JSON = {"code":200,"message":"success","data":{"account":"abc123","balance":100}}
则签名(signature)的源串为:
"{"code":200,"message":"success","data":{"account":"abc123","balance":100}}aaaa12345678"
得到响应后应,我方会先判断code是否为200成功, 然后再获取data字段数据
整体流程:
a) 我方会使用privateKey将数据加密好,放置在data,传入到您的接口中来
b) 您在接口中,接收到我方传过来的data参数,要先进行base64解码 , 然后根据我方提供的publicKey,使用RSA解密工具,对data进行解密
c) 我方传入的具体参数包装在data中,直接拿data的数据即可使用
d) 您在包装您的接口返回值时,data字段无需加密,直接返回原始值即可
e) 返回值组装好后, 根据包装好的返回值, signature字段 , 放置在responseHeader里返回响应
参数解密示例请参照上方加解密示例说明,根据各语言切换
- 本API版本接入前,我方会提供给您一份 唯一标识 和 publicKey 和 site(默认)
- 此处说明,为我方调用您的接口,需要您准备的事项
- 请求方式:POST
- 请求参数:格式为json, content-type=application/json
- 下方接口及说明中仅展示data字段所需要的数据
总流程示意

下注結算相关流程示意
正常下注 -> 結算

取消投注

取消已結算投注

活动派彩 / 人工加扣款及撤销调帐
每次調整金額都會生成新的帳單號,但只有取消帳單 /cancelbill 才會對應到原來的 billNoVenues。
adjustbill 主要用在 活动派彩 / 人工加扣款 这种「不依附于下注」的情况。
例如:
活动派彩:办活动送玩家奖金(不一定有下注)。
adjustbill → 加钱给玩家,生成 billNoVenues。
人工扣款:发现玩家异常,人工调整余额。
adjustbill → 扣钱(负数金额),生成 billNoVenues。
撤销调帐:如果这笔派彩/调整发错了,要撤销。
cancelbill → 依据原本的 billNoVenues 撤销。

1. **获取玩家信息接口(/getaccountinfo)
该接口为游戏方实时查询玩家余额接口
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型 (参考附录) |
// input sample
{
"account": "xxxxxxxx",
"coin": "cny"
}
- 响应参数
| 字段 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| account | string | Y | 玩家帐号 |
| accountName | string | N | 玩家名称 |
| coin | string | Y | 货币类型 (参考附录) |
| balance | decimal | Y | 玩家实时余额 |
// response
{
"account": "xxxxxxxx",
"accountName": "xxxxxxxx",
"balance": 100,
"coin": "cny"
}
2. **下注申请(/applycreatebet)

该接口在玩家下单或者预下单进行调用
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| bets | ApplyCreateBetItemV3Model[] | Y | 注单信息集合, 数据结构参考附录 |
// input sample
{
"gameType": "pg_electronic",
"account": "xxxxxxxx",
"coin": "cny",
"bets": [
{
"betAmount": 0,
"betNoVenue": "1982808557020184581:1982808557020184582",
"betTimestampMs": 1759232322918,
"gameCode": "135",
"isTrial": false
}
]
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"gameType": "pg_electronic",
"account": "xxxxxxxx",
"coin": "idr",
"balance": 100,
"results": {
"betType": 1,
"betNoVenue": "1982808557020184581:1982808557020184582",
"betNoMerchant": "10041162403",
"account": "xxxxxxxx",
"coin": "cny",
"betState": 1,
"settlementState": 1,
"operateState": 1,
"resultDesc": "Success"
}
}
3. 获取注单信息(/getbet)
- 请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| betNoVenues | string[] | Y | 注单号(场馆端的)集合 |
// input sample
{
"betNoVenues": [
"Nextspin_10177_56543398_202509200014361341271739"
],
"gameType": "nextsp_electronic"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| betMap | map |
Y | 注单信息字典, Key为注单号, Value为对应的注单信息; 若注单信息不存在, 返回空 Map {} 即可 |
// response
{
"betMap": {},
"gameType": "nextsp_electronic"
}
4. 更新初始注单(/updatebet)
- 必须是初始注单
- 不满足情况的商户端可以拒绝, 并返回对应的处理结果
关于初始订单的含义说明, 一笔注单在成功下注后都是要进入下一个最终状态的注单, 最终要么被取消, 要么被结算 即初始注单就是订单状态为有效且是未结算 (betState==1 && settlementState==1) 的注单
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| bets | ApplyCreateBetItemV3Model[] | Y | 注单信息集合, 数据结构参考附录 |
// input sample
{
"account": "xxxxxxxx",
"bets": [
{
"betAmount": 100,
"betNoVenue": "1557823605557955143",
"extend": {
"details": [
{
"betState": "已确认",
"desc": "Under 2.5",
"detailID": "1557823605557955399",
"league": "England Premier League",
"match": "2025-09-29 19:00:00",
"odds": 1.9,
"proj": "1007_Over/Under",
"teamA": "Everton FC ",
"teamB": "West Ham United"
},
{
"betState": "已确认",
"desc": "Under 3",
"detailID": "1557823605557955655",
"league": "Portugal Primeira Liga",
"match": "2025-09-29 19:00:00",
"odds": 1.89,
"proj": "1007_Over/Under",
"teamA": "FC Arouca ",
"teamB": "FC Porto"
},
{
"betState": "已结算",
"desc": "Besiktas JK -1/1.5",
"detailID": "1557823605557955911",
"league": "Turkey Super Lig",
"match": "2025-09-29 17:00:00",
"odds": 1.89,
"proj": "1000_Handicap",
"teamA": "Besiktas JK ",
"teamB": "Kocaelispor"
}
],
"isParlay": true,
"odds": 1.9,
"oddsType": "Europe",
"playType": "1",
"sportBetType": "Parlay"
},
"isTrial": false
}
],
"coin": "cny",
"gameType": "fb_sport"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"account": "xxxxxxxx",
"balance": 100,
"coin": "cny",
"gameType": "fb_sport",
"results": [
{
"account": "xxxxxxxx",
"betNoMerchant": "1972696774055727104",
"betNoVenue": "1557823605557955143",
"coin": "cny",
"operateState": 1
}
]
}
5. 取消初始注单(/cancelbet)

- 必须是初始注单
不满足情况的商户端可以拒绝, 并返回对应的处理结果
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| betNoVenues | string[] | Y | 注单号(场馆端的)集合 |
// input sample
{
"account": "xxxxxxxx",
"betNoVenues": [
"1759223994983"
],
"coin": "cny",
"gameType": "by_sport"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
关于注单与账单的关系, 请查看附录中的介绍
// response
{
"account": "xxxxxxxx",
"balance": 100,
"coin": "cny",
"gameType": "by_sport",
"results": [
{
"account": "xxxxxxxx",
"betNoMerchant": "1759223994983",
"betNoVenue": "",
"coin": "cny",
"operateState": 1
}
]
}
6. 回滚已取消注单(/backcancelbet)

- 将注单状态为已取消的注单(betState=4), 回到到初始状态
- 相当于就是重新下单了, 不过注单数据还是原先的
不满足情况的商户端可以拒绝, 并返回对应的处理结果
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| betNoVenues | string[] | Y | 注单号(场馆端的)集合 |
// input sample
{
"account": "xxxxxxxx",
"betNoVenues": [
"1759223994983"
],
"coin": "cny",
"gameType": "by_sport"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"account": "xxxxxxxx",
"balance": 100,
"coin": "cny",
"gameType": "by_sport",
"results": [
{
"account": "xxxxxxxx",
"betNoMerchant": "1972954549079937024",
"betNoVenue": "1759223994983",
"coin": "cny",
"operateState": 1
}
]
}
7. **结算初始注单(/settlementbet)

- 不同游戏馆或者说不同类型注单的下注结算过程有所差别
- 1.先调用下注接口, 再调用结算接口
- 2.直接就是给结算后的注单, 相当于下注并结算调用一次接口完成
不满足情况的商户端可以拒绝, 并返回对应的处理结果
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| bets | SettlementBetItemV3Model[] | Y | 注单信息集合, 数据结构参考附录 |
// input sample
{
"account": "xxxxxxxx",
"bets": [
{
"betAmount": 0,
"betNoVenue": "JiLiGaming_10177_56367276_586706132379648082",
"betTimestampMs": 0,
"extend": {},
"isCreateAndSettlement": false,
"isTrial": false,
"prizeAmount": 0,
"settlementAmountType": 1,
"settlementTimestampMs": 1759233707753,
"validAmount": 1.3
}
],
"coin": "cny",
"gameType": "jili_electronic"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"gameType": "jili_electronic",
"account": "xxxxxxxx",
"coin": "cny",
"balance": 36.46,
"results": [
{
"betType": 1,
"betNoVenue": "JiLiGaming_10177_56367276_586706132379648082",
"betNoMerchant": "129963JiLiGaming_10177_56367276_586706132379648082",
"account": "xxxxxxxx",
"coin": "cny",
"betState": 1,
"settlementState": 1,
"operateState": 1,
"resultDesc": ""
}
]
}
8. 重新结算注单(/resettlementbet)
- 忽略上一次的结算结果, 按新的结算结果重新结算一遍
- 通常情况下, 若商户收到重新结算的请求, 则需要对原先结算的结果进行撤销, 然后按重新结算的结果进行结算. 若在此之前商户系统的该笔注单未结算, 则忽略撤销的操作. 最终以商户端的系统设计来定
不满足情况的商户端可以拒绝, 并返回对应的处理结果
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| bets | SettlementBetItemV3Model[] | Y | 注单信息集合, 数据结构参考附录 |
// input sample
{
"account": "xxxxxxxx",
"bets": [
{
"betNoVenue": "G00012c1fe85c",
"extend": {},
"prizeAmount": 0,
"settlementAmountType": 1,
"settlementTimestampMs": 1759041579521
}
],
"coin": "cny",
"gameType": "art_electronic"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"account": "xxxxxxxx",
"balance": 100,
"coin": "cny",
"gameType": "art_electronic",
"results": [
{
"account": "xxxxxxxx",
"betNoVenue": "G00012c1fe85c",
"coin": "cny",
"operateState": 1
}
]
}
9. 回滚已结算注单(/backsettlementbet)
- 将已结算的注单(betState=1 && settlementState=3/4/5), 回滚到初始状态
- 通常情况下, 若这笔注单是赢了的, 此时回滚应该需要将已结算的净输赢返还, 当然最终按商户端的系统设计来定
- 必须是已结算的注单(输/赢/平)
不满足情况的商户端可以拒绝, 并返回对应的处理结果
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| betNoVenues | string[] | Y | 注单号(场馆端的)集合 |
// input sample
{
"account": "xxxxxxxx",
"betNoVenues": [
"1759224019772"
],
"coin": "cny",
"gameType": "by_sport"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"account": "xxxxxxxx",
"balance": 0,
"coin": "cny",
"gameType": "by_sport",
"results": [
{
"account": "xxxxxxxx",
"betNoMerchant": "1972954652744851456",
"betNoVenue": "1759224019772",
"coin": "cny",
"operateState": 1
}
]
}
10. 取消已结算注单(/cancelsettlementbet)
- 将已经结算的注单, 直接取消掉, 即 betState 由 1 修改为 4
- 通常情况下, 商户端根据自己系统的设计对余额进行返还
- 必须是已结算的注单
不满足情况的商户端可以拒绝, 并返回对应的处理结果
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| betNoVenues | string[] | Y | 注单号(场馆端的)集合 |
// input sample
{
"account": "xxxxxxxx",
"betNoVenues": [
"1759224019772"
],
"coin": "cny",
"gameType": "by_sport"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBetItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"account": "xxxxxxxx",
"balance": 100,
"coin": "cny",
"gameType": "by_sport",
"results": [
{
"account": "xxxxxxxx",
"betNoMerchant": "1972954652744851456",
"betNoVenue": "1759224019772",
"coin": "cny",
"operateState": 1
}
]
}
11. **余额调整(/adjustbill)

- 对于游戏馆的活动派彩的情况, 是没有注单数据的, 则会通过这个接口将数据推送到商户系统
- 部分游戏馆投注/结算时, 存在一个回合多次投注, 但最终也算是一笔注单的, 也是使用这个接口进行扣除或者增加余额
这个接口也可称为增加账单
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| bills | SingleBillItemV3Model[] | Y | 调整信息集合, 数据结构参考附录 |
// input sample
{
"account": "xxxxxxxx",
"bills": [
{
"account": "xxxxxxxx",
"amount": 100,
"billNoVenue": "72011641",
"coin": "cny",
"reason": "SETTLED-WagerId-2882367827-ActionId-122887905",
"timestampMs": 1759234109445
}
],
"coin": "cny",
"gameType": "ap_sport"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBillItemV3Result[] | Y | 注单处理结果集合, 数据结构参考附录 |
// response
{
"account": "xxxxxxxx",
"balance": 100,
"coin": "cny",
"gameType": "ap_sport",
"results": [
{
"account": "xxxxxxxx",
"billNoMerchant": "1972996972647260160",
"billNoVenue": "72011641",
"coin": "cny",
"operateState": 1
}
]
}
12. 取消账单(/cancelbill)
- 通过场馆的账单号, 取消adjustbill接口产生的账单, 商户需要对账单中增加或者扣除进行回滚操作, 并将账单状态置为“无效”
若账单取消成功/不存在/已经“无效”, 商户需返回对应的处理结果
请求参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| billNoVenues | string[] | Y | 账单号集合(场馆端) |
// input sample
{
"account": "xxxxxxxx",
"billNoVenues": [
"214791496971-900-948719984-2209517006"
],
"coin": "cny",
"gameType": "ly_brand"
}
- 响应参数
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型(参考附录) |
| balance | decimal | Y | 处理成功后的玩家实时余额 |
| results | SingleBillItemV3Result[] | Y | 账单处理结果集合, 数据结构参考附录 |
// response
{
"account": "xxxxxxxx",
"balance": 100,
"coin": "cny",
"gameType": "ly_brand",
"results": [
{
"account": "xxxxxxxx",
"billNoMerchant": "1972703317955915776",
"billNoVenue": "214791496971-900-948719984-2209517006",
"coin": "cny",
"operateState": 1
}
]
}
附录
ApplyCreateBetItemV3Model 单一钱包下注注单模型
| 参数 | 数据类型 | 说明 |
|---|---|---|
| betNoVenue | string | 注单号 - 第三方游戏馆的 |
| gameCode | string | 游戏编码 |
| betAmount | decimal | 下注金额,2位小数 |
| betTimestampMs | long | 下注时间戳(毫秒级) |
| isTrial | bool | 是否为试玩的注单 |
| extend | object | 棋牌注单的详细数据,betType=1时有数据 |
SettlementBetItemV3Model 单一钱包结算注单模型
| 参数 | 数据类型 | 说明 |
|---|---|---|
| betNoVenue | string | 注单号 - 第三方游戏馆的 |
| settlementAmountType | decimal | 结算时, 以哪个金额来计算[1:PrizeAmount 2:NetWinningAmount] |
| netWinningAmount | decimal | 净输赢金额, 4位小数 此处注意:每个游戏馆支持的取整逻辑不一样, 此处为XAgent接口返回的小数位数 |
| prizeAmount | decimal | 中奖金额/派奖金额(含下注金额),4位小数 此处注意:每个游戏馆支持的取整逻辑不一样, 此处为XAgent接口返回的小数位数 |
| settlementTimestampMs | long | 结算时间戳(毫秒级) |
| extend | object | 棋牌注单的详细数据,betType=1时有数据 |
| isCreateAndSettlement | bool | 是否为下注并结算,只有结算接口可能出现true,一般电子游艺类型的注单,不会先下注再结算,而是直接通知结果的 |
| gameCode | string | 游戏编码, isCreateAndSettlement=true才有值 |
| betAmount | decimal | 下注金额,2位小数, isCreateAndSettlement=true才有值 |
| betTimestampMs | long | 下注时间戳(毫秒级), isCreateAndSettlement=true才有值 |
| isTrial | bool | 是否为试玩的注单, isCreateAndSettlement=true才有值 |
| validAmount | decimal | 有效投注金额(部分场馆支持) |
GetBetItemV3Model 单一钱包获取注单模型
| 参数 | 数据类型 | 说明 |
|---|---|---|
| betNoVenue | string | 注单号 - 第三方游戏馆的 |
| betNoMerchant | string | 注单号 - 商户端的 |
| account | string | 玩家帐号 |
| coin | string | 货币类型 (参考附录) |
| gameCode | string | 游戏编码 |
| betState | int | 注单状态 (参考附录) |
| betAmount | decimal | 下注金额,2位小数 |
| betTimestampMs | long | 下注时间戳(毫秒级) |
| isTrial | bool | 是否为试玩的注单 |
| extend | object | 棋牌注单的详细数据,betType=1时有数据 |
| settlementState | int | 结算状态[1:未结算/未开奖/等待开奖 3:赢/中奖 4:输/未中奖 5:和/平局], 这个字段对于部分游戏仅供参考, 所以请根据下注和结算的金额计算出的净输赢最终确定输赢结果 |
| settlementTimestampMs | long | 结算时间戳(毫秒级) |
| netWinningAmount | decimal | 净输赢金额, 2位小数 |
关于注单信息中出现的金额特别说明
- BetAmount 下注金额 只能是正数(大于0)
- PrizeAmount 派彩金额 含下注金额, 任何情况都不会为负数
- NetWinningAmount 净输赢 减去下注金额的最终输赢, 正数负数都有可能, 若净输赢为负数, 其绝对值必定小于等于下注金额
- 下注10块, 没中奖: BetAmount=10; PrizeAmount=0; NetWinningAmount=-10;
- 下注10块, 中了8块: BetAmount=10; PrizeAmount=8; NetWinningAmount=-2;
- 下注10块, 中了10块: BetAmount=10; PrizeAmount=10; NetWinningAmount=0;
下注10块, 中了14块: BetAmount=10; PrizeAmount=14; NetWinningAmount=4;
这三个金额必定满足恒等式 BetAmount = PrizeAmount - NetWinningAmount;
结算时候因为不同游戏馆接口的差异, 不一定每次都是三个字段都有值, 但是一定会按满足这个公式定义的情况, 提供到商户, 以供商户进行结算, 例如SettlementAmountType指明使用PrizeAmount进行结算, 则使用PrizeAmount进行结算即可, 不用关心NetWinningAmount的值.
对于商户结算, 用 PrizeAmount 和 NetWinningAmount 这两个数据即可完成结算。
对于先下注后结算的注单, 也就是下注时候已经扣过下注金额的, 此时结算的就只是根据中奖情况返还余额而已。
- 按 PrizeAmount 计算则为: 返还金额 = PrizeAmount, 如果大于0则增加余额, 否则必定为0
- 按 NetWinningAmount 计算则为: 返还金额 = BetAmount + NetWinningAmount, 如果大于0则增加余额, 否则必定为0
对于同时下注并结算的, 此时BetAmount有值, PrizeAmount和NetWinningAmount也必定会有一个或者两个都有值。
这个就看商户那边是如何记账, 如果一笔扣一笔加的, 则与先下注后结算的没啥区别。
- 如果按一笔记录的(可能是增加可能是减少的)
- 下注金额肯定没得差别, 就是最终加减款有点差别,
- 按 PrizeAmount 计算则为: 最终加减款 = PrizeAmount - BetAmount, 如果大于0则增加余额, 小于0就是减少, 也有为0的情况
- 按 NetWinningAmount 计算则为: 终加减款 = NetWinningAmount, 如果大于0则增加余额, 小于0就是减少, 也有为0的情况
一定要牢记, 这三个金额必定满足恒等式 BetAmount = PrizeAmount - NetWinningAmount 。必须是满足这个等式的才是正确的。
SingleBetItemV3Result 单一钱包注单处理结果模型
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| betType | int | Y | 注单类别 [0:棋牌 1:电子游艺 2:真人视讯 3:彩票 4:竞技体育 5:股票] |
| betNoVenue | string | Y | 注单号 - 第三方游戏馆的 |
| betNoMerchant | string | Y | 注单号 - 商户的 |
| account | string | Y | 玩家帐号 |
| coin | string | Y | 货币类型 (参考附录) |
| betState | int | Y | 注单状态 (参考附录) |
| settlementState | int | Y | 结算状态[1:未结算/未开奖/等待开奖 3:赢/中奖 4:输/未中奖 5:和/平局] |
| operateState | int | Y | 操作的结果, 参考附录注单处理结果 |
| resultDesc | string | Y | 错误描述 |
- 关于注单与账单的关系与区别:
- 注单是玩家的游戏记录, 而账单是财务记录。
- 大部分场馆是没有账单的设计, 只有部分场馆, 会在一局中投注多次, 会有多条账单, 最终却只有一笔注单信息。商户只需要按本文档的要求对接回调即可。
- 对于只有账单而没有注单馆, 商户若需要注单数据, 则可调用单一钱包模式的获取历史注单接口, 得到玩家的历史注单记录
BrandBetItemExtend 棋牌注单的详细数据
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| roundNo | string | Y | 游戏局号 |
ElectronicBetItemExtend 电子游艺注单的详细数据
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| 暂无字段, 预留类型 |
LiveBetItemExtend 真人注单的详细数据
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| tableNo | string | Y | 桌子编号 |
LotteryBetItemExtend 彩票注单的详细数据
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| roundNo | string | Y | 期号 |
SportBetItemExtend 体育注单的详细数据
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| playType | string | Y | 体育比赛类型, 例如: 足球/篮球等 |
| sportBetType | string | Y | 体育注单类型[0:普通投注/普通注单/非滚球 1:混合投注/过关注单/混合非滚球 2:普通滚球/普通走地 3:混合滚球/混合走地 9:其它] |
| oddsType | int | Y | 赔率类型 [1:欧洲盘 2:香港盘 3:马来盘 4:印尼盘 ] |
| odds | decimal | Y | 赔率 |
| matchDate | string | Y | 比赛时间 |
| isParlay | bool | Y | 是否为混合过关,否则为普通投注 |
| details | SportBetItemDetail[] | Y | 体育注单比赛信息集合 |
StockBetItemExtend 股票注单的详细数据
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| stockCode | string | Y | 股票编码 |
| stockName | string | Y | 股票名称 |
| transDirection | string | Y | 交易方向 |
| transPrice | decimal | Y | 成交价格 |
| transNumber | decimal | Y | 成交数量 |
| transFee | decimal | Y | 手续费 |
| leverage | decimal | Y | 杠杆 |
SportBetItemDetail 体育注单具体的比赛信息实体
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| league | string | Y | 联赛名称 |
| teamA | string | Y | 主队名称 |
| teamB | string | Y | 客队名称 |
| proj | string | Y | 赌注项目, 若为混合过关,则是每场比赛的, 比如让球/独赢/大小/总入球等等 |
| desc | string | Y | 比赛内容, 若为混合过关,则是每场比赛的, 比如主队让球1个/总入球4个/客队独赢等等, 混合过关的时候,这个才有效 |
| score | string | Y | 最终比分(格式必须为 A:B(主队得分:客队得分) 或为空), 若为混合过关,则是每场比赛的 |
| gq | string | Y | 滚球(走地)下注时的比分,仅限走地, 若为混合过关,则是每场比赛的 |
| betState | string | Y | 注单状态, 若为混合过关,则是每场比赛的, 注单状态的文字 |
| odds | decimal | Y | 赔率, 若为混合过关,则是每场比赛的 |
| match | string | Y | 比赛时间(yyyy-MM-dd HH:mm:ss), 若为混合过关,则是每场比赛的 |
SingleBillItemV3Model 单一钱包账单模型
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| billNoVenue | string | Y | 账单号, 第三方游戏馆的 |
| account | string | Y | 会员账号 |
| coin | string | Y | 币种 |
| amount | decimal | Y | 调整金额, 正数为增加, 负数为减少 |
| timestampMs | long | Y | 调整时间戳(毫秒级) |
| reason | string | Y | 调整原因 |
| remark | string | Y | 备注信息 |
SingleBillItemV3Result 单一钱包账单处理结果模型
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| billNoVenue | string | Y | 账单号, 第三方游戏馆的 |
| billNoMerchant | string | Y | 账单号, 下游商户的 |
| account | string | Y | 会员账号 |
| coin | string | Y | 币种 |
| operateState | int | Y | 操作的结果, 参考BillOperateStates账单处理结果 |
GameType
此处只展示部分GameType,仅作参考,详细请移步查看XAgent Game List 文档, 后续增加了会再文档中体现, 或者通过商户后台查看最新数据
| 编码 | 名称 | 说明 |
|---|---|---|
| xg_electronic | XG电子 | |
| ag_electronic | AsiaGaming电子 | |
| ag_live | AsiaGaming真人 | |
| ax_electronic | Aviatrix电子 | |
| bng_electronic | BNG电子 | |
| cr_sport | 皇冠体育 | |
| dg_live | DreamGaming真人 | |
| evo_live | Evolution真人 | |
| fb_sport | FB体育 | |
| fg_brand | FunGaming棋牌 | |
| imty_sport | InplayMatrix体育 | |
| jdb_electronic | 夺宝电子 | |
| ky_brand | 开元棋牌 | |
| mg_electronic | MicroGaming电子 | |
| nlc_electronic | NoLimitCity电子 | |
| ob_live | DB(原OB)真人 | |
| obty_sport | 熊猫体育 | |
| pg_electronic | PocketGames电子 | |
| png_electronic | PlayNGo电子 | |
| pp_electronic | PragmaticPlay电子 | |
| pp_live | PragmaticPlay真人 | |
| rt_electronic | Red Tiger电子 | |
| sc_lottery | SHI CAI彩票 | |
| sexy_live | Sexy真人 | |
| shb_sport | 沙巴体育 |
Coin 币种
后续增加了会再文档中体现, 或者通过商户后台查看最新数据
| 编码 | 名称 | 说明 |
|---|---|---|
| aud | 澳大利亚元 | |
| bdt | 孟加拉塔卡 | |
| brl | 巴西雷亚尔 | |
| cny | 人民币 | |
| eur | 欧元 | |
| hkd | 港元 | |
| idr | 印尼盾 | |
| inr | 印度卢比 | |
| irr | 伊朗里亚尔 | |
| jpy | 日元 | |
| khr | 柬埔寨瑞尔 | |
| krw | 韩元 | |
| mmk | 缅元 | |
| myr | 马来西亚令吉 | |
| ngn | 尼日利亚奈拉 | |
| npr | 尼泊尔卢比 | |
| php | 菲律宾比索 | |
| pkr | 巴基斯坦卢比 | |
| pyg | 巴拉圭爪拉尼 | |
| rub | 俄罗斯卢布 | |
| sgd | 新加坡元 | |
| thb | 泰铢 | |
| twd | 新台币 | |
| usd | 美元 | |
| vnd | 越南盾 | |
| usdt | USDT |
Lang 语言
后续增加了会再文档中体现, 或者通过商户后台查看最新数据
| 编码 | 名称 | 说明 |
|---|---|---|
| en | 英文 | |
| hi | 印地语 | |
| id | 印尼语 | |
| ja | 日语 | |
| ko | 韩文 | |
| pt | 葡萄牙文 | |
| ta | 泰米尔语 | |
| th | 泰语 | |
| vi | 越南语 | |
| zh | 中文 | |
| zh_hant | 中文-繁体 | |
| es | 西班牙语 |
BetOperateStates 注单处理结果
| 编码 | 名称 | 说明 |
|---|---|---|
| 0 | 未知, 未赋值情况下的默认值或者不确定是否成功的任意情况, 也是失败 | |
| 1 | 成功 | |
| 2 | 失败 | |
| 3 | 余额不足 | |
| 4 | 玩家不存在 | |
| 20 | 注单不存在 | |
| 21 | 注单重复 | |
| 22 | 注单已结算 | |
| 23 | 注单已取消 | |
| 24 | 注单已回滚 |
BillOperateStates 账单处理结果
| 编码 | 名称 | 说明 |
|---|---|---|
| 0 | 未知, 未赋值情况下的默认值或者不确定是否成功的任意情况, 也是失败 | |
| 1 | 成功 | |
| 2 | 失败 | |
| 3 | 余额不足 | |
| 4 | 玩家不存在 | |
| 20 | 账单不存在 | |
| 21 | 账单重复 | |
| 23 | 账单已取消 |
VenueResultCodes 常见错误码
| 编码 | 名称 | 说明 |
|---|---|---|
| 200 | 成功, 除此之外全部都为失败 | |
| 400 | 参数错误 | |
| 9*** | 内部服务错误 | |
| 9999 | 包含任何失败的情况 | |
| 3000 | XAgent-系统维护 | |
| 3001 | XAgent-IP白名单限制 | |
| 3002 | 商户未开通这个游戏馆或者币种 | |
| 5000 | 游戏馆系统维护 | |
| 5001 | 游戏馆IP白名单限制 | |
| 5002 | 游戏馆不可访问 | |
| 5003 | 游戏馆系统繁忙 | |
| 5004 | 不可直接进入大厅 | |
| 5005 | 订单处理中 | |
| 5006 | 余额不足 | |
| 7000 | 商户端系统维护 | |
| 7001 | 商户端IP白名单限制 | |
| 7003 | 商户端系统繁忙 | |
| 7004 | 商户端账号不存在 |
- 3*** 系列的是XAgent相关的错误码
- 5*** 系列的是游戏馆相关的错误码
- 7*** 系列的是为商户端回调接口一些特定场景返回的错误码, 商户端处理回调时, 可根据实际情况返回对应错误码
- 其他错误码则时通用的错误码, 比如200/9999
BetStates 注单状态
| 编码 | 名称 | 转账模式 | 单一钱包 | 说明 |
|---|---|---|---|---|
| 0 | 未知状态 | 可用 | 可用 | |
| 1 | 注单已被接受,有效 | 可用 | 可用 | |
| 2 | 拒绝/投注失败 | 可用 | 不可用 | |
| 3 | 撤销/注销/第三方强制撤单/退款 | 可用 | 不可用 | |
| 4 | 注单已被取消 | 可用 | 可用 | |
| 5 | 回收/出售 | 可用 | 不可用 |
- 单一钱包的注单状态只有有效和取消两种状态
- 未知状态是不可获取或者获取出错的情况才会出现, 正常不会出现
GameTypeList 游戏类别实体
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| name | string | Y | 对应的中文名 |
| isEnable | bool | Y | 是否启用 true / false |
GameCodeList 游戏列表实体
| 参数 | 数据类型 | 必填 | 说明 |
|---|---|---|---|
| gameType | string | Y | 游戏类别 |
| gameCode | string | Y | 游戏编码, 具体游戏的编码 |
| gameNameEnus | string | Y | 游戏英文名称 |
| gameNamePtbr | string | Y | 游戏葡萄牙语名称 |
| gameNameZhcn | string | Y | 游戏中文名称 |
| isEnable | bool | Y | 是否启用 true / false |
| logoUrl | string | Y | 游戏logo |
| remark | string | Y | 备注 |