接口认证
所有POST请求使用Content-Type: application/json。除health和create_token外,公开接口使用token请求头。
服务器 IP 白名单
领取token和后续公开API请求都校验第三方服务器的出口IP;不在白名单时返回HTTP 403,错误码ip_not_allowed。空白名单拒绝接入。申请时填写调用接口的服务器公网出口IP,不要填写平台代理服务器的IP。
平台HTTPS入口会覆盖并传递真实来源IP。WebDeliverServer仅在连接来自管理员明确配置的可信代理时读取其X-Real-IP;其他来源的代理头均不受信任,X-Forwarded-For和请求体中自行声明的IP不能绕过白名单。第三方无需自行设置这些请求头。
白名单变更、暂停或secret重置随运行服务的配置刷新生效,通常数秒。已有token也会重新校验IP,不能通过提前领取token绕过限制。
领取token
POST /api/v1/create_token
{
"partner": "YOUR_CODE",
"timestamp": "UNIX_SECONDS",
"nonce": "32位小写十六进制随机数",
"sign": "64位小写十六进制HMAC"
}
签名算法:HMAC-SHA256(secret, timestamp + ":" + nonce),结果编码为小写十六进制。timestamp必须是秒级Unix时间的字符串,允许前后300秒时钟误差;nonce 必须恰好为 32 位小写十六进制文本(16 个随机字节编码),用加密安全随机数生成。每次领取,包括失败后的重试,都重新生成 nonce 和 timestamp。secret 按平台展示的文本原样作为 HMAC 密钥,不做十六进制解码。
{
"success": true,
"message": "TOKEN",
"expires_in": 3600
}
错误secret、过期签名、重复nonce、未开通合作方均被拒绝。token最长有效1小时,同一合作方重复获取会复用尚未过期的token;建议缓存不超过50分钟。DBServer重启后需重新领取,secret修改或合作方暂停后旧token失效。
不要每个请求重新领取token。业务请求失败时不能无条件重放;领取新token后,只对明确允许重试的请求重试。接口错误、会话中断和钱包回调失败是不同问题。
Go签名示例
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(timestamp + ":" + nonce))
sign := hex.EncodeToString(h.Sum(nil))
HTTP示例中的域名与凭据均为占位内容。正式部署使用HTTPS;本机测试可使用HTTP。访问日志必须移除token、secret、sign、user_key及包含会话的启动链接。
请求与响应约定
API 基础地址来自「接入应用 → 对应应用 → 接入凭据」。接口地址、code、secret 必须属于同一应用。partner 参数填写该应用的 code,不是应用 ID、邮箱或固定字符串 code。secret 只用于本地计算签名,不直接发送到 API。此协议不使用 Authorization: Bearer,请使用名为 token 的请求头。
| 领取 token 参数 | 类型 | 要求 |
|---|---|---|
| partner | string | 必填,已审核应用的 code |
| timestamp | string | 必填,当前 Unix 秒的十进制文本;不是毫秒 |
| nonce | string | 必填,32 位小写十六进制随机文本 |
| sign | string | 必填,64 位小写十六进制 HMAC-SHA256 结果 |
| token 响应字段 | 类型 | 说明 |
|---|---|---|
| success | boolean | 业务结果 |
| message | string | 成功为 token;失败为错误说明 |
| expires_in | integer | 当前返回 3600;重复获取会复用 token,不代表其剩余有效期又延长一小时 |
POST /api/v1/gamelist HTTP/1.1
Host: api.example.invalid
Content-Type: application/json
token: YOUR_TOKEN
{}
先判断 HTTP 状态,再判断业务 success。游戏目录、机台目录、游戏动态的成功响应 message 是 JSON 字符串;只有这三个接口需要对 message 再做一次 JSON 解析。其他接口使用顶层字段;健康检查没有 success 字段。不要对所有 message 无条件 JSON.parse。
const response = await fetch(apiBase + "/api/v1/gamelist", {
method: "POST",
headers: { "Content-Type": "application/json", token },
body: "{}"
});
const body = await response.json();
if (!response.ok || body.success !== true) {
throw new Error(body.message || body.error || "API request failed");
}
const catalog = JSON.parse(body.message);
const games = catalog.list;
示例仅在第三方服务端执行。生产实现还须设置请求超时、处理非 JSON 响应、限制日志中的敏感信息。
错误与重试
当前协议存在两类错误外形,不保证每次都有 error 字段。HTTP 200 也可能为业务失败。
{
"success": false,
"message": "invalid user code"
}
{
"error": "ip_not_allowed",
"message": "server IP is not in the partner whitelist"
}
| HTTP 状态 | 常见反馈 | 接入方处理 |
|---|---|---|
| 200 且 success=false | message 为业务原因 | 修正参数或业务条件;不能当作成功 |
| 400 | request_body_required / invalid_json_body | 检查请求体和 JSON 编码 |
| 401 | invalid credentials | 核对接口地址、code、secret、时钟和 nonce |
| 401 | missing partner token / invalid or expired partner token | 携带有效 token;失效后重新领取 |
| 403 | ip_not_allowed | 修改的服务器出口 IP;不是玩家浏览器 IP |
| 404 | route_not_found / method_not_allowed | 检查路径和 HTTP 方法;当前方法错误也返回 404 |
| 413 | 请求体过大 | 缩小请求,不要直接重复发送 |
| 500 / 503 | 服务异常或 db_unavailable | 记录脱敏上下文,稍后有限退避重试只读请求 |
| 504 | http_timeout | 结果可能未知;先查询状态或核对业务记录 |
只读目录与状态查询可在短暂故障后有限重试。启动、退出发生超时时,不应认定服务端未执行;先检查玩家状态。业务 API 未提供通用幂等请求头;不要套用其他平台的 Idempotency-Key 规则。回调幂等与确认机制见回调与结算。