ModReleaser/docs/modrinth/upload.md
2026-07-06 04:56:50 +08:00

15 KiB
Raw Blame History

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 TokenPATModrinth 用户设置 中生成。

创建版本需要 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_partsprimary_filefile_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 是一个 对象mapkey 是 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 目标项目的 ID8 位 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 发布渠道:releasebetaalpha "release"
loaders string[] 支持的模组加载器列表 ["fabric", "forge"]
featured boolean 是否为精选版本 false
dependencies object[] 依赖列表(可为空数组 [] 见下方 依赖结构

可选字段

字段 类型 说明 示例
primary_file string 主文件的 multipart 字段名。不提供时推断第一个文件为主文件 "main-file"
changelog string | null 更新日志Markdown/纯文本) "修复了若干 Bug"
status string 版本状态:listedarchiveddraftunlistedscheduledunknown。默认为 listed "listed"
requested_status string | null 请求的状态(用于审核流程):listedarchiveddraftunlisted "listed"
environment string 目标环境,见下方枚举 "client_and_server"
file_types object multipart 字段名 → 文件类型的映射 {"sources-file": "sources-jar"}

environment 枚举值

所有值来自 Modrinth 前端源码 environments.ts。以下按前端 UI 的层级结构排列,只有 Server-side onlyClient 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 依赖类型:requiredoptionalincompatibleembedded "required"
project_id string | null 依赖的项目 ID "P7dR8mSH" (Fabric API)
version_id string | null 依赖的具体版本 IDnull 时匹配最新版 "IIJJKKLL"
file_name string | null 依赖文件名,主要用于整合包中的外部依赖 "fabric-api-0.92.0.jar"

注意: project_idversion_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 文件哈希,包含 sha512sha1
url 文件直链
filename 文件名
primary 是否为主文件
size 文件大小(字节)
file_type 文件类型(对于 sources.jar 为 "sources-jar"

错误码

状态码 错误类型 说明
400 InvalidInputError 请求参数无效,详见响应中的 description。常见原因:缺少必填字段、game_versionsloaders 值不合法、文件格式不被接受
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. 环境与加载器的校验

loadersgame_versions 必须使用 Modrinth 认可的值。你可以通过以下端口查询可用值:

  • GET /tag/loader — 可用加载器
  • GET /tag/game_version — 可用 Minecraft 版本

10. Rate Limit

Modrinth API 有频率限制:每 IP 每分钟最多 300 个请求。响应头中包含 X-Ratelimit-LimitX-Ratelimit-RemainingX-Ratelimit-Reset


参考