- This page is provider reference material for resolver work and VCR-backed maintenance.
- It is not the source of truth for current empack feature status or the trusted verification matrix.
- Start with
../../README.md,../usage.md, and../testing.mdfor current product behavior. - Use
../testing.mdwhen changing recorded provider fixtures.
Technical reference for the Modrinth API (Labrinth). This document covers all endpoints, parameters, response schemas, rate limits, authentication, and integration patterns.
- API Name: Labrinth
- Current Version: v2.7.0/366f528
- Base URL (Production):
https://api.modrinth.com - Base URL (Staging):
https://staging-api.modrinth.com - API Specification: OpenAPI 3.0.0
- Terms of Service: https://modrinth.com/legal/terms
- Support: support@modrinth.com | https://support.modrinth.com
Test your API client by making a GET request to the base URL:
GET https://staging-api.modrinth.com/
Expected response:
{
"about": "Welcome traveler!",
"documentation": "https://docs.modrinth.com",
"name": "modrinth-labrinth",
"version": "2.7.0"
}For production, use api.modrinth.com instead of staging-api.modrinth.com.
Modrinth supports two authentication methods: Personal Access Tokens (PATs) and OAuth2.
All tokens use the Authorization header:
Authorization: mrp_RNtLRSPmGj2pd1v1ubi52nX7TJJM9sznrmwhAuj511oe4t1jAqAQ3D6Wc8Ic
Authentication is optional for most read operations. It is required for:
- Creating data - Version creation, project creation, etc.
- Modifying data - Editing projects, updating versions, etc.
- Accessing private data - Draft projects, notifications, emails, payout data
Each authenticated request requires specific scopes. Common scopes include:
USER_READ- Read user informationUSER_READ_EMAIL- Read user email addressesUSER_WRITE- Modify user informationPROJECT_READ- Read project information (including private projects)PROJECT_WRITE- Create and modify projectsVERSION_READ- Read version information (including drafts)VERSION_WRITE- Create and modify versionsNOTIFICATION_READ- Read notificationsNOTIFICATION_WRITE- Mark notifications as readPAYOUT_READ- Read payout dataPAYOUT_WRITE- Modify payout dataREPORT_CREATE- Create reportsTEAM_READ- Read team informationTEAM_WRITE- Modify team membership
Full scope list: https://github.com/modrinth/labrinth/blob/master/src/models/pats.rs#L15
Requests with invalid or insufficient scopes return a 401 Unauthorized error.
Generate PATs from your user settings: https://modrinth.com/settings/account
Recommended: Use PATs for programmatic access and integrations.
OAuth2 allows applications to request specific scopes and act on behalf of users.
Guide: https://docs.modrinth.com/guide/oauth/
DEPRECATED: GitHub tokens currently work but will be removed in API v3. Migrate to PATs immediately.
- Rate Limit: 300 requests per minute
- Scope: Per IP address
- Authentication Impact: Rate limits are the same for authenticated and unauthenticated requests
Every response includes rate limit information:
| Header | Description |
|---|---|
X-Ratelimit-Limit |
Maximum requests per minute (currently 300) |
X-Ratelimit-Remaining |
Requests remaining in current window |
X-Ratelimit-Reset |
Seconds until rate limit window resets |
When rate limited, you'll receive:
HTTP/1.1 429 Too Many Requests
X-Ratelimit-Limit: 300
X-Ratelimit-Remaining: 0
X-Ratelimit-Reset: 42
Retry-After: 42
If your use case requires higher limits, contact Modrinth: admin@modrinth.com
CRITICAL: A uniquely-identifying User-Agent header is REQUIRED for all requests.
- Bad:
User-Agent: okhttp/4.9.3(library-only identification) - Good:
User-Agent: project_name - Better:
User-Agent: github_username/project_name/1.56.0 - Best:
User-Agent: github_username/project_name/1.56.0 (launcher.com) - Best:
User-Agent: github_username/project_name/1.56.0 (contact@launcher.com)
Generic HTTP library user agents (e.g., "okhttp", "python-requests") will likely be blocked. Include contact information so Modrinth can reach you before blocking your traffic.
Modrinth implements CORS in compliance with the W3C specification. All responses have wildcard same-origin headers, making the API completely accessible from browser-based applications.
Most resources use unique 8-digit base62 IDs:
- Projects:
AABBCCDD - Versions:
IIJJKKLL - Users:
EEFFGGHH - Teams:
MMNNOOPP - Threads:
TTUUVVWW - Reports: Similar format
- Projects: Have slugs (e.g.,
fabric-api,sodium) - Users: Have usernames (e.g.,
jellysquid)
Important: Slugs and usernames can change. For long-term storage, use base62 IDs.
Version files are identified by their SHA-1 or SHA-512 hashes.
Most endpoints accept either format:
/project/{id|slug}- AcceptsAABBCCDDormy_project/user/{id|username}- AcceptsEEFFGGHHormy_username
Modrinth uses URL-based versioning. Breaking changes increment the major version:
- API v1:
/v1/...(Deprecated) - API v2:
/v2/...(Current) - API v3:
/v3/...(Future)
When a new API version is released:
- Previous version is immediately deprecated
- No further support for older versions
- Deprecated versions remain available temporarily
- Deprecated endpoints may return warnings (e.g., "STOP USING THIS API")
- Fully deprecated APIs return
410 Gone
Important: Handle 410 Gone errors gracefully and migrate promptly.
GET /search
Search for projects (mods, modpacks, resource packs, shaders).
| Parameter | Type | Default | Description |
|---|---|---|---|
query |
string | - | Search query (e.g., "gravestones") |
facets |
string | - | Filters (see Facets section below) |
index |
string | relevance |
Sort method: relevance, downloads, follows, newest, updated |
offset |
integer | 0 |
Skip this many results (pagination) |
limit |
integer | 10 |
Number of results to return (max 100) |
Facets allow complex filtering with AND/OR logic.
project_type-mod,modpack,resourcepack,shadercategories- Includes loaders (e.g.,forge,fabric,quilt)versions- Minecraft versions (e.g.,1.19.2,1.20.1)client_side-required,optional,unsupportedserver_side-required,optional,unsupportedopen_source-true,false
title- Project titleauthor- Author usernamefollows- Number of followersproject_id- Specific project IDlicense- License identifier (e.g.,MIT,GPL-3.0)downloads- Download countcolor- Project color (RGB integer)created_timestamp- Unix timestampmodified_timestamp- Unix timestampdate_created- ISO-8601 timestampdate_modified- ISO-8601 timestamp
:or=- Equal!=- Not equal>=- Greater than or equal>- Greater than<=- Less than or equal<- Less than
{type} {operator} {value}
Examples:
categories:adventure
versions!=1.20.1
downloads<=100
OR Logic: Elements in the same array
[["versions:1.16.5", "versions:1.17.1"]]Translates to: "Projects that support 1.16.5 OR 1.17.1"
AND Logic: Separate arrays
[["versions:1.16.5"], ["project_type:modpack"]]Translates to: "Projects that support 1.16.5 AND are modpacks"
Complex Example:
[["categories:forge"],["versions:1.17.1"],["project_type:mod"],["license:mit"]]Translates to: "Forge mods for 1.17.1 with MIT license"
{
"hits": [
{
"slug": "my_project",
"title": "My Project",
"description": "A short description",
"categories": ["technology", "adventure", "fabric"],
"client_side": "required",
"server_side": "optional",
"project_type": "mod",
"downloads": 1000000,
"icon_url": "https://cdn.modrinth.com/data/AABBCCDD/icon.png",
"color": 8703084,
"thread_id": "TTUUVVWW",
"monetization_status": "monetized",
"project_id": "AABBCCDD",
"author": "my_user",
"display_categories": ["technology", "fabric"],
"versions": ["1.19", "1.19.1", "1.19.2"],
"follows": 5000,
"date_created": "2022-01-01T00:00:00Z",
"date_modified": "2023-12-01T12:00:00Z",
"latest_version": "1.19.2",
"license": "MIT",
"gallery": [
"https://cdn.modrinth.com/data/AABBCCDD/images/image1.png"
],
"featured_gallery": "https://cdn.modrinth.com/data/AABBCCDD/images/featured.png"
}
],
"offset": 0,
"limit": 10,
"total_hits": 150
}Use offset and limit for pagination:
GET /search?query=fabric&limit=20&offset=0 // Page 1
GET /search?query=fabric&limit=20&offset=20 // Page 2
GET /search?query=fabric&limit=20&offset=40 // Page 3
Limit: Maximum 100 results per request.
GET /project/{id|slug}/dependencies
Retrieves all projects and versions that the specified project depends on.
| Parameter | Type | Description |
|---|---|---|
id|slug |
string | Project ID (base62) or slug |
{
"projects": [
{
"id": "P455w0rd5L1b",
"slug": "p455w0rds-library",
"title": "p455w0rd's Library",
"description": "A library mod",
"categories": ["library"],
"client_side": "required",
"server_side": "required",
"project_type": "mod",
"downloads": 500000,
"icon_url": "https://cdn.modrinth.com/data/...",
"color": 1234567,
"versions": ["1.19", "1.20"],
"loaders": ["forge", "fabric"]
}
],
"versions": [
{
"id": "IIJJKKLL",
"project_id": "AABBCCDD",
"author_id": "EEFFGGHH",
"name": "Version 1.0.0",
"version_number": "1.0.0",
"changelog": "Initial release",
"dependencies": [
{
"version_id": "QQRRSSTT",
"project_id": "P455w0rd5L1b",
"file_name": null,
"dependency_type": "required"
}
],
"game_versions": ["1.19.2"],
"version_type": "release",
"loaders": ["fabric"],
"featured": true,
"status": "listed",
"date_published": "2023-01-01T00:00:00Z",
"downloads": 10000,
"files": [
{
"hashes": {
"sha1": "c84dd4b3580c02b79958a0590afd5783d80ef504",
"sha512": "93ecf5fe02914fb53d94aa3d28c1fb562e23985f..."
},
"url": "https://cdn.modrinth.com/data/AABBCCDD/versions/1.0.0/mymod.jar",
"filename": "mymod-1.0.0.jar",
"primary": true,
"size": 1097270,
"file_type": null
}
]
}
]
}Version dependencies have four types:
| Type | Description |
|---|---|
required |
Must be installed for the mod to work |
optional |
Enhances functionality but not required |
incompatible |
Cannot be used together |
embedded |
Bundled within the mod file |
{
"version_id": "IIJJKKLL", // Specific version (if pinned)
"project_id": "QQRRSSTT", // Project being depended on
"file_name": "sodium-fabric-mc1.19-0.4.2+build.16.jar", // External dependency filename
"dependency_type": "required" // required | optional | incompatible | embedded
}Note: Either version_id or project_id may be null. For external dependencies (non-Modrinth), file_name is provided.
Versions specify supported loaders:
fabric- Fabricforge- Forge (legacy)neoforge- NeoForgequilt- Quiltminecraft- Vanilla (for resource packs, data packs)
Loader Resolution: When resolving dependencies, filter by:
game_versions- Must match target Minecraft versionloaders- Must match target mod loaderdependency_type- Handle based on application logic
All files are served from Modrinth's CDN:
https://cdn.modrinth.com/data/{project_id}/versions/{version_number}/{filename}
Example:
https://cdn.modrinth.com/data/AANobbMI/versions/mc1.19-0.4.2/sodium-fabric-mc1.19-0.4.2+build.16.jar
All version files include cryptographic hashes for verification:
{
"hashes": {
"sha1": "c84dd4b3580c02b79958a0590afd5783d80ef504",
"sha512": "93ecf5fe02914fb53d94aa3d28c1fb562e23985f8e4d48b9038422798618761fe208a31ca9b723667a4e05de0d91a3f86bcd8d018f6a686c39550e21b198d96f"
}
}Required: SHA-1 and SHA-512 Recommendation: Verify downloads using SHA-512
{
"hashes": {
"sha1": "...",
"sha512": "..."
},
"url": "https://cdn.modrinth.com/data/AABBCCDD/versions/1.0.0/file.jar",
"filename": "mymod-1.0.0.jar",
"primary": true,
"size": 1097270,
"file_type": null
}| Field | Type | Description |
|---|---|---|
hashes |
object | SHA-1 and SHA-512 hashes |
url |
string | Direct CDN download URL |
filename |
string | File name |
primary |
boolean | Whether this is the primary file (only one per version) |
size |
integer | File size in bytes |
file_type |
string|null | File type for additional files |
required-resource-pack- Required resource packoptional-resource-pack- Optional resource packsources-jar- Source code JARdev-jar- Development JARjavadoc-jar- Javadoc JARunknown- Unknown typesignature- Digital signaturenull- Primary mod/plugin file
Modrinth supports ETags for conditional requests and efficient caching.
Response includes:
ETag: "abc123def456"
Subsequent requests should include:
If-None-Match: "abc123def456"
If content unchanged, server returns:
HTTP/1.1 304 Not Modified
If content changed, server returns:
HTTP/1.1 200 OK
ETag: "xyz789new012"
[full content]
- Cache version metadata - Store version info locally
- Use ETags - For icons, images, and project metadata
- Verify hashes - Always verify downloaded files using SHA-512
- Respect rate limits - Cache aggressively to minimize API calls
- CDN URLs are stable - Safe to cache download URLs
Most downloads: No authentication required
Private versions: Require appropriate VERSION_READ scope
CDN URLs may redirect. Follow redirects (most HTTP clients handle automatically).
GET /project/{id|slug}
Retrieve project details by ID or slug.
Parameters:
id|slug(path, required) - Project ID or slug
Scopes: None (public projects), PROJECT_READ (draft/private projects)
Response: Project object (see Schemas section)
GET /projects?ids=["AABBCCDD","EEFFGGHH"]
Retrieve multiple projects in a single request.
Parameters:
ids(query, required) - JSON array of project IDs/slugs
Response: Array of Project objects
GET /projects_random?count=10
Get random projects (for discovery features).
Parameters:
count(query, optional) - Number of projects (default: 10)
Response: Array of Project objects
POST /project
Create a new project.
Scopes: PROJECT_CREATE, PROJECT_WRITE
Request Body: CreatableProject (see Schemas)
Response: Project object
PATCH /project/{id|slug}
Modify project details.
Scopes: PROJECT_WRITE
Request Body: EditableProject (partial updates)
Response: Project object
DELETE /project/{id|slug}
Delete a project permanently.
Scopes: PROJECT_DELETE
Response: 204 No Content
PATCH /projects
Edit multiple projects simultaneously.
Scopes: PROJECT_WRITE
Request Body: PatchProjectsBody
Response: 204 No Content
GET /project/{id|slug}/icon
Retrieve project icon image.
Response: Image file (PNG, JPEG, etc.)
Headers: Supports If-None-Match for ETag caching
PATCH /project/{id|slug}/icon
Upload a new project icon.
Scopes: PROJECT_WRITE
Request Body: Multipart form data with image file
Response: 204 No Content
DELETE /project/{id|slug}/icon
Remove project icon.
Scopes: PROJECT_WRITE
Response: 204 No Content
GET /project/{id|slug}/check
Check if a project slug or ID is valid and available.
Response: 200 OK if valid, 404 Not Found if not
GET /project/{id|slug}/gallery
Get all gallery images for a project.
Response: Array of GalleryImage objects
POST /project/{id|slug}/gallery
Upload a gallery image.
Scopes: PROJECT_WRITE
Request Body: Multipart form data with:
image- Image filefeatured- Boolean (featured status)title- String (optional)description- String (optional)ordering- Integer (display order)
Response: GalleryImage object
PATCH /project/{id|slug}/gallery?url={image_url}
Modify gallery image metadata.
Scopes: PROJECT_WRITE
Request Body: Partial GalleryImage
Response: GalleryImage object
DELETE /project/{id|slug}/gallery?url={image_url}
Remove a gallery image.
Scopes: PROJECT_WRITE
Response: 204 No Content
GET /project/{id|slug}/dependencies
Get all dependencies for a project. (See Dependency Resolution section)
Response: ProjectDependencyList
POST /project/{id|slug}/follow
Follow a project to receive updates.
Scopes: USER_WRITE
Response: 204 No Content
DELETE /project/{id|slug}/follow
Unfollow a project.
Scopes: USER_WRITE
Response: 204 No Content
GET /project/{id|slug}/schedule
Get scheduled releases for a project.
Scopes: PROJECT_READ
Response: Schedule object
GET /project/{id|slug}/version
Get all versions of a project.
Parameters:
loaders(query, optional) - Filter by loaders (JSON array)game_versions(query, optional) - Filter by game versions (JSON array)featured(query, optional) - Filter featured versions (boolean)
Response: Array of Version objects
GET /version/{id}
Get version details by ID.
Parameters:
id(path, required) - Version ID (base62)
Response: Version object
GET /project/{id|slug}/version/{id|number}
Get a specific version by version number or ID.
Response: Version object
POST /version
Create a new version for a project.
Scopes: VERSION_CREATE, VERSION_WRITE
Request Body: Multipart form data with:
data(JSON) -CreatableVersionobjectfile- JAR/ZIP file(s)
Response: Version object
Validation: Files are validated for correctness (e.g., Forge mods must have mods.toml)
PATCH /version/{id}
Modify version details.
Scopes: VERSION_WRITE
Request Body: EditableVersion (partial)
Response: Version object
DELETE /version/{id}
Delete a version.
Scopes: VERSION_DELETE
Response: 204 No Content
GET /versions?ids=["IIJJKKLL","QQRRSSTT"]
Retrieve multiple versions in one request.
Parameters:
ids(query, required) - JSON array of version IDs
Response: Array of Version objects
GET /version/{id}/schedule
Get scheduled release details.
Scopes: VERSION_READ
Response: Schedule object
POST /version/{id}/file
Add additional file to an existing version.
Scopes: VERSION_WRITE
Request Body: Multipart form data with file
Response: 204 No Content
GET /version_file/{hash}?algorithm={sha1|sha512}
Retrieve version information from file hash.
Parameters:
hash(path, required) - SHA-1 or SHA-512 hashalgorithm(query, optional) - Hash algorithm (default: sha1)
Response: Version object
Use Case: Identify which version a local file belongs to
POST /version_files
Get versions for multiple file hashes.
Request Body:
{
"hashes": [
"c84dd4b3580c02b79958a0590afd5783d80ef504",
"93ecf5fe02914fb53d94aa3d28c1fb562e23985f..."
],
"algorithm": "sha1"
}Response:
{
"c84dd4b3580c02b79958a0590afd5783d80ef504": {
"id": "IIJJKKLL",
"project_id": "AABBCCDD",
...
}
}POST /version_file/{hash}/update
Find the latest compatible version for a file hash.
Parameters:
hash(path, required) - File hash
Request Body:
{
"loaders": ["fabric", "quilt"],
"game_versions": ["1.19.2", "1.19.3"]
}Response: Version object (latest matching version)
Use Case: Update checking for existing installations
POST /version_files/update
Batch update checking for multiple files.
Request Body:
{
"hashes": ["hash1", "hash2"],
"algorithm": "sha512",
"loaders": ["fabric"],
"game_versions": ["1.19.2"]
}Response: Hash-to-version map
DELETE /version_file/{hash}?algorithm={sha1|sha512}&version_id={version_id}
Delete a file from a version.
Scopes: VERSION_WRITE
Parameters:
hash(path, required)algorithm(query, optional)version_id(query, optional) - Required if hash appears in multiple versions
Response: 204 No Content
GET /user/{id|username}
Get user information.
Scopes: USER_READ (for private data), USER_READ_EMAIL (for email)
Response: User object
GET /user
Get authenticated user's information.
Scopes: USER_READ
Response: User object
PATCH /user/{id|username}
Modify user profile.
Scopes: USER_WRITE
Request Body: EditableUser (partial)
Response: User object
GET /users?ids=["EEFFGGHH","user123"]
Retrieve multiple users.
Parameters:
ids(query, required) - JSON array of user IDs/usernames
Response: Array of User objects
GET /user/{id|username}/icon
Get user avatar/icon.
Response: Image file
Headers: Supports ETag caching
PATCH /user/{id|username}/icon
Upload new user avatar.
Scopes: USER_WRITE
Request Body: Multipart form data with image
Response: 204 No Content
GET /user/{id|username}/projects
Get all projects created by a user.
Response: Array of Project objects
GET /user/{id|username}/follows
Get projects followed by a user.
Scopes: USER_READ (for private follows)
Response: Array of Project objects
GET /user/{id|username}/payouts
Get payout history and data.
Scopes: PAYOUT_READ
Response: UserPayoutHistory
GET /user/{id|username}/notifications
Get notifications for a user.
Scopes: NOTIFICATION_READ
Response: Array of Notification objects
GET /notification/{id}
Get a specific notification.
Scopes: NOTIFICATION_READ
Response: Notification object
PATCH /notification/{id}
Mark notification as read.
Scopes: NOTIFICATION_WRITE
Response: 204 No Content
PATCH /notifications
Batch mark notifications as read.
Scopes: NOTIFICATION_WRITE
Request Body:
{
"ids": ["NOTIF001", "NOTIF002"]
}Response: 204 No Content
DELETE /notification/{id}
Delete a notification.
Scopes: NOTIFICATION_WRITE
Response: 204 No Content
DELETE /notifications
Batch delete notifications.
Scopes: NOTIFICATION_WRITE
Request Body:
{
"ids": ["NOTIF001", "NOTIF002"]
}Response: 204 No Content
POST /report
Report a project, version, or user.
Scopes: REPORT_CREATE
Request Body: CreatableReport
Response: Report object
GET /report/{id}
Get report details (moderators only).
Scopes: REPORT_READ
Response: Report object
GET /reports
Get all reports (moderators only).
Scopes: REPORT_READ
Response: Array of Report objects
PATCH /report/{id}
Update report status (moderators only).
Scopes: REPORT_WRITE
Response: Report object
GET /thread/{id}
Get thread details.
Scopes: THREAD_READ
Response: Thread object
GET /threads
Get threads for authenticated user.
Scopes: THREAD_READ
Response: Array of Thread objects
POST /thread/{id}
Send a message to a thread.
Scopes: THREAD_WRITE
Request Body: ThreadMessageBody
Response: ThreadMessage object
GET /message/{id}
Get a specific message.
Scopes: THREAD_READ
Response: ThreadMessage object
DELETE /message/{id}
Delete a message.
Scopes: THREAD_WRITE
Response: 204 No Content
GET /project/{id|slug}/members
Get team members for a project.
Response: Array of TeamMember objects
GET /team/{id}/members
Get team members by team ID.
Response: Array of TeamMember objects
POST /team/{id}/members
Add a member to a team.
Scopes: TEAM_WRITE
Request Body: ModifyTeamMemberBody
Response: 204 No Content
GET /teams?ids=["MMNNOOPP","QQRRSSTT"]
Get multiple teams.
Parameters:
ids(query, required) - JSON array of team IDs
Response: Array of Team objects
POST /team/{id}/join
Accept team invitation.
Scopes: TEAM_WRITE
Response: 204 No Content
PATCH /team/{id}/members/{id|username}
Modify team member role/permissions.
Scopes: TEAM_WRITE
Request Body: ModifyTeamMemberBody
Response: 204 No Content
DELETE /team/{id}/members/{id|username}
Remove member from team.
Scopes: TEAM_WRITE
Response: 204 No Content
PATCH /team/{id}/owner
Transfer team ownership to another member.
Scopes: TEAM_WRITE
Request Body:
{
"user_id": "EEFFGGHH"
}Response: 204 No Content
Tags are metadata categories used for filtering and organization.
GET /tag/category
Get all available categories (e.g., "technology", "adventure").
Response: Array of CategoryTag objects
GET /tag/loader
Get all supported loaders (e.g., "fabric", "forge", "quilt").
Response: Array of LoaderTag objects
GET /tag/game_version
Get all Minecraft versions (e.g., "1.19.2", "1.20.1").
Response: Array of GameVersionTag objects
GET /tag/license
Get all available licenses.
Response: Array of LicenseTag objects
GET /tag/license/{id}
Get details for a specific license.
Parameters:
id(path, required) - License ID (e.g., "MIT", "GPL-3.0")
Response: License object
GET /tag/donation_platform
Get supported donation platforms.
Response: Array of DonationPlatformTag objects
GET /tag/report_type
Get available report types.
Response: Array of report types
GET /tag/project_type
Get project types (mod, modpack, resourcepack, shader).
Response: Array of project types
GET /tag/side_type
Get side types (client, server).
Response: Array of side types
GET /updates/{id|slug}/forge_updates.json
Forge-compatible update checker endpoint.
Response: ForgeUpdates object
GET /statistics
Get platform-wide statistics.
Response: Statistics object
{
"projects": 50000,
"versions": 200000,
"files": 300000,
"authors": 10000
}{
// Identity
id: string, // Base62 ID (e.g., "AABBCCDD")
slug: string, // URL slug (e.g., "fabric-api")
title: string, // Display name
description: string, // Short description
// Classification
project_type: "mod" | "modpack" | "resourcepack" | "shader",
categories: string[], // Tags (includes loaders)
additional_categories: string[], // Secondary tags
// Support
client_side: "required" | "optional" | "unsupported" | "unknown",
server_side: "required" | "optional" | "unsupported" | "unknown",
// Content
body: string, // Long description (Markdown)
body_url: null, // Deprecated, always null
// Media
icon_url: string | null, // Icon URL
color: number | null, // RGB color integer
gallery: GalleryImage[], // Gallery images
// Metadata
published: string, // ISO-8601 timestamp
updated: string, // ISO-8601 timestamp
approved: string | null, // ISO-8601 timestamp
queued: string | null, // ISO-8601 timestamp
// Status
status: "approved" | "archived" | "rejected" | "draft" | "unlisted" |
"processing" | "withheld" | "scheduled" | "private" | "unknown",
requested_status: "approved" | "archived" | "unlisted" | "private" | "draft" | null,
moderator_message: ModeratorMessage | null,
// Social
downloads: number, // Total downloads
followers: number, // Follower count
// Links
issues_url: string | null,
source_url: string | null,
wiki_url: string | null,
discord_url: string | null,
donation_urls: DonationURL[],
// License
license: {
id: string, // SPDX ID (e.g., "MIT")
name: string, // Full name
url: string | null // License URL
},
// Versions & Compatibility
versions: string[], // Version IDs
game_versions: string[], // Minecraft versions
loaders: string[], // Mod loaders
// Team
team: string, // Team ID
// Moderation
thread_id: string, // Moderation thread ID
monetization_status: "monetized" | "demonetized" | "force-demonetized"
}{
// Identity
id: string, // Base62 ID
project_id: string, // Parent project ID
author_id: string, // Author user ID
// Version Info
name: string, // Display name (e.g., "Version 1.0.0")
version_number: string, // Semantic version (e.g., "1.0.0")
changelog: string | null, // Markdown changelog
changelog_url: null, // Deprecated, always null
// Type & Status
version_type: "release" | "beta" | "alpha",
status: "listed" | "archived" | "draft" | "unlisted" | "scheduled" | "unknown",
requested_status: "listed" | "archived" | "draft" | "unlisted" | null,
// Compatibility
game_versions: string[], // Minecraft versions
loaders: string[], // Mod loaders
// Dependencies
dependencies: VersionDependency[],
// Files
files: VersionFile[],
// Metadata
date_published: string, // ISO-8601
downloads: number,
featured: boolean // Featured status
}{
version_id: string | null, // Specific version (if pinned)
project_id: string | null, // Project ID
file_name: string | null, // External dependency filename
dependency_type: "required" | "optional" | "incompatible" | "embedded"
}{
hashes: {
sha1: string, // SHA-1 hash
sha512: string // SHA-512 hash
},
url: string, // CDN download URL
filename: string, // File name
primary: boolean, // Primary file flag
size: number, // Bytes
file_type: "required-resource-pack" | "optional-resource-pack" |
"sources-jar" | "dev-jar" | "javadoc-jar" |
"unknown" | "signature" | null
}{
// Identity
id: string, // Base62 ID
username: string, // Username
name: string | null, // Display name
// Profile
email: string | null, // Email (requires USER_READ_EMAIL scope)
bio: string | null, // Biography
avatar_url: string | null, // Avatar URL
// Timestamps
created: string, // ISO-8601
// Role
role: "admin" | "moderator" | "developer" | "user",
// Badges (array of badge IDs)
badges: number
}{
url: string, // Image URL
featured: boolean, // Featured flag
title: string | null, // Image title
description: string | null, // Image description
created: string, // ISO-8601
ordering: number // Display order (lower = earlier)
}{
id: string, // Notification ID
user_id: string, // Recipient user ID
type: string, // Notification type (e.g., "project_update")
title: string, // Notification title
text: string, // Notification body
link: string, // Related URL
read: boolean, // Read status
created: string, // ISO-8601
actions: NotificationAction[] // Available actions
}{
team_id: string, // Team ID
user: User, // User object
role: string, // Role name
permissions: number, // Permission bitfield
accepted: boolean, // Invitation accepted
ordering: number // Display order
}{
hits: ProjectResult[], // Search results
offset: number, // Results skipped
limit: number, // Results returned
total_hits: number // Total matching results
}{
error: string, // Error name
description: string // Error details
}| Code | Meaning | Description |
|---|---|---|
| 200 | OK | Request successful |
| 204 | No Content | Success, no response body |
| 304 | Not Modified | Resource unchanged (ETag match) |
| 400 | Bad Request | Invalid input or malformed request |
| 401 | Unauthorized | Missing, invalid, or insufficient token scopes |
| 403 | Forbidden | Action not permitted |
| 404 | Not Found | Resource not found or no access |
| 410 | Gone | API version deprecated |
| 429 | Too Many Requests | Rate limit exceeded |
| 500 | Internal Server Error | Server error |
{
"error": "invalid_input",
"description": "Error while parsing multipart payload"
}Causes:
- Malformed JSON
- Invalid facet syntax
- Missing required fields
- Invalid enum values
{
"error": "unauthorized",
"description": "Authentication required"
}Causes:
- Missing Authorization header
- Invalid token
- Insufficient scopes
HTTP/1.1 429 Too Many Requests
X-Ratelimit-Limit: 300
X-Ratelimit-Remaining: 0
X-Ratelimit-Reset: 42
Retry-After: 42
Response:
- Wait for
X-Ratelimit-Resetseconds - Respect
Retry-Afterheader - Implement exponential backoff
{
"error": "not_found",
"description": "The requested item(s) were not found or no authorization to access the requested item(s)"
}Causes:
- Invalid ID/slug
- Private resource without proper scopes
- Deleted resource
{
"error": "gone",
"description": "This API version is deprecated and no longer available"
}Action: Migrate to current API version immediately
- Monitor headers - Track
X-Ratelimit-Remaining - Implement backoff - Exponential backoff on 429 errors
- Cache aggressively - Cache search results, project metadata
- Batch requests - Use bulk endpoints (
/projects,/versions,/version_files) - Use ETags - Reduce bandwidth with conditional requests
- Project metadata - TTL: 5-15 minutes
- Version lists - TTL: 5-15 minutes
- Search results - TTL: 5-10 minutes
- Tag lists - TTL: 1 hour (changes infrequently)
- User profiles - TTL: 10 minutes
- Icons/images - Use ETags, cache indefinitely
- On project updates: Invalidate project cache
- On version creation: Invalidate version list cache
- Use
updatedtimestamp to detect stale cache
For large result sets:
- Start small - Use
limit=20initially - Increase gradually - Up to
limit=100if needed - Track offset -
offset = page * limit - Monitor total_hits - Determine total pages
- Fetch project dependencies -
GET /project/{id}/dependencies - Filter by loader and game version
- Resolve transitive dependencies - Recursively fetch dependencies
- Handle conflicts - Check
incompatibledependencies - Respect dependency types:
required: Must installoptional: User choiceincompatible: Must not install togetherembedded: Already included
Always verify downloads:
import hashlib
def verify_file(file_path, expected_sha512):
sha512 = hashlib.sha512()
with open(file_path, 'rb') as f:
for chunk in iter(lambda: f.read(4096), b""):
sha512.update(chunk)
return sha512.hexdigest() == expected_sha512import time
def api_request_with_retry(url, max_retries=3):
for attempt in range(max_retries):
response = requests.get(url)
if response.status_code == 200:
return response.json()
elif response.status_code == 429:
# Rate limited
retry_after = int(response.headers.get('Retry-After', 60))
time.sleep(retry_after)
elif response.status_code == 404:
# Not found
return None
elif response.status_code >= 500:
# Server error, retry with backoff
time.sleep(2 ** attempt)
else:
# Other error, don't retry
raise Exception(f"API error: {response.status_code}")
raise Exception("Max retries exceeded")import requests
APP_NAME = "MyLauncher"
APP_VERSION = "1.0.0"
CONTACT = "admin@mylauncher.com"
headers = {
"User-Agent": f"{APP_NAME}/{APP_VERSION} ({CONTACT})"
}
response = requests.get("https://api.modrinth.com/v2/search", headers=headers)- Search endpoint moved:
/api/v1/mod→/v2/search - Field renames:
mod_id→project_id,mod_*→project_* - New project field:
project_type(mod, modpack, resourcepack, shader) - New search facet:
project_type - Alphabetical sort removed (was broken)
- Gallery feature added: Projects can have multiple gallery images
- File validation: Uploaded files are validated (e.g., Forge mods need
mods.toml) - Project status: New
archivedstatus (excluded from search) - Tag icons: Tags now have SVG icons and project type associations
- Dependencies redesigned: New dependency system with types
- Notification types: Notifications now have
typefield - Slugs everywhere: Endpoints accept slugs in addition to IDs
- Donation URLs enabled
body_url- Always nullchangelog_url- Always null- GitHub tokens - Will be removed in API v3
- v2.7.0/366f528 (Current) - Latest stable release
- v2.x - Active development
- v1.x - Deprecated
- GitHub token authentication will be removed
- Potential breaking changes TBD
- Changelog: https://modrinth.com/news/changelog
- Documentation: https://docs.modrinth.com
- API Spec: https://docs.modrinth.com/openapi.yaml
- Documentation: https://docs.modrinth.com
- API Specification: https://docs.modrinth.com/openapi.yaml
- Support Center: https://support.modrinth.com
- Contact: support@modrinth.com
- Terms of Service: https://modrinth.com/legal/terms
- GitHub: https://github.com/modrinth
- Labrinth (API backend): https://github.com/modrinth/labrinth
- Issue Tracker: https://github.com/modrinth/docs/issues
Multiple community-maintained client libraries are available:
- Rust:
modrinth-api- https://crates.io/crates/modrinth-api - PHP:
aternos/modrinth-api- https://github.com/aternosorg/php-modrinth-api - Python:
modrinth- https://pypi.org/project/modrinth/ - Dart:
modrinth_api- https://pub.dev/packages/modrinth_api
All libraries are generated from the OpenAPI specification.
| Method | Endpoint | Description | Auth Required |
|---|---|---|---|
| GET | / |
API information | No |
| GET | /search |
Search projects | No |
| GET | /project/{id|slug} |
Get project | Conditional |
| GET | /projects |
Get multiple projects | Conditional |
| GET | /projects_random |
Get random projects | No |
| POST | /project |
Create project | Yes |
| PATCH | /project/{id|slug} |
Edit project | Yes |
| DELETE | /project/{id|slug} |
Delete project | Yes |
| PATCH | /projects |
Bulk edit projects | Yes |
| GET | /project/{id|slug}/icon |
Get project icon | No |
| PATCH | /project/{id|slug}/icon |
Update project icon | Yes |
| DELETE | /project/{id|slug}/icon |
Delete project icon | Yes |
| GET | /project/{id|slug}/check |
Check project validity | No |
| GET | /project/{id|slug}/gallery |
Get gallery images | No |
| POST | /project/{id|slug}/gallery |
Add gallery image | Yes |
| PATCH | /project/{id|slug}/gallery |
Edit gallery image | Yes |
| DELETE | /project/{id|slug}/gallery |
Delete gallery image | Yes |
| GET | /project/{id|slug}/dependencies |
Get dependencies | No |
| POST | /project/{id|slug}/follow |
Follow project | Yes |
| DELETE | /project/{id|slug}/follow |
Unfollow project | Yes |
| GET | /project/{id|slug}/schedule |
Get project schedule | Yes |
| GET | /project/{id|slug}/version |
Get project versions | No |
| GET | /version/{id} |
Get version | Conditional |
| GET | /project/{id|slug}/version/{id|number} |
Get specific version | Conditional |
| POST | /version |
Create version | Yes |
| PATCH | /version/{id} |
Edit version | Yes |
| DELETE | /version/{id} |
Delete version | Yes |
| GET | /versions |
Get multiple versions | Conditional |
| GET | /version/{id}/schedule |
Get version schedule | Yes |
| POST | /version/{id}/file |
Add version file | Yes |
| GET | /version_file/{hash} |
Get version from hash | No |
| DELETE | /version_file/{hash} |
Delete version file | Yes |
| POST | /version_files |
Get versions from hashes | No |
| POST | /version_file/{hash}/update |
Get latest version from hash | No |
| POST | /version_files/update |
Get latest versions from hashes | No |
| GET | /user/{id|username} |
Get user | Conditional |
| PATCH | /user/{id|username} |
Edit user | Yes |
| GET | /user |
Get current user | Yes |
| GET | /users |
Get multiple users | Conditional |
| GET | /user/{id|username}/icon |
Get user icon | No |
| PATCH | /user/{id|username}/icon |
Update user icon | Yes |
| GET | /user/{id|username}/projects |
Get user's projects | No |
| GET | /user/{id|username}/follows |
Get followed projects | Conditional |
| GET | /user/{id|username}/payouts |
Get user payouts | Yes |
| GET | /user/{id|username}/notifications |
Get notifications | Yes |
| GET | /notification/{id} |
Get notification | Yes |
| PATCH | /notification/{id} |
Mark notification read | Yes |
| DELETE | /notification/{id} |
Delete notification | Yes |
| PATCH | /notifications |
Mark notifications read | Yes |
| DELETE | /notifications |
Delete notifications | Yes |
| POST | /report |
Create report | Yes |
| GET | /report/{id} |
Get report | Yes |
| PATCH | /report/{id} |
Update report | Yes |
| GET | /reports |
Get reports | Yes |
| GET | /thread/{id} |
Get thread | Yes |
| GET | /threads |
Get threads | Yes |
| POST | /thread/{id} |
Send message | Yes |
| GET | /message/{id} |
Get message | Yes |
| DELETE | /message/{id} |
Delete message | Yes |
| GET | /project/{id|slug}/members |
Get project team | No |
| GET | /team/{id}/members |
Get team members | No |
| POST | /team/{id}/members |
Add team member | Yes |
| GET | /teams |
Get multiple teams | No |
| POST | /team/{id}/join |
Join team | Yes |
| PATCH | /team/{id}/members/{id|username} |
Edit team member | Yes |
| DELETE | /team/{id}/members/{id|username} |
Remove team member | Yes |
| PATCH | /team/{id}/owner |
Transfer ownership | Yes |
| GET | /tag/category |
Get categories | No |
| GET | /tag/loader |
Get loaders | No |
| GET | /tag/game_version |
Get game versions | No |
| GET | /tag/license |
Get licenses | No |
| GET | /tag/license/{id} |
Get license details | No |
| GET | /tag/donation_platform |
Get donation platforms | No |
| GET | /tag/report_type |
Get report types | No |
| GET | /tag/project_type |
Get project types | No |
| GET | /tag/side_type |
Get side types | No |
| GET | /updates/{id|slug}/forge_updates.json |
Forge update checker | No |
| GET | /statistics |
Get statistics | No |
Total Endpoints: 55
Document Version: 1.0 Last Updated: 2025-12-21 API Version: v2.7.0/366f528 Compiled From: Official Modrinth OpenAPI specification and documentation