# 外部 API 文档(机器人 / 第三方系统) 适用对象:QQ 官方机器人、游戏服务器插件、统计面板等**无法做网页登录**的外部系统。 - Base URL:`https://<你的域名>/api/external` - 数据格式:JSON(`Content-Type: application/json`) - 本文档所有接口**不需要用户登录**,只需要客户端凭据(见下) --- ## 一、鉴权(唯一方式:ID + Secret) 在站点后台 →「外部API」页面创建客户端,获得一对凭据: ```text Client ID: c_1a2b3c4d5e6f7a8b9c0d1e2f Secret: s_9f8e7d6c5b4a39281726354a1b2c3d4e5f60718293a4b5c6d7e8f9a0b1c2d3e ``` > ⚠️ Secret 只在创建时显示一次,请立即保存。支持创建多个客户端、单独停用/删除,互不影响。 > 无凭据 / 凭据错误 / 客户端停用 → 一律返回 `401`。 调用时在请求头携带: | 请求头 | 值 | |--------|-----| | `x-api-client-id` | 你的 Client ID | | `x-api-secret` | 你的 Secret | --- ## 二、快速开始(Python / Node 示例) ### Python ```python import requests BASE = "https://你的域名/api/external" HEADERS = { "x-api-client-id": "c_1a2b3c4d5e6f7a8b9c0d1e2f", "x-api-secret": "s_9f8e7d6c...", "Content-Type": "application/json", } # 提交举报工单 r = requests.post(f"{BASE}/tickets", headers=HEADERS, json={ "type": "report", "title": "恶意破坏", "reporter_game_name": "Steve", "reporter_game_uid": "df273bda10b94aa18db345574d5a1e1d", "target_game_name": "Alex", "target_game_uid": "SKIN_UUID_002", "reason": "刷屏+破坏他人建筑", "description": "多次警告无效", "server": "survival", # 可选: 子服别名 }) print(r.json()) # {"id": 123, "tracking_token": "..."} ``` ### Node.js ```javascript const BASE = 'https://你的域名/api/external'; const H = { 'x-api-client-id': 'c_1a2b3c...', 'x-api-secret': 's_9f8e7d6c...', 'Content-Type': 'application/json', }; // 查询工单进度(从提交到结束全程可查) const res = await fetch(`${BASE}/tickets/track?token=你的tracking_token`, { headers: H }); console.log(await res.json()); ``` --- ## 三、子服务器定位(`server` 参数) 子服可在后台「服务器管理」配置**外部别名(alias)**。所有带 `server` 的接口支持三种写法: | 写法 | 示例 | 说明 | |------|------|------| | 别名(推荐) | `survival` | 服务器改名不影响 | | 分组/子服 | `网易服务器/生存服` | URL 编码或 JSON 直接传 | | 子服名 | `生存服` | 同名时取第一个 | 查询服务器列表(含别名):`GET /api/external/servers` --- ## 四、接口清单 ### 1. 提交工单 ``` POST /api/external/tickets ``` | 字段 | 类型 | 必填 | 说明 | |------|------|------|------| | type | string | ✅ | `report` / `suggestion` / `appeal` | | title | string | ✅ | 标题 | | reporter_game_name | string | ✅ | 提交人游戏名 | | reporter_game_uid | string | ✅ | 提交人 UID / UUID | | target_game_name | string | 条件 | 被举报人游戏名(report 建议填) | | target_game_uid | string | 条件 | 被举报人 UID | | reason | string | 条件 | 举报原因(report/appeal 必填) | | description | string | 条件 | 详情(suggestion/appeal 必填) | | server | string | 否 | 子服(别名/分组/子服名) | 限制:同一提交人**待处理工单最多 5 个**。 **成功响应 201:** ```json { "id": 123, "tracking_token": "f47ac10b-58cc-4372-a567-0e02b2c3d479", "server": "生存服" } ``` > `tracking_token` 是查询进度的唯一凭证,请妥善保存。 ### 2. 查询工单进度(提交 → 处理 → 结束) ``` GET /api/external/tickets/track?token= ``` **成功响应:** ```json { "id": 123, "type": "report", "title": "恶意破坏", "status": "processing", "priority": "medium", "reporter_game_name": "Steve", "target_game_name": "Alex", "reason": "刷屏+破坏他人建筑", "assigned_to": "管理员", "claim_note": "已受理", "server_name": "生存服", "created_at": "2026-08-19T10:00:00.000Z", "updated_at": "2026-08-19T11:30:00.000Z", "responses": [ { "content": "游戏内提交...", "is_staff": 0, "created_at": "..." }, { "content": "正在核实,请耐心等待", "is_staff": 1, "created_at": "..." } ] } ``` **工单状态流转:** ``` pending(待处理) → processing(处理中) → resolved(已解决) ↘ awaiting_info(待补充信息) → processing / rejected(驳回) ↘ closed(关闭) appealed(申诉中) → resolved / rejected ``` ### 3. 工单列表 ``` GET /api/external/all-tickets?type=&status=&server=&page=&limit= ``` | 参数 | 说明 | |------|------| | type | `report` / `suggestion` / `appeal` | | status | `pending` / `processing` / `awaiting_info` / `appealing` / `resolved` / `rejected` / `closed` | | server | 子服(别名/分组/子服名) | | page / limit | 分页,limit ≤ 200,默认 page=1 limit=50 | ### 4. 工单详情(含回复与附件) ``` GET /api/external/all-tickets/:id ``` ### 5. 拉取封禁列表 ``` GET /api/external/bans?server=&status=&player=&page=&limit= ``` | 参数 | 说明 | |------|------| | server | 子服过滤(可选) | | status | `active` / `expired` / `appealed` / `lifted`(默认不滤) | | player | 按玩家名或 UID 精确匹配 | | page / limit | 分页,limit ≤ 500 | **成功响应:** ```json [ { "id": 7, "player_name": "Alex", "player_uid": "SKIN_UUID_002", "source": "netease", "reason": "使用外挂", "type": "ban", "duration": "7d", "server_name": "生存服", "status": "active", "created_at": "2026-08-19T10:00:00.000Z", "expires_at": "2026-08-26T10:00:00.000Z" } ] ``` ### 6. 新增封禁 ``` POST /api/external/bans ``` ```json { "player_name": "Alex", "player_uid": "SKIN_UUID_002", "source": "netease", "reason": "使用外挂", "type": "ban", "duration": "7d", "expires_at": "2026-08-26T10:00:00.000Z", "server": "survival", "status": "active" } ``` | 字段 | 必填 | 说明 | |------|------|------| | player_name | ✅ | 玩家名 | | type | 否 | `ban` / `mute` / `warn` / `other`,默认 `ban` | | status | 否 | `active` / `expired` / `appealed` / `lifted`,默认 `active` | | expires_at | 否 | ISO 时间或 `null`(永久) | **响应 201:** `{ "id": 7 }` ### 7. 被举报人统计 ``` GET /api/external/reported-players?server= ``` **响应:** ```json [ { "target_game_name": "Alex", "target_game_uid": "SKIN_UUID_002", "total": 5, "active": 2, "resolved": 3, "last_report": "2026-08-19T10:00:00.000Z" } ] ``` ### 8. 服务器列表(含别名) ``` GET /api/external/servers ``` **响应:** ```json [ { "group_name": "网易服务器", "server_name": "生存服", "alias": "survival" }, { "group_name": "网易服务器", "server_name": "空岛服", "alias": "skyblock" } ] ``` ### 9. 工单统计 ``` GET /api/external/stats?server= ``` **响应:** ```json { "total": 128, "byType": [ { "type": "report", "c": 95 }, { "type": "suggestion", "c": 20 } ], "byStatus": [ { "status": "pending", "c": 12 }, { "status": "resolved", "c": 100 } ] } ``` --- ## 五、错误码 | HTTP | 说明 | |------|------| | 400 | 参数错误(缺少必填字段 / 类型不正确 / 待处理工单超上限) | | 401 | 鉴权失败(凭据错误或客户端已停用) | | 404 | 工单 / 封禁不存在 | | 500 | 服务器内部错误 | 错误响应统一为 `{ "error": "描述信息" }`。 --- ## 六、鉴权失败排查 1. **401 缺少凭据**:请求必须携带 `x-api-client-id` 与 `x-api-secret` 两个请求头。 2. **401 客户端鉴权失败**:检查 Client ID / Secret 是否与创建时一致;secret 是否完整无换行空格;客户端是否被停用。 3. **客户端被停用**:后台「外部API」→ 启用。 4. **需要多个客户端**:后台可创建多个,分别用于机器人 / 插件 / 统计面板,互不影响;删除即立即失效。 --- ## 七、典型场景 ### QQ 机器人:玩家提交举报 1. 玩家在 QQ 群发送举报信息 → 机器人调 `POST /tickets` 提交(reporter 为玩家 QQ 绑定的游戏名/UID) 2. 机器人把返回的 `tracking_token` 发给玩家 → 玩家随时发「查进度」→ 机器人调 `GET /tickets/track?token=...` 3. 处理结果(状态变化)可通过工单详情轮询,或后台「通知配置」设置 Webhook 推送 ### 服务器插件:同步封禁 1. 插件启动时调 `GET /bans?status=active&server=生存服` 拉取本服封禁 2. 服内封禁新玩家时调 `POST /bans` 同步到系统 3. 定期轮询 `GET /bans?status=active` 保持同步 --- *协议版本 v1 · 服务端接口以部署版本为准*