15 KiB
Modrinth 新建版本 API 使用文档
本文档详细描述如何通过 Modrinth API 创建一个新版本,包括上传模组主文件(.jar)和一个 -sources.jar 附属文件。
基本信息
| 项目 | 内容 |
|---|---|
| 端点 | POST /version |
| 生产环境 | https://api.modrinth.com/v2/version |
| 测试环境 | https://staging-api.modrinth.com/v2/version |
| Content-Type | multipart/form-data |
| 认证 | 必需 — Personal Access Token (PAT) |
| 所需 Scope | VERSION_CREATE |
| 成功响应码 | 200 |
| 成功响应体 | Version 对象 |
认证
所有创建数据的请求都需要认证。你需要一个 Personal Access Token(PAT),在 Modrinth 用户设置 中生成。
创建版本需要 PAT 具有 VERSION_CREATE 权限范围。
将 Token 放在 Authorization 请求头中:
Authorization: mrp_RNtLRSPmGj2pd1v1ubi52nX7TJJM9sznrmwhAuj511oe4t1jAqAQ3D6Wc8Ic
注意: 需要在
upload.md中提供有效的 Token。
同时,Modrinth 要求提供一个可唯一标识的 User-Agent 请求头:
User-Agent: github_username/project_name/1.0.0 (contact@example.com)
请求格式
请求是一个 multipart/form-data 请求,必须包含至少两个表单字段:
data:一个 JSON 字符串,包含版本元数据(见下方 data JSON 结构)。- 一个或多个文件字段:包含要上传的
.jar、.mrpack、.zip或.litemod文件。文件字段名可自定义。
重要概念区分:multipart 字段名 vs 文件名
在 multipart 请求中,每个文件字段都有两个不同的名字:
-F "main-file=@./build/libs/my-mod-1.0.0.jar"
^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^
multipart 字段名 (field name) 文件名 (filename)
- multipart 字段名(如
main-file):在请求体中标识这一部分数据的 key,由你自定义。 - 文件名(如
my-mod-1.0.0.jar):被上传文件的原始名称。
关键规则:
file_parts、primary_file、file_types的 key 全部使用 multipart 字段名,而不是文件名。
file_parts — 声明有哪些文件
在 data JSON 的 file_parts 数组中列出所有承载文件的 multipart 字段名,并在 primary_file 中指定哪个是主文件。
{
"file_parts": ["main-file", "sources-file", "dev-file"],
"primary_file": "main-file"
}
file_types — 标记附属文件类型
file_types 是一个 对象(map),key 是 multipart 字段名(与 file_parts 中的值一致),value 是该文件的类型枚举值。用于标记 -sources.jar、-dev.jar 等附属文件。
可用的文件类型(FileTypeEnum):
| 值 | 含义 |
|---|---|
required-resource-pack |
必需资源包 |
optional-resource-pack |
可选资源包 |
sources-jar |
源代码 JAR |
dev-jar |
开发版 JAR(包含未混淆的类) |
javadoc-jar |
Javadoc JAR |
unknown |
未知类型 |
signature |
签名文件 |
标记 sources.jar 的示例:
{
"file_types": {
"sources-file": "sources-jar"
}
}
上例中
"sources-file"是 multipart 字段名,需要在file_parts中同步出现。
data JSON 结构
data 字段的值是一个 JSON 字符串,对应 CreatableVersion schema,它扩展了 BaseVersion。
顶层结构(CreateVersionBody)
{
"data": "{ ... CreatableVersion JSON ... }"
}
CreatableVersion 字段一览
必填字段
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
project_id |
string |
目标项目的 ID(8 位 base62) | "AABBCCDD" |
file_parts |
string[] |
所有承载文件的 multipart 字段名 列表 | ["main-file", "sources-file"] |
name |
string |
版本名称 | "Version 1.0.0" |
version_number |
string |
版本号,建议遵循语义化版本 | "1.0.0" |
game_versions |
string[] |
支持的 Minecraft 版本列表 | ["1.20.1", "1.20.4"] |
version_type |
string |
发布渠道:release、beta、alpha |
"release" |
loaders |
string[] |
支持的模组加载器列表 | ["fabric", "forge"] |
featured |
boolean |
是否为精选版本 | false |
dependencies |
object[] |
依赖列表(可为空数组 []) |
见下方 依赖结构 |
可选字段
| 字段 | 类型 | 说明 | 示例 |
|---|---|---|---|
primary_file |
string |
主文件的 multipart 字段名。不提供时推断第一个文件为主文件 | "main-file" |
changelog |
string | null |
更新日志(Markdown/纯文本) | "修复了若干 Bug" |
status |
string |
版本状态:listed、archived、draft、unlisted、scheduled、unknown。默认为 listed |
"listed" |
requested_status |
string | null |
请求的状态(用于审核流程):listed、archived、draft、unlisted |
"listed" |
environment |
string |
目标环境,见下方枚举 | "client_and_server" |
file_types |
object |
multipart 字段名 → 文件类型的映射 | {"sources-file": "sources-jar"} |
environment 枚举值
所有值来自 Modrinth 前端源码 environments.ts。以下按前端 UI 的层级结构排列,只有 Server-side only 和 Client and server 是带子选项的大类,其余为单选:
| 大类(前端 UI) | 子项标题 | API 值 | 说明 |
|---|---|---|---|
| (无分类,单选) | Unknown environment | unknown |
未指定或无法确定环境 |
| Client-side only | — | client_only |
所有功能在客户端运行,兼容原版服务端 |
| Server-side only | Works in singleplayer too | server_only |
所有功能在服务端运行,兼容原版客户端;也支持单人模式的内置服务端 |
| Dedicated server only | dedicated_server_only |
所有功能在服务端运行,兼容原版客户端;仅在专用服务器上工作 | |
| Client and server | Required on both | client_and_server |
客户端和服务端都必须安装 |
| Optional on client | server_only_client_optional |
主要为服务端功能,客户端安装可增强体验 | |
| Optional on server | client_only_server_optional |
主要为客户端功能,服务端安装可增强体验 | |
| Optional on both, works best when installed on both sides | client_or_server_prefers_both |
双方都装体验最佳 | |
| Optional on both, works the same if installed on either side | client_or_server |
单独安装任一侧效果相同 | |
| Singleplayer only | — | singleplayer_only |
仅在单人模式或未连接多人服务器时可用 |
依赖结构
dependencies 数组中每个依赖对象至少需要 dependency_type 字段:
| 字段 | 类型 | 必填 | 说明 | 示例 |
|---|---|---|---|---|
dependency_type |
string |
✅ | 依赖类型:required、optional、incompatible、embedded |
"required" |
project_id |
string | null |
❌ | 依赖的项目 ID | "P7dR8mSH" (Fabric API) |
version_id |
string | null |
❌ | 依赖的具体版本 ID;为 null 时匹配最新版 |
"IIJJKKLL" |
file_name |
string | null |
❌ | 依赖文件名,主要用于整合包中的外部依赖 | "fabric-api-0.92.0.jar" |
注意:
project_id和version_id二者至少提供一个,否则依赖关系无法解析。
Fabric API 依赖示例:
{
"dependency_type": "required",
"project_id": "P7dR8mSH"
}
完整请求示例
以下是一个使用 cURL 上传一个主 jar 和一个 sources.jar 的完整请求。
准备
假设:
- 项目 ID 为
AABBCCDD - 主文件为
my-mod-1.0.0.jar - 源代码文件为
my-mod-1.0.0-sources.jar
cURL 命令
curl -X POST "https://api.modrinth.com/v2/version" \
-H "Authorization: YOUR_PAT_TOKEN" \
-H "User-Agent: your_username/your_project/1.0.0" \
-F "data={
\"project_id\": \"AABBCCDD\",
\"file_parts\": [\"main-file\", \"sources-file\"],
\"primary_file\": \"main-file\",
\"name\": \"Version 1.0.0\",
\"version_number\": \"1.0.0\",
\"changelog\": \"## 更新内容\n\n- 新增了某某功能\n- 修复了某某 Bug\",
\"dependencies\": [
{
\"dependency_type\": \"required\",
\"project_id\": \"P7dR8mSH\"
}
],
\"game_versions\": [\"1.20.1\", \"1.20.4\"],
\"version_type\": \"release\",
\"loaders\": [\"fabric\"],
\"featured\": false,
\"status\": \"listed\",
\"environment\": \"client_and_server\",
\"file_types\": {
\"sources-file\": \"sources-jar\"
}
}" \
-F "main-file=@./build/libs/my-mod-1.0.0.jar" \
-F "sources-file=@./build/libs/my-mod-1.0.0-sources.jar"
Node.js (fetch) 示例
const fs = require("fs");
const TOKEN = "YOUR_PAT_TOKEN";
const PROJECT_ID = "AABBCCDD";
const form = new FormData();
const metadata = {
project_id: PROJECT_ID,
file_parts: ["main-file", "sources-file"],
primary_file: "main-file",
name: "Version 1.0.0",
version_number: "1.0.0",
changelog: "## 更新内容\n\n- 新增了某某功能\n- 修复了某某 Bug",
dependencies: [
{ dependency_type: "required", project_id: "P7dR8mSH" }
],
game_versions: ["1.20.1", "1.20.4"],
version_type: "release",
loaders: ["fabric"],
featured: false,
status: "listed",
environment: "client_and_server",
file_types: {
"sources-file": "sources-jar"
}
};
form.append("data", JSON.stringify(metadata));
form.append("main-file", new Blob([fs.readFileSync("./build/libs/my-mod-1.0.0.jar")]), "my-mod-1.0.0.jar");
form.append("sources-file", new Blob([fs.readFileSync("./build/libs/my-mod-1.0.0-sources.jar")]), "my-mod-1.0.0-sources.jar");
const response = await fetch("https://api.modrinth.com/v2/version", {
method: "POST",
headers: {
"Authorization": TOKEN,
"User-Agent": "your_username/your_project/1.0.0"
},
body: form
});
const result = await response.json();
console.log(result);
响应格式
成功创建后返回一个 Version 对象,HTTP 状态码 200。
Version 对象
{
"id": "IIJJKKLL",
"project_id": "AABBCCDD",
"author_id": "EEFFGGHH",
"name": "Version 1.0.0",
"version_number": "1.0.0",
"changelog": "## 更新内容\n\n- 新增了某某功能\n- 修复了某某 Bug",
"date_published": "2025-01-01T00:00:00Z",
"downloads": 0,
"version_type": "release",
"status": "listed",
"requested_status": null,
"game_versions": ["1.20.1", "1.20.4"],
"loaders": ["fabric"],
"featured": false,
"files": [
{
"hashes": {
"sha512": "93ecf5fe...",
"sha1": "c84dd4b3..."
},
"url": "https://cdn.modrinth.com/data/AABBCCDD/versions/1.0.0/my-mod-1.0.0.jar",
"filename": "my-mod-1.0.0.jar",
"primary": true,
"size": 1097270,
"file_type": null
},
{
"hashes": {
"sha512": "ab12cd34...",
"sha1": "ef56gh78..."
},
"url": "https://cdn.modrinth.com/data/AABBCCDD/versions/1.0.0/my-mod-1.0.0-sources.jar",
"filename": "my-mod-1.0.0-sources.jar",
"primary": false,
"size": 543210,
"file_type": "sources-jar"
}
]
}
响应中 files 数组的每个文件对象包含:
| 字段 | 说明 |
|---|---|
hashes |
文件哈希,包含 sha512 和 sha1 |
url |
文件直链 |
filename |
文件名 |
primary |
是否为主文件 |
size |
文件大小(字节) |
file_type |
文件类型(对于 sources.jar 为 "sources-jar") |
错误码
| 状态码 | 错误类型 | 说明 |
|---|---|---|
400 |
InvalidInputError |
请求参数无效,详见响应中的 description。常见原因:缺少必填字段、game_versions 或 loaders 值不合法、文件格式不被接受 |
401 |
AuthError |
Token 无效、未提供 Token,或 Token 不包含 VERSION_CREATE 权限范围 |
404 |
— | 目标项目 project_id 不存在 |
注意事项与最佳实践
1. 必须至少上传一个文件
除非版本 status 设置为 draft,否则每个新版本必须附带至少一个文件。接受的格式:.mrpack、.jar、.zip、.litemod。
2. file_parts / file_types / primary_file 全部使用 multipart 字段名
这三处字符串和实际表单字段名必须严格匹配,且它们指向的都是 multipart 字段名(如 "main-file"),不是文件名(如 "my-mod-1.0.0.jar")。否则上传的文件不会被正确关联。
3. sources.jar 的正确做法
- 给 sources 文件随意命名 multipart 字段名(如
"sources-file"),将其列入file_parts。 - 在
file_types中映射该 multipart 字段名 →"sources-jar"。 - 不要将 sources 文件设为主文件(
primary_file应指向主 jar 的 multipart 字段名)。
4. dependencies 可以是空数组
如果该模组没有依赖(极少数情况),直接传 [] 即可。但 dependencies 字段本身是必填的。
5. 文件大小限制
Modrinth 对上传文件有大小限制。如果文件过大,可能收到 400 错误。建议保持在合理范围内(一般单个文件不超过 100MB)。
6. 版本号建议
version_number 理想上应遵循语义化版本规范,便于 Modrinth 进行版本比较和用户理解。
7. 草稿版本
如果你想先上传版本而不立即公开,可将 status 设为 draft。草稿版本可以不附带文件。后续可通过 PATCH /version/{id} 修改状态为 listed 来发布。
8. 已有版本追加文件
如果版本已创建但需要追加文件,应使用 POST /version/{id}/file 端点(需要 VERSION_WRITE 权限范围)。
9. 环境与加载器的校验
loaders 和 game_versions 必须使用 Modrinth 认可的值。你可以通过以下端口查询可用值:
GET /tag/loader— 可用加载器GET /tag/game_version— 可用 Minecraft 版本
10. Rate Limit
Modrinth API 有频率限制:每 IP 每分钟最多 300 个请求。响应头中包含 X-Ratelimit-Limit、X-Ratelimit-Remaining、X-Ratelimit-Reset。