TWL 开放 API 参考

世界盒子(WorldBox)模组、地图、游戏版本、前置框架的只读索引与上传接口。 索引结构与 TWL 源完全一致,第三方启动器只要把 base URL 换过来就能接入。

只读接口全部公开,不需要任何凭据。只有上传和手动触发同步需要 API Key。

概览

主入口https://apigtl.tidewhisperai.xyz
备用入口https://api.twl.tidewhisperai.xyz(Cloudflare Worker 前置,行为一致)
数据规模208 模组 · 272 地图 · 5 个 PC 游戏版本 · 8 个安卓版本 · 9 个前置框架
协议HTTPS,全部返回 JSON(下载接口返回文件流或 302)
CORS完全开放,Access-Control-Allow-Origin 回显请求来源,浏览器可直接调用
更新频率索引每小时自动与上游全量同步一次,上传后立即生效
Swagger/docs · OpenAPI JSON /docs/json

快速开始

BASE URL
https://apigtl.tidewhisperai.xyz
最常见的用法
# 拿全部模组
curl https://apigtl.tidewhisperai.xyz/api/v1/mods

# 下某个模组(会 302 跳到 CDN,加 -L 跟随)
curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download

鉴权

上传与同步触发需要在请求头带 Key,两种写法等价:

x-api-key: twl_xxxxxxxxxxxxxxxxxxxx
Authorization: Bearer twl_xxxxxxxxxxxxxxxxxxxx
申请:联系「汐语启动器 TWL」作者(QQ 2143919078),说明用途即可。 每个 Key 的额度独立计算:单文件 2 GB · 每日 5 GB / 200 次。

两种数据格式

所有索引接口支持 ?format= 参数:

取值说明适用
compat默认 字段与 TWL 源 mods.json 完全一致,裸数组(versions 接口除外,它是带 versions 字段的对象)。旧启动器换地址即可用。 直接接入
rest 语义化字段名 + { data, meta } 外壳,更适合新写的客户端。 新建项目

compat 与 rest 的字段对应:

compatrest含义
modname模组 / 地图名称
introducedescription介绍
tagtags分类标签数组
previewcover封面图地址
versions[].gameversionversions[].gameVersion适配的游戏版本
versions[].modVersionversions[].version模组自身版本
versions[].downloadLinkversions[].downloadUrl下载地址

下载行为

下载接口返回 HTTP 302,Location 指向 CDN 直链,客户端跟随即可拿到文件(curl 要加 -L)。

HTTP/1.1 302 Found
location: https://www.modelscope.cn/models/bm2410/TIDE/resolve/master/mods/698fe727c7de4d7eafd7e954385b5c29.zip
content-disposition: attachment; filename*=UTF-8''698fe727c7de4d7eafd7e954385b5c29.zip
特性说明
Range 断点续传支持。跟随 302 后由 CDN 返回 206 Partial Content,多线程分片可用
CORS302 响应与 CDN 最终响应都带 Access-Control-Allow-Origin,浏览器 fetch 也能用
文件名游戏本体是 WorldBox-x.y.z.zip,模组是 <uuid>.zip(建议客户端按索引里的名称自行重命名)
为什么是 302 而不是服务端中转:中转模式会让每个下载的流量进出服务器各一遍, 多人同时下载就卡。直连 CDN 后速度是 CDN 满速,也不占服务端带宽。 Location 里是自建的公开镜像地址,不涉及任何保密内容。

模组索引

GET /api/v1/mods

返回全部模组条目。每条含多个版本(不同游戏版本各一份文件)。

查询参数

参数类型说明
format可选compat(默认)或 rest

响应(compat,节选)

[
  {
    "mod": "更多权力PowerBox",
    "introduce": "①扩展功能:查看文明单位…",
    "author": "Keymasterer, IFailedLife, don_nikon",
    "preview": "https://apigtl.tidewhisperai.xyz/api/v1/preview/698fe727c7de4d7eafd7e954385b5c29",
    "tag": ["辅助模组"],
    "updatedAt": 1765267152,
    "versions": [
      {
        "uuid": "698fe727c7de4d7eafd7e954385b5c29",
        "gameversion": "0.50.5",
        "modVersion": "1.4.0",
        "variant": null,
        "size": 419953,
        "fileName": "698fe727c7de4d7eafd7e954385b5c29.zip",
        "downloadLink": "https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download?gameversion=0.50.5"
      }
    ]
  }
]
注意 versions 的顺序:数组是上传先后顺序,不是版本高低。 想要最适配某个游戏版本的,请在客户端自己按 gameversion 筛选匹配,不要直接取 versions[0]。

响应头

头说明
X-TWL-Catalog固定为 mods
X-TWL-Total条目总数
Cache-Controlpublic, max-age=300(5 分钟)

地图索引

GET /api/v1/maps

结构与模组完全一致,只是内容换成了社区地图。

[
  {
    "mod": "莫泰拉幻想世界Morterra",
    "introduce": "",
    "author": "Mr.Calamitous",
    "preview": "https://apigtl.tidewhisperai.xyz/api/v1/preview/7e5db993f02942609434ed3bfb10c826",
    "tag": ["架空幻想", "类世界地图", "多岛屿", "多版本"],
    "versions": [
      {
        "uuid": "7e5db993f02942609434ed3bfb10c826",
        "gameversion": "0.22.x",
        "size": "14x7",
        "fileName": "7e5db993f02942609434ed3bfb10c826.zip",
        "downloadLink": "https://apigtl.tidewhisperai.xyz/api/v1/maps/7e5db993f02942609434ed3bfb10c826/download?gameversion=0.22.x"
      }
    ]
  }
]
地图的 size 是地图尺寸("14x7"),不是字节数。 真实文件大小以下载时 Content-Length 为准。

游戏版本索引(PC)

GET /api/v1/versions

PC 端 WorldBox 游戏本体清单,解压即用的 zip 包。

响应(compat)

{
  "schema": 1,
  "source": "TWL",
  "versions": [
    {
      "version": "0.51.2",
      "channel": "stable",
      "totalSize": 449049815,
      "notes": "WorldBox 0.51.2 完整游戏本体(解压即用)",
      "files": [
        {
          "path": "WorldBox-0.51.2.zip",
          "size": 449049815,
          "url": "https://apigtl.tidewhisperai.xyz/api/v1/versions/0.51.2/download"
        }
      ]
    }
  ]
}

注意这个接口返回的是对象而不是裸数组(其余索引是数组)。channel 取值 stable / archived。

游戏版本索引(安卓)

GET /api/v1/android/versions

安卓端游戏本体清单。原样返回,不做 compat/rest 转换 —— 字段是安卓特有的,转换会丢信息。

{
  "schema": 1,
  "source": "TWL",
  "platform": "android",
  "versions": [
    {
      "version": "0.51.2",
      "variant": "pure",
      "label": "纯游戏原版",
      "channel": "stable",
      "totalSize": 321686443,
      "minSdk": 23,
      "abi": ["arm64-v8a"],
      "notes": "最新稳定版…",
      "files": [
        {
          "path": "android/game/twl-wb-0.51.2-pure.apk",
          "size": 321686443,
          "sha256": "e51972fac3aef32ce4b797983a70c1bc5b6a4ea3d51a6700ef7ca7e8dee41a88",
          "url": "https://www.modelscope.cn/models/bm2410/TIDE/resolve/master/android/game/twl-wb-0.51.2-pure.apk"
        }
      ]
    }
  ]
}
这个接口的 files[].url 是 CDN 直链,不经过 API 转发,可以直接下载。 variant 区分同版本的不同构建(pure 纯原版 / menu 内置菜单版)。

前置框架索引

GET /api/v1/dependencies

模组能跑起来需要的前置:BepInEx(注入器)、NeoModLoader(模组加载器)。结构与模组索引一致,是裸数组。

[
  {
    "mod": "BepInEx 模组加载器",
    "introduce": "WorldBox 模组加载器(Doorstop 注入)…",
    "author": "BepInEx",
    "preview": "https://apigtl.tidewhisperai.xyz/api/v1/preview/bepinex-5.4.22",
    "tag": ["前置", "加载器"],
    "versions": [
      {
        "uuid": "bepinex-5.4.22",
        "gameversion": "all",
        "modVersion": "5.4.22.0",
        "size": 622553,
        "fileName": "BepInEx_x64_5.4.22.0.zip",
        "downloadLink": "https://apigtl.tidewhisperai.xyz/api/v1/mods/bepinex-5.4.22/download?gameversion=all"
      }
    ]
  }
]
前置框架的 downloadLink 指向 /api/v1/mods/<uuid>/download, 这个端点在模组里找不到时会自动回退查前置框架索引,直接用即可。

单条详情

GET /api/v1/mods/<uuid>
GET /api/v1/maps/<uuid>

按 uuid 取单条。返回结构是只含这一条的数组(compat)或 { data: [ … ] }(rest),方便复用列表解析逻辑。

# 取模组详情
curl https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29

# 不存在时
HTTP/1.1 404 Not Found
{ "error": "not_found" }

下载模组 / 地图

GET /api/v1/mods/<uuid>/download
GET /api/v1/maps/<uuid>/download

查询参数

参数类型说明
gameversion可选同一个 uuid 对应多个游戏版本时用来精确指定;不给则取第一个匹配项
# -L 跟随 302,-O -J 用服务端给的文件名保存
curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download

# 指定游戏版本
curl -L -O -J "https://apigtl.tidewhisperai.xyz/api/v1/mods/698fe727c7de4d7eafd7e954385b5c29/download?gameversion=0.50.5"

# 断点续传 / 分片
curl -L -H "Range: bytes=0-1048575" -o part1 \
  https://apigtl.tidewhisperai.xyz/api/v1/maps/7e5db993f02942609434ed3bfb10c826/download

下载游戏本体

GET /api/v1/versions/<version>/download

version 是版本号本身(如 0.51.2),不是 uuid。

curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/versions/0.51.2/download

下载前置框架

GET /api/v1/framework/<name>

name 支持模糊匹配,大小写不敏感。

写法匹配到
bepinex名称含 bepinex 的条目
NeoModLoader名称含 neomloader 的条目(取第一个版本的加载器)
BepInEx_x64_5.4.22.0.zip按文件名精确匹配
curl -L -O -J https://apigtl.tidewhisperai.xyz/api/v1/framework/bepinex
多个 NeoModLoader 版本时:这个端点按名称模糊匹配,命中哪个取决于索引顺序。 需要精确指定版本请改用 /api/v1/mods/<uuid>/download, uuid 从 /api/v1/dependencies 里取。

封面图

GET /api/v1/preview/<uuid>

返回图片本体(image/jpeg / image/webp / image/png / image/gif),带 30 天强缓存。

<img src="https://apigtl.tidewhisperai.xyz/api/v1/preview/698fe727c7de4d7eafd7e954385b5c29">

按 uuid 命名,内容不会变,可放心长期缓存。Cache-Control: public, max-age=2592000, immutable。

上传资源

POST /api/v1/upload?type=mod|map|version

需要 API Key。multipart/form-data,异步处理:立刻返回 202 + taskId,文件在后台写入仓库并推送,用任务接口查进度。

表单字段

字段必填说明
file必填要上传的文件,只接受 .zip
name必填资源名(模组名 / 地图名 / 游戏版本号)
gameversionmod/map 必填适配的游戏版本,如 0.51.x、0.50.5
modVersion可选模组自身版本号,如 1.4.0
author可选作者,默认 -
introduce可选介绍文本,支持换行
tag可选标签,多个用逗号 / 空格分隔:辅助模组,优化
preview可选封面图 URL
channelversion 专用stable(默认)/ archived
notesversion 专用版本说明

示例

curl -X POST "https://apigtl.tidewhisperai.xyz/api/v1/upload?type=mod" \
  -H "x-api-key: twl_xxxxxxxxxxxx" \
  -F "file=@我的模组.zip" \
  -F "name=我的模组" \
  -F "gameversion=0.51.x" \
  -F "modVersion=1.0.0" \
  -F "author=你的名字" \
  -F "introduce=一句话介绍" \
  -F "tag=辅助模组,优化"

响应 202

{
  "taskId": "4b32aae5-45e3-458b-9de4-162fc2239e81",
  "status": "running",
  "message": "文件已接收,正在写入源站",
  "fileName": "我的模组__0.51.x__31f51332.zip",
  "size": 502,
  "quota": {
    "bytesLeft": 5368708618,
    "countLeft": 199,
    "dailyBytes": 5368709120,
    "dailyCount": 200
  },
  "poll": "https://apigtl.tidewhisperai.xyz/api/v1/tasks/4b32aae5-45e3-458b-9de4-162fc2239e81"
}
上传成功后:文件落到仓库 → 自动追加到公开索引 → 自动推送到源站。 不需要你手动改任何 JSON。索引里立刻可见(列表缓存 5 分钟)。

上传错误

状态码error原因
400bad_typetype 不是 mod / map / version
400no_file没带 file 字段
400bad_name缺 name
400bad_gameversionmod/map 没给 gameversion
400bad_extension不是 .zip
401unauthorizedKey 缺失或无效
413too_large超过单文件上限(2 GB)
429quota_exceeded今日次数或容量用完
503upload_disabled服务端关闭了上传

任务进度

GET /api/v1/tasks/<taskId>

轮询上传进度。status 为 done 或 failed 时停止轮询。

{
  "id": "4b32aae5-45e3-458b-9de4-162fc2239e81",
  "type": "mod",
  "name": "我的模组",
  "size": 502,
  "status": "done",
  "phase": "完成",
  "progress": 100,
  "result": {
    "type": "mod",
    "name": "我的模组",
    "gameVersion": "0.51.x",
    "fileName": "我的模组__0.51.x__31f51332.zip",
    "size": 502,
    "downloadUrl": "https://apigtl.tidewhisperai.xyz/api/v1/mods/31f51332/download",
    "index": "mods"
  },
  "error": null,
  "createdAt": "2026-11-01T18:34:50.368Z",
  "updatedAt": "2026-11-01T18:34:54.344Z"
}

phase 会经历:接收文件 → 写入源站 → 推送文件 → 更新索引 → 推送索引 → 清理本地副本 → 完成。

GET /api/v1/tasks

最近的任务列表,?limit=50(1–200)。不含 Key 明文。

额度查询

GET /api/v1/quota

需要 API Key。返回当前 Key 的剩余额度。无效或不带 Key 都返回 401。

{
  "bytesLeft": 5368709120,
  "countLeft": 200,
  "dailyBytes": 5368709120,
  "dailyCount": 200,
  "note": "主账号自用",
  "limits": {
    "maxFileSize": 2147483648,
    "dailyBytes": 5368709120,
    "dailyCount": 200,
    "allowedExt": [".zip"]
  }
}

健康检查

GET/api/v1/health

适合做存活探针,也可用来显示「当前资源量」。

{
  "status": "ok",
  "version": "1.0.0",
  "uptimeSeconds": 1000,
  "uploadEnabled": true,
  "counts": { "mods": 208, "maps": 272, "versions": 5 }
}
GET/api/v1

服务自述:全部端点、鉴权方式、限额、CORS 策略。写客户端时可以先打这个接口做能力探测。

同步状态

GET/api/v1/sync

上游同步状态。服务每小时自动与上游全量同步一次(补资源 + 补封面 + 体检游戏本体实体)。

{
  "enabled": true,
  "intervalMinutes": 60,
  "running": false,
  "lastRunAt": "2026-11-01T18:53:23.511Z",
  "lastResult": {
    "ok": true,
    "full": true,
    "kinds": { "mods": { "added": 0 }, "maps": { "added": 0 }, "dependencies": { "added": 0 } },
    "elapsedMs": 10600
  },
  "consecutiveFailures": 0
}
POST/api/v1/sync/run

需要 API Key。立刻触发一轮同步,默认全量。参数:?dryRun=1 只比对不下载、?full=0 只补资源、?maxFiles=N 限制本轮文件数(默认不限)。

错误码

错误响应统一是 { "error": "...", "message": "..." } 结构。

状态码error说明
400bad_* / no_file请求参数不合法
401unauthorizedKey 缺失、格式错或无效
404not_founduuid / 版本号 / 任务 / 封面不存在
404no_download条目存在但没有可下载文件
413too_large文件超过 2 GB
429quota_exceeded额度用完
502upstream_failed回源失败(CDN 暂时不可达)
503catalog_unavailable索引文件读不到(仓库未就绪)

字段说明

资源条目(模组 / 地图 / 前置框架通用)

字段类型说明
modstring名称(同一条目的唯一键)
introducestring介绍,可能是空串,可能含换行
authorstring作者,未知时为 -
previewstring | null封面图地址(本站转发端点)
tagstring[]分类标签
updatedAtnumberUnix 时间戳(秒)
versionsobject[]版本列表,见下

版本条目(versions[])

字段类型说明
uuidstring该版本的唯一标识,下载接口用它
gameversionstring适配的游戏版本。可能是精确版(0.50.5)也可能是通配(0.51.x)或 all
modVersionstring | null模组自身版本号
variantstring | null同版本的不同构建(如安卓的 pure / menu)
sizenumber | string | null模组 / 框架是字节数;地图是尺寸字符串(如 "14x7");也可能是 null
fileNamestring仓库里的文件名,模组/地图为 <uuid>.zip
downloadLinkstring下载地址(指向本 API 的 download 端点)

游戏版本条目

字段类型说明
versionstring游戏版本号,如 0.51.2
channelstringstable / archived
totalSizenumber压缩包总字节数
notesstring版本说明
files[]object[]path 文件名、size 字节数、url 下载地址

接入示例

JavaScript(浏览器 / Node 18+)

const BASE = 'https://apigtl.tidewhisperai.xyz';

// 1. 拉模组列表,挑出适配 0.51.x 的版本
const mods = await (await fetch(`${BASE}/api/v1/mods`)).json();

const pick = mods
  .map(m => ({
    name: m.mod,
    cover: m.preview,
    hit: (m.versions || []).find(v => v.gameversion === '0.51.x'),
  }))
  .filter(x => x.hit);

console.log(`共 ${pick.length} 个模组支持 0.51.x`);

// 2. 下载(fetch 会自动跟随 302)
const res = await fetch(pick[0].hit.downloadLink);
const buf = Buffer.from(await res.arrayBuffer());
require('fs').writeFileSync('mod.zip', buf);

Python

import requests

BASE = "https://apigtl.tidewhisperai.xyz"

# 拉地图列表
maps = requests.get(f"{BASE}/api/v1/maps", timeout=30).json()

# 下载第一个地图(requests 默认跟随 302)
url = maps[0]["versions"][0]["downloadLink"]
r = requests.get(url, timeout=120)
with open("map.zip", "wb") as f:
    f.write(r.content)
print(f"下载 {len(r.content)} 字节")

# 上传(需要 Key)
files = {"file": ("mod.zip", open("mod.zip", "rb"), "application/zip")}
data = {"name": "我的模组", "gameversion": "0.51.x", "author": "我"}
r = requests.post(
    f"{BASE}/api/v1/upload?type=mod",
    headers={"x-api-key": "twl_xxxx"},
    files=files, data=data, timeout=120,
)
task_id = r.json()["taskId"]

# 轮询进度
while True:
    t = requests.get(f"{BASE}/api/v1/tasks/{task_id}", timeout=30).json()
    print(t["status"], t["phase"])
    if t["status"] in ("done", "failed"):
        break
    time.sleep(3)

游戏版本匹配建议

gameversion 有三种形态,匹配时按这个顺序判断:

  1. 精确匹配优先:0.50.5 对 0.50.5
  2. 通配其次:0.51.x 匹配任何 0.51.*
  3. all 兜底:前置框架多为 all,任何版本都能用
不要直接取 versions[0]。数组是上传顺序,旧版本可能排在前面。