Introduction
The ModDex API gives read-only access to ModDex's Minecraft mod and modpack catalog: community reviews and ratings, project details, files, dependencies, and lookup from CurseForge and Modrinth IDs, slugs and links.
Access and rate limits
Every v2 endpoint is public. A token is optional: it raises your limits and changes nothing else (see Authenticating requests). Limits are per minute, counted per client IP (IPv6 per /64) without a token and per account with one:
| Without a token | With a token | |
|---|---|---|
| All requests | 60 | 300 |
Searches and filtered /v2/projects requests |
30 | 120 |
A search is any /v2/projects request with q or a filter. Paging, sorting and type count only against the first row. A batch lookup counts as one request.
Every response counted against your limit carries:
X-RateLimit-Limit: your limit for this kind of requestX-RateLimit-Remaining: requests left in the current windowX-RateLimit-Reset: when the window resets (Unix seconds)
If you go over, you get 429 with code: rate_limited and a Retry-After header (seconds). Wait that long before retrying. A response served from a cache carries the headers of the request that filled it, so treat them as approximate.
The API also has a shared ceiling for expensive requests (searches, heavy include blocks, dependents and modpack contents). When the whole API is busy those return 503 with code: service_unavailable and a Retry-After, whatever your own limit.
If that isn't enough, create a token and then ask for a higher limit by email at [email protected] or on the ModDex Discord. Tell us your ModDex username, what you're building and roughly how many requests a minute you expect.
Identify your client
Send X-Client: <name>/<version> with every request, for example X-Client: modrinth-reviews-extension/2.1.0. Browser extensions can't set User-Agent, so use X-Client; server-side clients may send either. It doesn't change the response. We use it to tell your traffic apart from everyone else's, and to get in touch before we block anything.
Caching
Responses are Cache-Control: public, max-age=300 (5 minutes) with an ETag. Catalog vocabulary (/v2/catalog/filters, /v2/minecraft-versions, /v2/loaders, /v2/tags) is cached for an hour. A lookup that finds nothing is cached for 60 seconds, so a page that isn't on ModDex doesn't cost a request on every view. No other error is cached.
Revalidate with If-None-Match: <etag>: an unchanged response is 304 with no body. Requests with a token are private, so shared caches skip them.
CORS
Every endpoint sends Access-Control-Allow-Origin: *, so a browser page or extension on any origin can call it. Requests don't use credentials, so don't send cookies. Authorization and X-Client are allowed request headers, and ETag, Retry-After and the X-RateLimit-* headers are readable from JavaScript.
Conventions
Errors. Every error has the same shape. Branch on code, which is stable, rather than on message:
{
"message": "The per page field must not be greater than 50.",
"code": "validation_failed",
"errors": {"per_page": ["The per page field must not be greater than 50."]},
"docs_url": "https://moddex.gg/api/docs"
}
code |
Status | Meaning |
|---|---|---|
not_found |
404 | No such project, review or route. |
validation_failed |
422 | A parameter is invalid; errors maps each parameter to its messages. |
ambiguous |
422 | A slug matches a mod and a modpack; candidates lists both. Pass type. |
conflict |
409 | A combined lookup's identifiers match different projects; matches shows which. |
page_depth_exceeded |
422 | page × per_page is over 10,000. Narrow the query with filters. |
invalid_cursor |
422 | A sync cursor was edited or belongs to the other feed. Start over without it. |
unauthenticated, token_expired |
401 | The bearer token is invalid, or has expired. |
forbidden |
403 | Your client is blocked, or the token can't be used (no read ability, or an unverified account). |
rate_limited |
429 | See Access and rate limits. |
service_unavailable |
503 | Busy, timed out, or switched off for maintenance. Retry after Retry-After. |
method_not_allowed, bad_request, server_error, api_version_retired |
405, 400, 500, 410 | As named. |
Some errors add a hint saying what to change.
Lists are comma-separated: genres=tech,magic. Values are trimmed, and empty and repeated entries are ignored. Array syntax (genres[]=) and repeated keys are a 422. A list takes at most 50 values unless its parameter says fewer, and a batch lookup takes 100 in total.
Booleans are 1, 0, true or false. Anything else is a 422. A filter described only by what it keeps, such as featured ("Only staff picks"), does nothing when 0.
include adds heavy blocks a response leaves out by default, such as include=description,ratings on a project. Each endpoint lists what it accepts; an unknown value is a 422.
Pagination. Lists are paged with page and per_page and return meta: {current_page, last_page, per_page, total} and links: {first, last, prev, next}. You can read up to 10,000 rows into a list (page × per_page). The two sync feeds use cursors instead: follow meta.next_cursor.
| Endpoint | Paging | per_page (default / max) |
|---|---|---|
/v2/projects |
page | 20 / 50 |
/v2/projects/{id}/reviews, /v2/reviews, lookup reviews |
page | 20 / 50 |
/v2/projects/{id}/files |
page | 20 / 50 (10 / 10 with include=changelog) |
/v2/projects/{id}/dependencies, /contents |
page | 20 / 100 |
/v2/projects/{id}/dependents |
page | 20 / 50 |
/v2/projects/{id}/similar |
page | 12 / 50 |
/v2/sync/projects |
cursor | 100 / 100 |
/v2/sync/reviews |
cursor | 50 / 50 |
Timestamps are ISO 8601 in UTC, such as 2026-09-30T12:00:00Z.
Ratings. A reviewer rates from 0.5 to 5 stars in steps of 0.5. Every project carries a rating block:
"rating": {"average": 4.8, "bayesian": 4.6, "count": 52, "written_count": 31}
average is the mean and bayesian the adjusted score the catalog ranks by; both are null (not 0) when nobody has rated the project. count is every rating, quick (stars only) and written; written_count is written reviews only.
Taxonomy. Genres, features, themes, loaders and environments are {slug, name} objects. The slug is what the matching /v2/projects filter takes, so a value from any response can go straight back into a filter. Minecraft versions are plain strings such as 1.21.1.
Downloads. downloads_count is exact. The min_downloads and max_downloads filters compare against the count rounded to 2 significant figures, as the website's slider does, and max_downloads is exclusive.
Output safety
Fields named *_html (descriptions, changelogs, review text) are sanitized HTML that's safe to insert into a page:
- no scripts or event handlers
- no
idorclassattributes - every link is absolute
Everything else is plain text, so escape it before you render it. That includes:
- names and review titles
content, the Markdown the reviewer wrotemodrinth.description, Markdown that allows inline HTML (renderdescription_htmlinstead)
On a page you don't control (a browser extension on Modrinth or CurseForge), put ModDex HTML inside a Shadow DOM or a sandboxed iframe, so the host page's styles and scripts can't reach it, and ours can't reach theirs.
Spoilers in content_html are wrapped in <span data-spoiler>. Hide them with CSS such as [data-spoiler]{filter:blur(4px)}.
Profanity masking
Review text is masked by default: each profane word becomes asterisks of the same length. Add unmasked=1 for the original text. Masking depends only on that parameter, not on who's asking, so responses stay cacheable.
Looking up projects
ModDex lists projects from CurseForge and Modrinth, often both under one page. Lookup finds that page from any of six keys:
| Key | Example |
|---|---|
moddex_id |
1234 |
moddex_slug |
sodium (old slugs still resolve: via_alias) |
curseforge_id |
394468 |
curseforge_slug |
sodium |
modrinth_id |
AANobbMI (8 characters, case-sensitive) |
modrinth_slug |
sodium |
Path form. /v2/lookup/{platform}/{value} works out whether the value is an ID or a slug. Add /reviews to get the project's reviews with the project summary in meta.project, in one request.
Links. /v2/lookup?url=<link> takes a pasted ModDex, CurseForge or Modrinth project link, with or without the scheme, www., a trailing slash, query string or fragment. The link's own type (/mod/ or /modpack/) is used. ModDex doesn't fetch the link.
Combined. /v2/lookup?curseforge_id=394468&modrinth_id=AANobbMI resolves each key separately. If they all match the same project, or only some match (ModDex may not have linked the two listings), you get 200 with matched saying what each key hit. Keys that match different projects are a 409 conflict.
Mod or modpack? A CurseForge slug, or a ModDex slug, can belong to a mod and a modpack at once. Without type=mod or type=modpack that's 422 ambiguous with both candidates. Links carry their type, so url= is never ambiguous.
Stale listings. When a platform slug is held by more than one project of the same type (a listing that stopped syncing keeps its old URL), the live, most recently synced one wins and the others are listed in matched.alternatives.
Merged listings. Some mods publish separate Fabric and Forge listings that ModDex merges into one page. Looking up the merged listing returns the main project with matched.via_facet: true. A /v2/projects/{id}/… URL with a merged listing's ID redirects (301) to the main project.
Batch and files. /v2/lookup/batch looks up to 100 values in one request. /v2/lookup/files finds a project from a Modrinth file's SHA1 or a CurseForge file ID, and /v2/lookup/files/batch takes up to 100.
Lookup resolves every project that has a ModDex page, including delisted ones (available: false). Listings (/v2/projects, similar projects) show only what the catalog shows.
Storing ModDex data
The API is built for showing ModDex data next to your own, not for copying the catalog. If you do store reviews or projects for longer than the HTTP cache keeps them, ModDex's terms require you to remove content within 7 days of its removal from ModDex. To do that:
- delete a project when the projects sync feed sends its tombstone (
removed: true), and delete its reviews too - at least daily, check the reviews you hold against
/v2/sync/reviews/idsand delete every one it doesn't list
The daily check is needed because a review can disappear without leaving a tombstone (it was unapproved or deleted, or its author deleted their account).
Authenticating requests
You don't need a token for v2. A token only raises your rate limits (see Access and rate limits), and the responses are the same either way. The deprecated v1 endpoints still require one.
Token lifecycle
- Create: sign in to ModDex, open Settings → API Tokens, name the token and click Create (you may be asked for your password). Copy the token right away, because it's only shown in full once.
- Use: send it in the
Authorizationheader. Responses to a request with a token carryX-ModDex-Token-Expires, the expiry time in ISO 8601. - Renew: tokens expire after 90 days. We email you 7 days and 1 day before. Create a new one and swap it in.
- Revoke: delete a token from the same page at any time.
Authorization: Bearer {YOUR_AUTH_KEY}
Tokens are read-only. Keep them on a server: if you put a token in a browser extension or a web page, anyone who installs or opens it can read the token.
Check a token with:
curl https://moddex.gg/api/user \
--header 'Authorization: Bearer {YOUR_AUTH_KEY}' \
--header 'Accept: application/json'
A 200 means it works; X-ModDex-Token-Expires says until when.
Authentication errors
If the token doesn't work, you get an error. We don't quietly downgrade the request to guest access.
v2 code |
v1 error |
Meaning |
|---|---|---|
unauthenticated |
token_invalid |
The token is unknown, malformed or revoked. |
token_expired |
token_expired |
The token is past its expiry date. |
| (none) | token_missing |
v1 only: no token was sent. |
v2 errors use the standard error shape:
{
"message": "API token has expired.",
"code": "token_expired",
"hint": "Create a new token from https://moddex.gg/settings?tab=tokens and update the Authorization header.",
"docs_url": "https://moddex.gg/api/docs"
}
v2
The current API. It's public, so you don't need an account or a token. Every endpoint is a GET under
https://moddex.gg/api/v2.
Lookup
Find a ModDex project from a ModDex, CurseForge or Modrinth ID or slug, from a
pasted link, or from a file. Lookup resolves any project with a page on ModDex, including delisted
ones (available: false). A merged loader-specific listing resolves to its project (via_facet),
and an old ModDex slug to the project that holds it now (via_alias).
Look up by explicit keys or a link.
Pass any combination of the six keys and url. Each is resolved on its own, then:
- every hit is the same project: 200, with
matchedreporting each parameter - only some keys hit: still 200, since ModDex may not have linked the two platforms
- hits on different projects: 409
conflict - no hits: 404
url accepts modrinth.com/{mod|modpack}/{id or slug}, curseforge.com/minecraft/{mc-mods|modpacks}/{slug},
curseforge.com/projects/{id} and ModDex /{mod|modpack}/{slug} links, with or without the
scheme, www., a trailing slash, query string or fragment. A CurseForge or Modrinth sub-page
(/files, /files/{id}, /versions, /version/{v}, /gallery) resolves to its project, so
the current tab's URL can be passed as it is. The link's type wins over type.
ModDex doesn't fetch the link.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/lookup?moddex_id=1234&curseforge_id=394468&modrinth_id=AANobbMI" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/lookup"
);
const params = {
"moddex_id": "1234",
"curseforge_id": "394468",
"modrinth_id": "AANobbMI",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/lookup';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'moddex_id' => '1234',
'curseforge_id' => '394468',
'modrinth_id' => 'AANobbMI',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/lookup'
params = {
'moddex_id': '1234',
'curseforge_id': '394468',
'modrinth_id': 'AANobbMI',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Found):
{
"data": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
},
"summary": "A modern rendering engine for Minecraft.",
"downloads_count": 98000000,
"last_updated_at": "2026-09-30T12:00:00Z",
"published_at": "2020-01-07T00:00:00Z",
"curseforge": {
"id": 394468,
"slug": "sodium",
"url": "https://www.curseforge.com/minecraft/mc-mods/sodium",
"downloads_count": 40000000,
"created_at": "2020-06-01T00:00:00Z",
"updated_at": "2026-09-30T12:00:00Z",
"delisted_at": null,
"screenshots": []
},
"modrinth": {
"id": "AANobbMI",
"slug": "sodium",
"url": "https://modrinth.com/mod/sodium",
"downloads_count": 58000000,
"created_at": "2020-01-07T00:00:00Z",
"updated_at": "2026-09-29T08:00:00Z",
"delisted_at": null,
"screenshots": [],
"organization": {
"id": "aBcD1234",
"slug": "caffeinemc",
"name": "CaffeineMC",
"url": "https://modrinth.com/organization/caffeinemc",
"icon_url": null
}
},
"minecraft_versions": [
"1.21.1",
"1.20.1"
],
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
},
{
"slug": "neoforge",
"name": "NeoForge"
}
],
"genres": [
{
"slug": "no-genre",
"name": "No Genre"
}
],
"features": [
{
"slug": "performance-optimization",
"name": "Performance & Optimization"
}
],
"themes": [],
"environment": [
{
"slug": "client-only",
"name": "Client Only"
}
],
"client_side": "required",
"server_side": "unsupported",
"counts": {
"dependencies": 0,
"dependents": 4200,
"modpack_dependents": 3900
},
"featured": null,
"license": {
"name": "Polyform Shield License 1.0.0",
"open_source": false,
"categories": [
"restrictive"
]
},
"latest_version": {
"curseforge": null,
"modrinth": {
"version_number": "mc1.21.1-0.6.0",
"released_at": "2026-09-29T08:00:00Z",
"minecraft_versions": [
"1.21.1"
],
"loaders": [
"fabric",
"neoforge"
],
"release_type": "release",
"url": "https://modrinth.com/mod/sodium/version/abc12345"
}
},
"authors": [
{
"name": "CaffeineMC",
"role": null,
"is_owner": false,
"is_organization": true,
"curseforge_url": null,
"modrinth_url": "https://modrinth.com/organization/caffeinemc",
"curseforge_handle": null,
"modrinth_handle": null
},
{
"name": "jellysquid3",
"role": "Owner",
"is_owner": true,
"is_organization": false,
"curseforge_url": "https://www.curseforge.com/members/jellysquid3",
"modrinth_url": "https://modrinth.com/user/jellysquid3",
"curseforge_handle": "jellysquid3",
"modrinth_handle": "jellysquid3"
}
],
"platform_urls": {
"source": "https://github.com/CaffeineMC/sodium",
"issues": "https://github.com/CaffeineMC/sodium/issues",
"wiki": null,
"discord": null
},
"sources": [
{
"project_id": 1234,
"platform": "modrinth",
"platform_id": "AANobbMI",
"label": "Modrinth",
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
}
],
"url": "https://modrinth.com/mod/sodium",
"latest_file_url": "https://modrinth.com/mod/sodium/version/abc12345",
"downloads_count": 58000000,
"available": true,
"is_canonical": true,
"last_updated_at": "2026-09-29T08:00:00Z"
}
],
"community_tags_count": 3
},
"matched": {
"curseforge_id": {
"hit": true,
"key": "curseforge_id",
"value": "394468",
"via_facet": false,
"via_alias": false,
"alternatives": []
},
"modrinth_id": {
"hit": true,
"key": "modrinth_id",
"value": "AANobbMI",
"via_facet": false,
"via_alias": false,
"alternatives": []
}
}
}
Example response (404, No match):
{
"message": "No ModDex project matches.",
"code": "not_found",
"docs_url": "https://moddex.gg/api/docs"
}
Example response (409, Different projects):
{
"message": "The identifiers match different projects.",
"code": "conflict",
"matches": {
"curseforge_id": 1234,
"modrinth_id": 5678
},
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
downloads_count
integer|null
created_at
string|null
updated_at
string|null
delisted_at
string|null
When CurseForge stopped listing it.
screenshots
object[]
url
string
title
string|null
Plain text.
description
string|null
Plain text.
description_html
string
With include=description. Sanitized HTML.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
downloads_count
integer|null
created_at
string|null
updated_at
string|null
delisted_at
string|null
When Modrinth stopped listing it.
screenshots
object[]
url
string
title
string|null
Plain text.
description
string|null
Plain text.
organization
object|null
The Modrinth organization that owns it, if any.
id
string
slug
string|null
name
string
url
string|null
icon_url
string|null
description
string|null
With include=description. Markdown source that allows inline HTML: never render it with a permissive renderer; use description_html.
description_html
string|null
With include=description. Sanitized HTML.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
followers
integer
With include=counts.
stacks
integer
With include=counts.
library_entries
integer
With include=counts.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
license
object
name
string|null
As listed; comma-separated when several.
open_source
boolean
True only when every listed license is open source.
categories
string[]
One of permissive, copyleft, public_domain, attribution, restrictive, other, none.
latest_version
object
Newest release per platform; null when there is none.
curseforge
object|null
version_number
string|null
released_at
string|null
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
release_type
string
One of release, beta, alpha.
url
string|null
The release on its platform.
modrinth
object|null
version_number
string|null
released_at
string|null
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
release_type
string
One of release, beta, alpha.
url
string|null
The release on its platform.
authors
object[]
Credits, as the project page shows them.
name
string
role
string|null
is_owner
boolean
is_organization
boolean
curseforge_url
string|null
modrinth_url
string|null
curseforge_handle
string|null
CurseForge username; what curseforge_authors matches.
modrinth_handle
string|null
Modrinth username; what modrinth_authors matches.
platform_urls
object
Each an https URL or null.
https URL or null.source
string|null
issues
string|null
wiki
string|null
discord
string|null
sources
object[]
Every listing the project is downloaded from, including merged loader-specific ones.
project_id
integer
The listing's ModDex ID: what /dependencies?source= takes.
platform
string
One of curseforge, modrinth.
platform_id
string
label
string
loaders
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
url
string|null
Null while the listing is delisted.
latest_file_url
string|null
downloads_count
integer
available
boolean
is_canonical
boolean
This is the project's own row, not a merged loader-specific listing.
last_updated_at
string|null
community_tags_count
integer
Tags in /community-tags active: voted community tags plus the project's own genres, themes and features.
ratings
object
With include=ratings.
include=ratings.
histogram
object[]
Ten steps, 0.5 to 5.
rating
number
0.5 to 5.
count
integer
categories
object
gameplay
object[]
rating
number
0.5 to 5.
count
integer
performance
object[]
rating
number
0.5 to 5.
count
integer
aesthetics
object[]
rating
number
0.5 to 5.
count
integer
ranks
object|null
Null when unrated.
global
integer
by_type
integer
Among projects of the same type.
avg_completion_hours
number|null
With include=completion. Modpacks only; null for mods and when nobody has reported it.
matched
object
One entry per lookup parameter sent, keyed by parameter name.
*
object
hit
boolean
Whether this parameter matched the project.
key
string|null
The identifier tried (for url, the one the link mapped to). Null for a link ModDex doesn't cover. One of moddex_id, moddex_slug, curseforge_id, curseforge_slug, modrinth_id, modrinth_slug.
value
string
The value looked up (for url, the ID or slug taken from the link).
via_facet
boolean
via_alias
boolean
alternatives
integer[]
Batch lookup.
Up to 100 values in total, comma-separated, in one request (it counts as one request against
the rate limit). modrinth, curseforge and moddex values are auto-detected as on the path
lookup. urls takes links: URL-encode each one before joining them with commas. A urls value
that decodes to several links (the commas between them were encoded too) is a 422. type
applies to every value except a link that carries its own type.
Each value maps to one of:
- a project summary
null: not on ModDex, or not a valid value{ambiguous: true, candidates: [...]}: a slug shared by a mod and a modpack, with notypegiven
A bad value doesn't fail the rest of the batch. Output is keyed by each value as sent (trimmed); sort your values so identical batches share a cache entry.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/lookup/batch?modrinth=AANobbMI%2Clithium&curseforge=394468" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/lookup/batch"
);
const params = {
"modrinth": "AANobbMI,lithium",
"curseforge": "394468",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/lookup/batch';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'modrinth' => 'AANobbMI,lithium',
'curseforge' => '394468',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/lookup/batch'
params = {
'modrinth': 'AANobbMI,lithium',
'curseforge': '394468',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Mixed):
{
"data": {
"modrinth": {
"AANobbMI": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
}
},
"lithium": null
},
"curseforge": {},
"moddex": {},
"urls": {}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
modrinth
object
Keyed by each modrinth value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
modrinth value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
*
object
ambiguous
boolean
candidates
object[]
Every project the value could mean. The project summary: id, name, slug, type, logo_url, available, rating and links.
curseforge
object
Keyed by each curseforge value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
curseforge value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
*
object
ambiguous
boolean
candidates
object[]
Every project the value could mean. The project summary: id, name, slug, type, logo_url, available, rating and links.
moddex
object
Keyed by each moddex value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
moddex value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
*
object
ambiguous
boolean
candidates
object[]
Every project the value could mean. The project summary: id, name, slug, type, logo_url, available, rating and links.
urls
object
Keyed by each urls value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
urls value as sent: a project summary, {ambiguous, candidates}, or null (not on ModDex, or not a valid value).
*
object
ambiguous
boolean
candidates
object[]
Every project the value could mean. The project summary: id, name, slug, type, logo_url, available, rating and links.
Look up a file.
Map a file (from a mods folder or a crash log) to its ModDex project. Modrinth files are found by SHA1, CurseForge files by file ID. CurseForge fingerprints aren't stored, so a CurseForge jar can't be found by its content.
Pass exactly one of sha1 or curseforge_file_id. A Modrinth file returns its version's row:
the version's primary file at the top level and the rest in secondary_files. secondary is
true when the SHA1 you sent is one of those secondary files.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/lookup/files?curseforge_file_id=5432101" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/lookup/files"
);
const params = {
"curseforge_file_id": "5432101",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/lookup/files';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'curseforge_file_id' => '5432101',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/lookup/files'
params = {
'curseforge_file_id': '5432101',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Found):
{
"data": {
"file": {
"id": 9,
"platform": "curseforge",
"curseforge_file_id": "5432101",
"modrinth_version_id": null,
"sha1": null,
"display_name": "sodium-1.21.1-0.6.0.jar",
"version_number": "0.6.0",
"release_type": "release",
"minecraft_versions": [
"1.21.1"
],
"loaders": [
"fabric"
],
"file_name": "sodium-1.21.1-0.6.0.jar",
"file_size": 1048576,
"downloads_count": 1200,
"released_at": "2026-09-01T12:00:00Z",
"is_featured": false,
"download_url": "https://www.curseforge.com/minecraft/mc-mods/sodium/download/5432101",
"platform_url": "https://www.curseforge.com/minecraft/mc-mods/sodium/files/5432101",
"server_pack": null,
"secondary_files": []
},
"project": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
}
},
"secondary": false
}
}
Example response (404, No match):
{
"message": "No ModDex project has this file.",
"code": "not_found",
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
file
object
The release row.
id
integer
ModDex file ID.
platform
string
One of curseforge, modrinth.
curseforge_file_id
string|null
CurseForge rows only.
modrinth_version_id
string|null
Modrinth rows only.
sha1
string|null
Modrinth rows only: the primary file's SHA1.
display_name
string
version_number
string|null
release_type
string
One of release, beta, alpha.
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
file_name
string|null
file_size
integer|null
Bytes.
downloads_count
integer
The file's downloads (the version's, for Modrinth rows).
released_at
string|null
is_featured
boolean
Modrinth's featured flag.
download_url
string|null
The platform's download page. Null while the publishing listing is delisted.
platform_url
string|null
The release's page on its platform. Null while the listing is delisted.
server_pack
object|null
CurseForge modpacks: the server pack.
curseforge_file_id
string
file_name
string|null
file_size
integer|null
download_url
string|null
secondary_files
object[]
Modrinth: the version's other files.
sha1
string
file_name
string|null
file_size
integer|null
download_url
string|null
changelog_html
string|null
With include=changelog. Sanitized HTML.
changelog_truncated
boolean
With include=changelog. True when the changelog was cut at 100 KB.
project
object
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
secondary
boolean
The looked-up SHA1 is one of this version's secondary files.
Batch file lookup.
Up to 100 values in total across sha1 and curseforge_file_id, comma-separated. Each maps
to {file, project, secondary} or null (unknown, hidden or malformed). Output is keyed by
each value as sent.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/lookup/files/batch?curseforge_file_id=5432101%2C5432102" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/lookup/files/batch"
);
const params = {
"curseforge_file_id": "5432101,5432102",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/lookup/files/batch';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'curseforge_file_id' => '5432101,5432102',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/lookup/files/batch'
params = {
'curseforge_file_id': '5432101,5432102',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Mixed):
{
"data": {
"sha1": {},
"curseforge_file_id": {
"5432101": null
}
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
sha1
object
Keyed by SHA1 as sent; null when unknown.
*
object
file
object
The release row.
id
integer
ModDex file ID.
platform
string
One of curseforge, modrinth.
curseforge_file_id
string|null
CurseForge rows only.
modrinth_version_id
string|null
Modrinth rows only.
sha1
string|null
Modrinth rows only: the primary file's SHA1.
display_name
string
version_number
string|null
release_type
string
One of release, beta, alpha.
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
file_name
string|null
file_size
integer|null
Bytes.
downloads_count
integer
The file's downloads (the version's, for Modrinth rows).
released_at
string|null
is_featured
boolean
Modrinth's featured flag.
download_url
string|null
The platform's download page. Null while the publishing listing is delisted.
platform_url
string|null
The release's page on its platform. Null while the listing is delisted.
server_pack
object|null
CurseForge modpacks: the server pack.
curseforge_file_id
string
file_name
string|null
file_size
integer|null
download_url
string|null
secondary_files
object[]
Modrinth: the version's other files.
sha1
string
file_name
string|null
file_size
integer|null
download_url
string|null
changelog_html
string|null
With include=changelog. Sanitized HTML.
changelog_truncated
boolean
With include=changelog. True when the changelog was cut at 100 KB.
project
object
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
secondary
boolean
The looked-up SHA1 is one of this version's secondary files.
curseforge_file_id
object
Keyed by file ID as sent; null when unknown.
*
object
file
object
The release row.
id
integer
ModDex file ID.
platform
string
One of curseforge, modrinth.
curseforge_file_id
string|null
CurseForge rows only.
modrinth_version_id
string|null
Modrinth rows only.
sha1
string|null
Modrinth rows only: the primary file's SHA1.
display_name
string
version_number
string|null
release_type
string
One of release, beta, alpha.
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
file_name
string|null
file_size
integer|null
Bytes.
downloads_count
integer
The file's downloads (the version's, for Modrinth rows).
released_at
string|null
is_featured
boolean
Modrinth's featured flag.
download_url
string|null
The platform's download page. Null while the publishing listing is delisted.
platform_url
string|null
The release's page on its platform. Null while the listing is delisted.
server_pack
object|null
CurseForge modpacks: the server pack.
curseforge_file_id
string
file_name
string|null
file_size
integer|null
download_url
string|null
secondary_files
object[]
Modrinth: the version's other files.
sha1
string
file_name
string|null
file_size
integer|null
download_url
string|null
changelog_html
string|null
With include=changelog. Sanitized HTML.
changelog_truncated
boolean
With include=changelog. True when the changelog was cut at 100 KB.
project
object
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
secondary
boolean
The looked-up SHA1 is one of this version's secondary files.
Look up by platform and value, with the project's reviews.
The project's review list (same parameters and response as /v2/projects/{id}/reviews), with
the project in meta.project (summary shape) and the match in meta.matched (as on the path
lookup). One request gives a browser extension the rating, the links and the reviews.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/lookup/modrinth/sodium/reviews" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/lookup/modrinth/sodium/reviews"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/lookup/modrinth/sodium/reviews';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/lookup/modrinth/sodium/reviews'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Found):
{
"data": [],
"links": {
"first": "https://moddex.gg/api/v2/lookup/modrinth/sodium/reviews?page=1",
"last": "https://moddex.gg/api/v2/lookup/modrinth/sodium/reviews?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 0,
"project": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": null,
"bayesian": null,
"count": 0,
"written_count": 0
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
}
},
"matched": {
"key": "modrinth_slug",
"value": "sodium",
"via_facet": false,
"via_alias": false,
"alternatives": []
}
}
}
Example response (404, No match):
{
"message": "No ModDex project matches.",
"code": "not_found",
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
id
integer
is_quick_rating
boolean
Stars only: no title or text.
title
string|null
Plain text.
content
string|null
The Markdown the author wrote. Plain text: escape it.
content_html
string|null
Sanitized HTML. Spoilers are wrapped in <span data-spoiler>.
rating
number
0.5 to 5 in steps of 0.5.
categories
object
Each 0.5 to 5, or null when not rated.
gameplay
number|null
performance
number|null
aesthetics
number|null
minecraft_version
string|null
As the reviewer entered it; may list several, comma-separated.
playtime_hours
integer|null
completion_hours
integer|null
play_status
string|null
One of playing, played, completed, plan_to_play, on_hold, dropped.
pack_version
string|null
The modpack version reviewed.
helpful_votes
integer
unhelpful_votes
integer
is_verified_developer
boolean
Written by one of the project's verified developers.
public_moderator_note
string|null
Plain text.
images
object[]
url
string
caption
string|null
Plain text.
developer_response
object|null
The developer's reply, if any.
content
string
Plain text.
responded_at
string|null
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
project
object
The project summary: id, name, slug, type, logo_url, available, rating and links.
url
string|null
The review's page on ModDex.
created_at
string|null
edited_at
string|null
updated_at
string|null
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
project
object
The project.
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
matched
object
How the value matched.
key
string
Which identifier matched. One of moddex_id, moddex_slug, curseforge_id, curseforge_slug, modrinth_id, modrinth_slug.
value
string
The value as sent.
via_facet
boolean
The identifier belongs to a loader-specific listing merged into this project.
via_alias
boolean
The ModDex slug is one this project used to have.
alternatives
integer[]
Other project IDs that share the slug and type (stale listings).
Look up by platform and value.
The value is auto-detected: on moddex and curseforge an all-digit value is tried as an ID
first, then as a slug; on modrinth an 8-character value is tried as a project ID (exact,
case-sensitive) first, then as a slug. An ID hit beats a slug hit. CurseForge and Modrinth
slugs are matched case-insensitively; a ModDex slug is matched exactly first (some carry a
case-sensitive suffix), then lowercased.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/lookup/modrinth/sodium?type=mod" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/lookup/modrinth/sodium"
);
const params = {
"type": "mod",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/lookup/modrinth/sodium';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'type' => 'mod',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/lookup/modrinth/sodium'
params = {
'type': 'mod',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Found):
{
"data": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
},
"summary": "A modern rendering engine for Minecraft.",
"downloads_count": 98000000,
"last_updated_at": "2026-09-30T12:00:00Z",
"published_at": "2020-01-07T00:00:00Z",
"curseforge": {
"id": 394468,
"slug": "sodium",
"url": "https://www.curseforge.com/minecraft/mc-mods/sodium",
"downloads_count": 40000000,
"created_at": "2020-06-01T00:00:00Z",
"updated_at": "2026-09-30T12:00:00Z",
"delisted_at": null,
"screenshots": []
},
"modrinth": {
"id": "AANobbMI",
"slug": "sodium",
"url": "https://modrinth.com/mod/sodium",
"downloads_count": 58000000,
"created_at": "2020-01-07T00:00:00Z",
"updated_at": "2026-09-29T08:00:00Z",
"delisted_at": null,
"screenshots": [],
"organization": {
"id": "aBcD1234",
"slug": "caffeinemc",
"name": "CaffeineMC",
"url": "https://modrinth.com/organization/caffeinemc",
"icon_url": null
}
},
"minecraft_versions": [
"1.21.1",
"1.20.1"
],
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
},
{
"slug": "neoforge",
"name": "NeoForge"
}
],
"genres": [
{
"slug": "no-genre",
"name": "No Genre"
}
],
"features": [
{
"slug": "performance-optimization",
"name": "Performance & Optimization"
}
],
"themes": [],
"environment": [
{
"slug": "client-only",
"name": "Client Only"
}
],
"client_side": "required",
"server_side": "unsupported",
"counts": {
"dependencies": 0,
"dependents": 4200,
"modpack_dependents": 3900
},
"featured": null,
"license": {
"name": "Polyform Shield License 1.0.0",
"open_source": false,
"categories": [
"restrictive"
]
},
"latest_version": {
"curseforge": null,
"modrinth": {
"version_number": "mc1.21.1-0.6.0",
"released_at": "2026-09-29T08:00:00Z",
"minecraft_versions": [
"1.21.1"
],
"loaders": [
"fabric",
"neoforge"
],
"release_type": "release",
"url": "https://modrinth.com/mod/sodium/version/abc12345"
}
},
"authors": [
{
"name": "CaffeineMC",
"role": null,
"is_owner": false,
"is_organization": true,
"curseforge_url": null,
"modrinth_url": "https://modrinth.com/organization/caffeinemc",
"curseforge_handle": null,
"modrinth_handle": null
},
{
"name": "jellysquid3",
"role": "Owner",
"is_owner": true,
"is_organization": false,
"curseforge_url": "https://www.curseforge.com/members/jellysquid3",
"modrinth_url": "https://modrinth.com/user/jellysquid3",
"curseforge_handle": "jellysquid3",
"modrinth_handle": "jellysquid3"
}
],
"platform_urls": {
"source": "https://github.com/CaffeineMC/sodium",
"issues": "https://github.com/CaffeineMC/sodium/issues",
"wiki": null,
"discord": null
},
"sources": [
{
"project_id": 1234,
"platform": "modrinth",
"platform_id": "AANobbMI",
"label": "Modrinth",
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
}
],
"url": "https://modrinth.com/mod/sodium",
"latest_file_url": "https://modrinth.com/mod/sodium/version/abc12345",
"downloads_count": 58000000,
"available": true,
"is_canonical": true,
"last_updated_at": "2026-09-29T08:00:00Z"
}
],
"community_tags_count": 3
},
"matched": {
"key": "modrinth_slug",
"value": "sodium",
"via_facet": false,
"via_alias": false,
"alternatives": []
}
}
Example response (404, No match):
{
"message": "No ModDex project matches.",
"code": "not_found",
"docs_url": "https://moddex.gg/api/docs"
}
Example response (422, Shared by a mod and a modpack):
{
"message": "More than one project matches.",
"code": "ambiguous",
"hint": "Pass type=mod or type=modpack, or look up by a URL that carries the type.",
"candidates": [],
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
downloads_count
integer|null
created_at
string|null
updated_at
string|null
delisted_at
string|null
When CurseForge stopped listing it.
screenshots
object[]
url
string
title
string|null
Plain text.
description
string|null
Plain text.
description_html
string
With include=description. Sanitized HTML.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
downloads_count
integer|null
created_at
string|null
updated_at
string|null
delisted_at
string|null
When Modrinth stopped listing it.
screenshots
object[]
url
string
title
string|null
Plain text.
description
string|null
Plain text.
organization
object|null
The Modrinth organization that owns it, if any.
id
string
slug
string|null
name
string
url
string|null
icon_url
string|null
description
string|null
With include=description. Markdown source that allows inline HTML: never render it with a permissive renderer; use description_html.
description_html
string|null
With include=description. Sanitized HTML.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
followers
integer
With include=counts.
stacks
integer
With include=counts.
library_entries
integer
With include=counts.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
license
object
name
string|null
As listed; comma-separated when several.
open_source
boolean
True only when every listed license is open source.
categories
string[]
One of permissive, copyleft, public_domain, attribution, restrictive, other, none.
latest_version
object
Newest release per platform; null when there is none.
curseforge
object|null
version_number
string|null
released_at
string|null
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
release_type
string
One of release, beta, alpha.
url
string|null
The release on its platform.
modrinth
object|null
version_number
string|null
released_at
string|null
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
release_type
string
One of release, beta, alpha.
url
string|null
The release on its platform.
authors
object[]
Credits, as the project page shows them.
name
string
role
string|null
is_owner
boolean
is_organization
boolean
curseforge_url
string|null
modrinth_url
string|null
curseforge_handle
string|null
CurseForge username; what curseforge_authors matches.
modrinth_handle
string|null
Modrinth username; what modrinth_authors matches.
platform_urls
object
Each an https URL or null.
https URL or null.source
string|null
issues
string|null
wiki
string|null
discord
string|null
sources
object[]
Every listing the project is downloaded from, including merged loader-specific ones.
project_id
integer
The listing's ModDex ID: what /dependencies?source= takes.
platform
string
One of curseforge, modrinth.
platform_id
string
label
string
loaders
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
url
string|null
Null while the listing is delisted.
latest_file_url
string|null
downloads_count
integer
available
boolean
is_canonical
boolean
This is the project's own row, not a merged loader-specific listing.
last_updated_at
string|null
community_tags_count
integer
Tags in /community-tags active: voted community tags plus the project's own genres, themes and features.
ratings
object
With include=ratings.
include=ratings.
histogram
object[]
Ten steps, 0.5 to 5.
rating
number
0.5 to 5.
count
integer
categories
object
gameplay
object[]
rating
number
0.5 to 5.
count
integer
performance
object[]
rating
number
0.5 to 5.
count
integer
aesthetics
object[]
rating
number
0.5 to 5.
count
integer
ranks
object|null
Null when unrated.
global
integer
by_type
integer
Among projects of the same type.
avg_completion_hours
number|null
With include=completion. Modpacks only; null for mods and when nobody has reported it.
matched
object
How the value matched.
key
string
Which identifier matched. One of moddex_id, moddex_slug, curseforge_id, curseforge_slug, modrinth_id, modrinth_slug.
value
string
The value as sent.
via_facet
boolean
The identifier belongs to a loader-specific listing merged into this project.
via_alias
boolean
The ModDex slug is one this project used to have.
alternatives
integer[]
Other project IDs that share the slug and type (stale listings).
Projects
A project by its ModDex ID. Any project with a page on ModDex resolves, including delisted ones
(available: false). A loader-specific listing that was merged into another project redirects
(301) to that project.
List and search projects.
The catalog, as a guest sees it on the website: listed projects only (no delisted projects
and no merged loader-specific listings), with every filter and sort the catalog page has.
/v2/catalog/filters lists every parameter and its valid values; an unknown parameter or
value is a 422.
Most list filters have an _exclude twin (genres_exclude=); genres, features, themes,
minecraft_versions (mc_mode) and uses_mods take an any/all mode. Searches (q) and
filtered requests count against a separate, lower rate limit; paging, sorting and type don't.
A search returns at most 1,000 matches and needs the search engine: while it is down, q
gets a 503 and listing without q still works. Pages deeper than page × per_page = 10,000
are a 422.
A page can hold fewer than per_page projects while the search index catches up with a
project that was just removed; meta.total still counts it until then.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects?type=mod&loaders=fabric&minecraft_versions=1.21.1&sort=downloads_count" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects"
);
const params = {
"type": "mod",
"loaders": "fabric",
"minecraft_versions": "1.21.1",
"sort": "downloads_count",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'type' => 'mod',
'loaders' => 'fabric',
'minecraft_versions' => '1.21.1',
'sort' => 'downloads_count',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects'
params = {
'type': 'mod',
'loaders': 'fabric',
'minecraft_versions': '1.21.1',
'sort': 'downloads_count',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Success):
{
"data": [
{
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
},
"summary": "A modern rendering engine for Minecraft.",
"downloads_count": 98000000,
"last_updated_at": "2026-09-30T12:00:00Z",
"published_at": "2020-01-07T00:00:00Z",
"curseforge": {
"id": 394468,
"slug": "sodium",
"url": "https://www.curseforge.com/minecraft/mc-mods/sodium"
},
"modrinth": {
"id": "AANobbMI",
"slug": "sodium",
"url": "https://modrinth.com/mod/sodium"
},
"minecraft_versions": [
"1.21.1",
"1.20.1"
],
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
}
],
"genres": [
{
"slug": "no-genre",
"name": "No Genre"
}
],
"features": [
{
"slug": "performance-optimization",
"name": "Performance & Optimization"
}
],
"themes": [],
"environment": [
{
"slug": "client-only",
"name": "Client Only"
}
],
"client_side": "required",
"server_side": "unsupported",
"counts": {
"dependencies": 0,
"dependents": 4200,
"modpack_dependents": 3900
},
"featured": null
}
],
"links": {
"first": "https://moddex.gg/api/v2/projects?page=1",
"last": "https://moddex.gg/api/v2/projects?page=200",
"prev": null,
"next": "https://moddex.gg/api/v2/projects?page=2"
},
"meta": {
"current_page": 1,
"last_page": 200,
"per_page": 20,
"total": 4000
}
}
Example response (422, Unknown value):
{
"message": "Unknown value(s): techh. Valid values: adventureexploration, base-defense, expert, kitchen-sink, magic, no-genre, roguelike, rpg, rts, run-and-gun, shooter, skyblock, stoneblock, survival, tech, vanilla, village-farm-life.",
"code": "validation_failed",
"errors": {
"genres": [
"Unknown value(s): techh. Valid values: adventureexploration, base-defense, expert, kitchen-sink, magic, no-genre, roguelike, rpg, rts, run-and-gun, shooter, skyblock, stoneblock, survival, tech, vanilla, village-farm-life."
]
},
"docs_url": "https://moddex.gg/api/docs"
}
Example response (503, Search unavailable):
{
"message": "Service temporarily unavailable. Retry after the Retry-After interval.",
"code": "service_unavailable",
"hint": "Search is temporarily unavailable. Listing and filtering without q still work.",
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
Projects in the list shape.
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
Show a project.
The full project. Heavy blocks are left out unless you ask for them with include:
description: the CurseForge and Modrinth descriptionsratings: rating histograms and rankcounts: followers, stacks and library entriescompletion: average hours to complete a modpack
Only fields named *_html are HTML; escape everything else (see Output safety).
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects/1234" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects/1234"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects/1234';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects/1234'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Found):
{
"data": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
},
"summary": "A modern rendering engine for Minecraft.",
"downloads_count": 98000000,
"last_updated_at": "2026-09-30T12:00:00Z",
"published_at": "2020-01-07T00:00:00Z",
"curseforge": {
"id": 394468,
"slug": "sodium",
"url": "https://www.curseforge.com/minecraft/mc-mods/sodium",
"downloads_count": 40000000,
"created_at": "2020-06-01T00:00:00Z",
"updated_at": "2026-09-30T12:00:00Z",
"delisted_at": null,
"screenshots": []
},
"modrinth": {
"id": "AANobbMI",
"slug": "sodium",
"url": "https://modrinth.com/mod/sodium",
"downloads_count": 58000000,
"created_at": "2020-01-07T00:00:00Z",
"updated_at": "2026-09-29T08:00:00Z",
"delisted_at": null,
"screenshots": [],
"organization": {
"id": "aBcD1234",
"slug": "caffeinemc",
"name": "CaffeineMC",
"url": "https://modrinth.com/organization/caffeinemc",
"icon_url": null
}
},
"minecraft_versions": [
"1.21.1",
"1.20.1"
],
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
},
{
"slug": "neoforge",
"name": "NeoForge"
}
],
"genres": [
{
"slug": "no-genre",
"name": "No Genre"
}
],
"features": [
{
"slug": "performance-optimization",
"name": "Performance & Optimization"
}
],
"themes": [],
"environment": [
{
"slug": "client-only",
"name": "Client Only"
}
],
"client_side": "required",
"server_side": "unsupported",
"counts": {
"dependencies": 0,
"dependents": 4200,
"modpack_dependents": 3900
},
"featured": null,
"license": {
"name": "Polyform Shield License 1.0.0",
"open_source": false,
"categories": [
"restrictive"
]
},
"latest_version": {
"curseforge": null,
"modrinth": {
"version_number": "mc1.21.1-0.6.0",
"released_at": "2026-09-29T08:00:00Z",
"minecraft_versions": [
"1.21.1"
],
"loaders": [
"fabric",
"neoforge"
],
"release_type": "release",
"url": "https://modrinth.com/mod/sodium/version/abc12345"
}
},
"authors": [
{
"name": "CaffeineMC",
"role": null,
"is_owner": false,
"is_organization": true,
"curseforge_url": null,
"modrinth_url": "https://modrinth.com/organization/caffeinemc",
"curseforge_handle": null,
"modrinth_handle": null
},
{
"name": "jellysquid3",
"role": "Owner",
"is_owner": true,
"is_organization": false,
"curseforge_url": "https://www.curseforge.com/members/jellysquid3",
"modrinth_url": "https://modrinth.com/user/jellysquid3",
"curseforge_handle": "jellysquid3",
"modrinth_handle": "jellysquid3"
}
],
"platform_urls": {
"source": "https://github.com/CaffeineMC/sodium",
"issues": "https://github.com/CaffeineMC/sodium/issues",
"wiki": null,
"discord": null
},
"sources": [
{
"project_id": 1234,
"platform": "modrinth",
"platform_id": "AANobbMI",
"label": "Modrinth",
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
}
],
"url": "https://modrinth.com/mod/sodium",
"latest_file_url": "https://modrinth.com/mod/sodium/version/abc12345",
"downloads_count": 58000000,
"available": true,
"is_canonical": true,
"last_updated_at": "2026-09-29T08:00:00Z"
}
],
"community_tags_count": 3
}
}
Example response (301, Merged listing):
{}
Example response (404, No such project):
{
"message": "Not found.",
"code": "not_found",
"docs_url": "https://moddex.gg/api/docs"
}
Example response (422, Unknown include):
{
"message": "Unknown value(s): screenshots. Valid values: description, ratings, counts, completion.",
"code": "validation_failed",
"errors": {
"include": [
"Unknown value(s): screenshots. Valid values: description, ratings, counts, completion."
]
},
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
downloads_count
integer|null
created_at
string|null
updated_at
string|null
delisted_at
string|null
When CurseForge stopped listing it.
screenshots
object[]
url
string
title
string|null
Plain text.
description
string|null
Plain text.
description_html
string
With include=description. Sanitized HTML.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
downloads_count
integer|null
created_at
string|null
updated_at
string|null
delisted_at
string|null
When Modrinth stopped listing it.
screenshots
object[]
url
string
title
string|null
Plain text.
description
string|null
Plain text.
organization
object|null
The Modrinth organization that owns it, if any.
id
string
slug
string|null
name
string
url
string|null
icon_url
string|null
description
string|null
With include=description. Markdown source that allows inline HTML: never render it with a permissive renderer; use description_html.
description_html
string|null
With include=description. Sanitized HTML.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
followers
integer
With include=counts.
stacks
integer
With include=counts.
library_entries
integer
With include=counts.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
license
object
name
string|null
As listed; comma-separated when several.
open_source
boolean
True only when every listed license is open source.
categories
string[]
One of permissive, copyleft, public_domain, attribution, restrictive, other, none.
latest_version
object
Newest release per platform; null when there is none.
curseforge
object|null
version_number
string|null
released_at
string|null
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
release_type
string
One of release, beta, alpha.
url
string|null
The release on its platform.
modrinth
object|null
version_number
string|null
released_at
string|null
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
release_type
string
One of release, beta, alpha.
url
string|null
The release on its platform.
authors
object[]
Credits, as the project page shows them.
name
string
role
string|null
is_owner
boolean
is_organization
boolean
curseforge_url
string|null
modrinth_url
string|null
curseforge_handle
string|null
CurseForge username; what curseforge_authors matches.
modrinth_handle
string|null
Modrinth username; what modrinth_authors matches.
platform_urls
object
Each an https URL or null.
https URL or null.source
string|null
issues
string|null
wiki
string|null
discord
string|null
sources
object[]
Every listing the project is downloaded from, including merged loader-specific ones.
project_id
integer
The listing's ModDex ID: what /dependencies?source= takes.
platform
string
One of curseforge, modrinth.
platform_id
string
label
string
loaders
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
url
string|null
Null while the listing is delisted.
latest_file_url
string|null
downloads_count
integer
available
boolean
is_canonical
boolean
This is the project's own row, not a merged loader-specific listing.
last_updated_at
string|null
community_tags_count
integer
Tags in /community-tags active: voted community tags plus the project's own genres, themes and features.
ratings
object
With include=ratings.
include=ratings.
histogram
object[]
Ten steps, 0.5 to 5.
rating
number
0.5 to 5.
count
integer
categories
object
gameplay
object[]
rating
number
0.5 to 5.
count
integer
performance
object[]
rating
number
0.5 to 5.
count
integer
aesthetics
object[]
rating
number
0.5 to 5.
count
integer
ranks
object|null
Null when unrated.
global
integer
by_type
integer
Among projects of the same type.
avg_completion_hours
number|null
With include=completion. Modpacks only; null for mods and when nobody has reported it.
List a project's reviews.
Approved written reviews, as the project's Reviews tab shows them. Quick ratings (stars only)
count toward rating but aren't listed.
Text is profanity-masked unless unmasked=1.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects/1234/reviews?sort=newest" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects/1234/reviews"
);
const params = {
"sort": "newest",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects/1234/reviews';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'sort' => 'newest',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects/1234/reviews'
params = {
'sort': 'newest',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Reviews):
{
"data": [
{
"id": 77,
"is_quick_rating": false,
"title": "Essential",
"content": "Doubles my FPS. ||The config screen is hidden in Video Settings.||",
"content_html": "<p>Doubles my FPS. <span data-spoiler>The config screen is hidden in Video Settings.</span></p>",
"rating": 5,
"categories": {
"gameplay": null,
"performance": 5,
"aesthetics": null
},
"minecraft_version": "1.21.1",
"playtime_hours": 300,
"completion_hours": null,
"play_status": "playing",
"pack_version": null,
"helpful_votes": 12,
"unhelpful_votes": 0,
"is_verified_developer": false,
"public_moderator_note": null,
"images": [],
"developer_response": null,
"author": {
"id": 9,
"name": "Steve",
"username": "steve",
"avatar_url": null,
"profile_url": "https://moddex.gg/user/steve",
"roles": [],
"reputation": {
"points": 420,
"tier": "contributor",
"tier_label": "Contributor"
}
},
"project": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
}
},
"url": "https://moddex.gg/mod/sodium/reviews/77",
"created_at": "2026-09-01T10:00:00Z",
"edited_at": null,
"updated_at": "2026-09-01T10:00:00Z"
}
],
"links": {
"first": "https://moddex.gg/api/v2/projects/1234/reviews?page=1",
"last": "https://moddex.gg/api/v2/projects/1234/reviews?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
id
integer
is_quick_rating
boolean
Stars only: no title or text.
title
string|null
Plain text.
content
string|null
The Markdown the author wrote. Plain text: escape it.
content_html
string|null
Sanitized HTML. Spoilers are wrapped in <span data-spoiler>.
rating
number
0.5 to 5 in steps of 0.5.
categories
object
Each 0.5 to 5, or null when not rated.
gameplay
number|null
performance
number|null
aesthetics
number|null
minecraft_version
string|null
As the reviewer entered it; may list several, comma-separated.
playtime_hours
integer|null
completion_hours
integer|null
play_status
string|null
One of playing, played, completed, plan_to_play, on_hold, dropped.
pack_version
string|null
The modpack version reviewed.
helpful_votes
integer
unhelpful_votes
integer
is_verified_developer
boolean
Written by one of the project's verified developers.
public_moderator_note
string|null
Plain text.
images
object[]
url
string
caption
string|null
Plain text.
developer_response
object|null
The developer's reply, if any.
content
string
Plain text.
responded_at
string|null
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
project
object
The project summary: id, name, slug, type, logo_url, available, rating and links.
url
string|null
The review's page on ModDex.
created_at
string|null
edited_at
string|null
updated_at
string|null
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
List a project's files.
The project's Files tab, one platform at a time: the files of the project and of every
loader-specific listing merged into it. Without platform you get the platform the website
opens on; meta.platforms lists every platform with files.
One row per release. A CurseForge row is a file, with its server pack attached. A Modrinth row
is a version: its primary file's fields at the top level, its other files in secondary_files.
download_url and platform_url are null while the listing that published the file is
delisted. Download links go to the platform's own download or version page, not a CDN.
include=changelog adds each release's changelog as sanitized HTML and caps per_page at 10.
A changelog over 100 KB is cut short (changelog_truncated: true); the full text is on
platform_url.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects/1234/files?platform=modrinth&minecraft_version=1.21.1&loader=fabric" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects/1234/files"
);
const params = {
"platform": "modrinth",
"minecraft_version": "1.21.1",
"loader": "fabric",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects/1234/files';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'platform' => 'modrinth',
'minecraft_version' => '1.21.1',
'loader' => 'fabric',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects/1234/files'
params = {
'platform': 'modrinth',
'minecraft_version': '1.21.1',
'loader': 'fabric',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Modrinth versions):
{
"data": [
{
"id": 9001,
"platform": "modrinth",
"curseforge_file_id": null,
"modrinth_version_id": "abc12345",
"sha1": "0123456789abcdef0123456789abcdef01234567",
"display_name": "Sodium 0.6.0",
"version_number": "mc1.21.1-0.6.0",
"release_type": "release",
"minecraft_versions": [
"1.21.1"
],
"loaders": [
"fabric",
"neoforge"
],
"file_name": "sodium-fabric-0.6.0+mc1.21.1.jar",
"file_size": 1048576,
"downloads_count": 250000,
"released_at": "2026-09-29T08:00:00Z",
"is_featured": true,
"download_url": "https://modrinth.com/mod/sodium/version/abc12345",
"platform_url": "https://modrinth.com/mod/sodium/version/abc12345",
"server_pack": null,
"secondary_files": [
{
"sha1": "89abcdef0123456789abcdef0123456789abcdef",
"file_name": "sodium-fabric-0.6.0+mc1.21.1-sources.jar",
"file_size": 524288,
"download_url": "https://modrinth.com/mod/sodium/version/abc12345"
}
]
}
],
"links": {
"first": "https://moddex.gg/api/v2/projects/1234/files?page=1",
"last": "https://moddex.gg/api/v2/projects/1234/files?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1,
"platform": "modrinth",
"platforms": [
"curseforge",
"modrinth"
]
}
}
Example response (422, Too many changelogs):
{
"message": "With include=changelog, per_page may be at most 10.",
"code": "validation_failed",
"errors": {
"per_page": [
"With include=changelog, per_page may be at most 10."
]
},
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
One row per release.
id
integer
ModDex file ID.
platform
string
One of curseforge, modrinth.
curseforge_file_id
string|null
CurseForge rows only.
modrinth_version_id
string|null
Modrinth rows only.
sha1
string|null
Modrinth rows only: the primary file's SHA1.
display_name
string
version_number
string|null
release_type
string
One of release, beta, alpha.
minecraft_versions
string[]
As the platform lists them.
loaders
string[]
As the platform lists them.
file_name
string|null
file_size
integer|null
Bytes.
downloads_count
integer
The file's downloads (the version's, for Modrinth rows).
released_at
string|null
is_featured
boolean
Modrinth's featured flag.
download_url
string|null
The platform's download page. Null while the publishing listing is delisted.
platform_url
string|null
The release's page on its platform. Null while the listing is delisted.
server_pack
object|null
CurseForge modpacks: the server pack.
curseforge_file_id
string
file_name
string|null
file_size
integer|null
download_url
string|null
secondary_files
object[]
Modrinth: the version's other files.
sha1
string
file_name
string|null
file_size
integer|null
download_url
string|null
changelog_html
string|null
With include=changelog. Sanitized HTML.
changelog_truncated
boolean
With include=changelog. True when the changelog was cut at 100 KB.
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
platform
string
The platform listed. One of curseforge, modrinth.
platforms
string[]
Platforms with at least one file. One of curseforge, modrinth.
List a project's dependencies.
What the project's Dependencies tab lists: the projects it requires, optionally uses, embeds
or ships with, as its own listing declares them. A dependency ModDex has is project, in the
list shape, always the project's main page even when the listing named a loader-specific
one. A dependency ModDex doesn't have has project: null and only its platform ID and name.
On a project listed on both CurseForge and Modrinth, the two listings usually name the same
libraries, so the list is read one platform at a time, as on the website: platform picks
which (default: the website's), and a library on both appears once. meta.platform is null
when the choice makes no difference.
Incompatible projects are listed in full under incompatible, not in data.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects/1234/dependencies?platform=modrinth" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects/1234/dependencies"
);
const params = {
"platform": "modrinth",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects/1234/dependencies';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'platform' => 'modrinth',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects/1234/dependencies'
params = {
'platform': 'modrinth',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Dependencies):
{
"data": [
{
"relation_type": "required",
"name": "Fabric API",
"curseforge_id": null,
"modrinth_id": "P7dR8mSH",
"project": {
"id": 77,
"name": "Fabric API",
"slug": "fabric-api",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/P7dR8mSH/icon.png",
"available": true,
"rating": {
"average": 4.9,
"bayesian": 4.7,
"count": 80,
"written_count": 40
},
"links": {
"web": "https://moddex.gg/mod/fabric-api",
"reviews": "https://moddex.gg/mod/fabric-api#reviews",
"write_review": "https://moddex.gg/mod/fabric-api#review-form",
"badge": "https://moddex.gg/badges/projects/fabric-api/rating.svg?type=mod"
},
"summary": "Core API library for the Fabric toolchain.",
"downloads_count": 200000000,
"last_updated_at": "2026-09-30T12:00:00Z",
"published_at": "2018-12-14T00:00:00Z",
"curseforge": {
"id": 306612,
"slug": "fabric-api",
"url": "https://www.curseforge.com/minecraft/mc-mods/fabric-api"
},
"modrinth": {
"id": "P7dR8mSH",
"slug": "fabric-api",
"url": "https://modrinth.com/mod/fabric-api"
},
"minecraft_versions": [
"1.21.1"
],
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
}
],
"genres": [],
"features": [
{
"slug": "apilibrary",
"name": "API/Library"
}
],
"themes": [],
"environment": [],
"client_side": "optional",
"server_side": "optional",
"counts": {
"dependencies": 0,
"dependents": 97000,
"modpack_dependents": 60000
},
"featured": null
}
},
{
"relation_type": "optional",
"name": "Some Addon",
"curseforge_id": null,
"modrinth_id": "AbCdEf12",
"project": null
}
],
"incompatible": [],
"links": {
"first": "https://moddex.gg/api/v2/projects/1234/dependencies?page=1",
"last": "https://moddex.gg/api/v2/projects/1234/dependencies?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 2,
"platform": "modrinth",
"source": 1234
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
relation_type
string
unknown when the listing gave none; incompatible in the incompatible list only. One of required, optional, embedded, tool, include, unknown, incompatible.
name
string
The name the listing declared.
curseforge_id
integer|null
The CurseForge project ID the listing declared.
modrinth_id
string|null
The Modrinth project ID the listing declared.
project
object|null
The dependency on ModDex; null when ModDex doesn't have it.
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
platform
string|null
The platform read; null when the project's list doesn't differ by platform. One of curseforge, modrinth.
source
integer
The ModDex ID of the listing whose list was read.
incompatible
object[]
Incompatible projects, not paginated.
relation_type
string
unknown when the listing gave none; incompatible in the incompatible list only. One of required, optional, embedded, tool, include, unknown, incompatible.
name
string
The name the listing declared.
curseforge_id
integer|null
The CurseForge project ID the listing declared.
modrinth_id
string|null
The Modrinth project ID the listing declared.
project
object|null
The dependency on ModDex; null when ModDex doesn't have it.
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
List a project's dependents.
What the project's Dependents tab lists: every project whose own listing declares this one as
a dependency (incompatible declarations don't count), including delisted projects
(available: false), as the website does. Each row's relation_type is how it depends on
this one.
On a project listed on both platforms the list is read one platform at a time, by where the
dependent is listed: platform picks which (default: the website's). meta.platform is null
when the choice makes no difference.
Pages deeper than page × per_page = 10,000 are a 422.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects/1234/dependents?type=modpack" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects/1234/dependents"
);
const params = {
"type": "modpack",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects/1234/dependents';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'type' => 'modpack',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects/1234/dependents'
params = {
'type': 'modpack',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Dependents):
{
"data": [
{
"relation_type": "embedded",
"project": {
"id": 5678,
"name": "Example Pack",
"slug": "example-pack",
"type": "modpack",
"logo_url": "https://media.forgecdn.net/avatars/thumbnails/1/2/64/64/example.png",
"available": true,
"rating": {
"average": 4,
"bayesian": 3.9,
"count": 6,
"written_count": 2
},
"links": {
"web": "https://moddex.gg/modpack/example-pack",
"reviews": "https://moddex.gg/modpack/example-pack#reviews",
"write_review": "https://moddex.gg/modpack/example-pack#review-form",
"badge": "https://moddex.gg/badges/projects/example-pack/rating.svg?type=modpack"
},
"summary": "A light tech and exploration pack.",
"downloads_count": 1250000,
"last_updated_at": "2026-09-12T08:00:00Z",
"published_at": "2025-03-01T00:00:00Z",
"curseforge": {
"id": 998877,
"slug": "example-pack",
"url": "https://www.curseforge.com/minecraft/modpacks/example-pack"
},
"modrinth": null,
"minecraft_versions": [
"1.21.1"
],
"loaders": [
{
"slug": "neoforge",
"name": "NeoForge"
}
],
"genres": [
{
"slug": "tech",
"name": "Tech"
}
],
"features": [],
"themes": [],
"environment": [],
"client_side": null,
"server_side": null,
"counts": {
"dependencies": 142,
"dependents": 0,
"modpack_dependents": 0
},
"featured": null
}
}
],
"links": {
"first": "https://moddex.gg/api/v2/projects/1234/dependents?type=modpack&page=1",
"last": "https://moddex.gg/api/v2/projects/1234/dependents?type=modpack&page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1,
"platform": "modrinth"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
relation_type
string
How the dependent depends on this project. One of required, optional, embedded, tool, include, unknown.
project
object
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
platform
string|null
The platform read; null when the list doesn't differ by platform. One of curseforge, modrinth.
List a modpack's contents.
The mods a modpack ships, which are its dependencies: the same list, parameters and shape as
"List a project's dependencies". A mod is a 404. For the modpacks that contain a mod, use
"List a project's dependents" with type=modpack.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects/5678/contents" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects/5678/contents"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects/5678/contents';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects/5678/contents'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Contents):
{
"data": [
{
"relation_type": "embedded",
"name": "Sodium",
"curseforge_id": null,
"modrinth_id": "AANobbMI",
"project": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
},
"summary": "A modern rendering engine for Minecraft.",
"downloads_count": 98000000,
"last_updated_at": "2026-09-30T12:00:00Z",
"published_at": "2020-01-07T00:00:00Z",
"curseforge": {
"id": 394468,
"slug": "sodium",
"url": "https://www.curseforge.com/minecraft/mc-mods/sodium"
},
"modrinth": {
"id": "AANobbMI",
"slug": "sodium",
"url": "https://modrinth.com/mod/sodium"
},
"minecraft_versions": [
"1.21.1",
"1.20.1"
],
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
},
{
"slug": "neoforge",
"name": "NeoForge"
}
],
"genres": [
{
"slug": "no-genre",
"name": "No Genre"
}
],
"features": [
{
"slug": "performance-optimization",
"name": "Performance & Optimization"
}
],
"themes": [],
"environment": [
{
"slug": "client-only",
"name": "Client Only"
}
],
"client_side": "required",
"server_side": "unsupported",
"counts": {
"dependencies": 0,
"dependents": 4200,
"modpack_dependents": 3900
},
"featured": null
}
}
],
"incompatible": [],
"links": {
"first": "https://moddex.gg/api/v2/projects/5678/contents?page=1",
"last": "https://moddex.gg/api/v2/projects/5678/contents?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 20,
"total": 1,
"platform": "modrinth",
"source": 5678
}
}
Example response (404, A mod):
{
"message": "Not found.",
"code": "not_found",
"hint": "Only modpacks have contents. For the modpacks that include this mod, use /api/v2/projects/1234/dependents?type=modpack.",
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
relation_type
string
unknown when the listing gave none; incompatible in the incompatible list only. One of required, optional, embedded, tool, include, unknown, incompatible.
name
string
The name the listing declared.
curseforge_id
integer|null
The CurseForge project ID the listing declared.
modrinth_id
string|null
The Modrinth project ID the listing declared.
project
object|null
The dependency on ModDex; null when ModDex doesn't have it.
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
platform
string|null
The platform read; null when the project's list doesn't differ by platform. One of curseforge, modrinth.
source
integer
The ModDex ID of the listing whose list was read.
incompatible
object[]
Incompatible projects, not paginated.
relation_type
string
unknown when the listing gave none; incompatible in the incompatible list only. One of required, optional, embedded, tool, include, unknown, incompatible.
name
string
The name the listing declared.
curseforge_id
integer|null
The CurseForge project ID the listing declared.
modrinth_id
string|null
The Modrinth project ID the listing declared.
project
object|null
The dependency on ModDex; null when ModDex doesn't have it.
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
List similar projects.
The project's Similar tab: up to 100 listed projects of the same type, most similar first, from a list ModDex computes ahead of time.
A newly added project has no list yet: the response is computed: false with an empty data
and a Retry-After (seconds). ModDex computes new projects every 15 minutes. Delisted
projects aren't computed. They return computed: true, computed_at: null and no
Retry-After, since there's nothing to wait for.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/projects/1234/similar" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/projects/1234/similar"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/projects/1234/similar';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/projects/1234/similar'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Computed):
{
"data": [
{
"id": 4321,
"name": "Embeddium",
"slug": "embeddium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/sk9rgfiA/icon.png",
"available": true,
"rating": {
"average": 4.5,
"bayesian": 4.2,
"count": 12,
"written_count": 5
},
"links": {
"web": "https://moddex.gg/mod/embeddium",
"reviews": "https://moddex.gg/mod/embeddium#reviews",
"write_review": "https://moddex.gg/mod/embeddium#review-form",
"badge": "https://moddex.gg/badges/projects/embeddium/rating.svg?type=mod"
},
"summary": "Rendering optimizations for NeoForge, based on Sodium.",
"downloads_count": 9800000,
"last_updated_at": "2026-08-30T10:00:00Z",
"published_at": "2023-08-01T00:00:00Z",
"curseforge": {
"id": 908741,
"slug": "embeddium",
"url": "https://www.curseforge.com/minecraft/mc-mods/embeddium"
},
"modrinth": {
"id": "sk9rgfiA",
"slug": "embeddium",
"url": "https://modrinth.com/mod/embeddium"
},
"minecraft_versions": [
"1.21.1",
"1.20.1"
],
"loaders": [
{
"slug": "neoforge",
"name": "NeoForge"
}
],
"genres": [
{
"slug": "no-genre",
"name": "No Genre"
}
],
"features": [
{
"slug": "performance-optimization",
"name": "Performance & Optimization"
}
],
"themes": [],
"environment": [
{
"slug": "client-only",
"name": "Client Only"
}
],
"client_side": "required",
"server_side": "unsupported",
"counts": {
"dependencies": 0,
"dependents": 310,
"modpack_dependents": 300
},
"featured": null
}
],
"computed": true,
"computed_at": "2026-10-06T03:12:00Z",
"links": {
"first": "https://moddex.gg/api/v2/projects/1234/similar?page=1",
"last": "https://moddex.gg/api/v2/projects/1234/similar?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 12,
"total": 1
}
}
Example response (200, Not computed yet):
{
"data": [],
"computed": false,
"computed_at": null,
"links": {
"first": "https://moddex.gg/api/v2/projects/1234/similar?page=1",
"last": "https://moddex.gg/api/v2/projects/1234/similar?page=1",
"prev": null,
"next": null
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 12,
"total": 0
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
Similar projects, most similar first.
id
integer
ModDex project ID.
name
string
Plain text; escape it.
slug
string
ModDex slug.
type
string
One of mod, modpack.
logo_url
string
Absolute https URL; a ModDex placeholder when the project has no logo.
available
boolean
False when the project is delisted on every platform it was on. Its ModDex page still exists.
rating
object
average
number|null
Mean rating, 0.5 to 5 (each rating is a step of 0.5). Null when unrated.
bayesian
number|null
Bayesian-adjusted rating, which the catalog ranks by. Null when unrated.
count
integer
Quick ratings plus written reviews.
written_count
integer
Written reviews only.
links
object
web
string
The project page on ModDex.
reviews
string
The page's Reviews tab.
write_review
string
Opens the review form.
badge
string
Rating badge (SVG), for a README.
summary
string|null
Plain text.
downloads_count
integer
Downloads across both platforms.
last_updated_at
string|null
Newest platform update.
published_at
string|null
Earliest platform creation date.
curseforge
object|null
Null when the project isn't on CurseForge.
id
integer
slug
string|null
Null when the listing URL carries no slug.
url
string|null
Null while the listing is delisted.
modrinth
object|null
Null when the project isn't on Modrinth.
id
string
Modrinth project ID (8 characters, case-sensitive).
slug
string|null
url
string|null
Null while the listing is delisted.
minecraft_versions
string[]
Version strings, newest first.
loaders
object[]
Mod loaders.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
genres
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
features
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
themes
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
environment
object[]
Where it installs: client-only, server-only, client-and-server, either-side, …
client-only, server-only, client-and-server, either-side, …slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
client_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
server_side
string|null
Deprecated by Modrinth. One of required, optional, unsupported, unknown.
counts
object
dependencies
integer
Entries in the dependency lists of both platforms together; a dependency declared on each platform can count twice. /dependencies reads one platform at a time, so its meta.total is usually lower.
dependents
integer
Projects that depend on this one on either platform, each counted once. /dependents reads one platform at a time (meta.platform), so its meta.total can be lower.
modpack_dependents
integer
Modpacks that include the project.
featured
object|null
Staff pick. Null unless featured.
priority
integer|null
Its slot on the ModDex homepage, lowest first (1 is the large card).
blurb
string|null
Plain text.
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
computed
boolean
False while a new project waits for its first computation; retry after Retry-After seconds.
computed_at
string|null
When the list was computed.
List a project's community tags.
The genre, theme and feature tags on the project, as its community tag panel shows them.
active is every tag currently applied, pinned tags first, then by name. proposed lists tags
the community has suggested but not yet applied, highest score first. A tag that only comes
from the platform listing has no community record yet, so its weighted_score and
unique_voter_count are null.
The list isn't paginated, since a project has a few dozen tags at most.
Response
Response Fields
data
object
active
object[]
Applied tags, pinned first, then by name.
tag
object
id
integer
slug
string
name
string
type
string
One of genre, theme, feature.
weighted_score
integer|null
A starting score plus reputation-weighted votes; null when the tag has no community record yet.
unique_voter_count
integer|null
Distinct voters; null when weighted_score is.
pinned
boolean
Pinned by the developer or staff.
proposed
object[]
Suggested, not yet applied; highest score first.
tag
object
id
integer
slug
string
name
string
type
string
One of genre, theme, feature.
weighted_score
integer|null
A starting score plus reputation-weighted votes; null when the tag has no community record yet.
unique_voter_count
integer|null
Distinct voters; null when weighted_score is.
pinned
boolean
Pinned by the developer or staff.
Reviews
List reviews.
Every public review on ModDex, newest first: approved written reviews of projects that have a
page. Add quick ratings (stars only) with written_only=0. Takes the same filters as a
project's review list, plus project_ids, type and since, for "latest reviews" widgets and
authors watching their own projects. To post every new review as it appears, follow the reviews
sync feed instead.
Text is profanity-masked unless unmasked=1. Pages deeper than page × per_page = 10,000 are a 422.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/reviews" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/reviews"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/reviews';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/reviews'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Reviews):
{
"data": [
{
"id": 77,
"is_quick_rating": false,
"title": "Essential",
"content": "Doubles my FPS.",
"content_html": "<p>Doubles my FPS.</p>",
"rating": 5,
"categories": {
"gameplay": null,
"performance": 5,
"aesthetics": null
},
"minecraft_version": "1.21.1",
"playtime_hours": 300,
"completion_hours": null,
"play_status": "playing",
"pack_version": null,
"helpful_votes": 12,
"unhelpful_votes": 0,
"is_verified_developer": false,
"public_moderator_note": null,
"images": [
{
"url": "https://cdn.moddex.gg/review-images/77/1.webp",
"caption": null
}
],
"developer_response": {
"content": "Thanks!",
"responded_at": "2026-09-02T09:00:00Z",
"author": {
"id": 3,
"name": "jellysquid3",
"username": "jellysquid3",
"avatar_url": null,
"profile_url": "https://moddex.gg/user/jellysquid3",
"roles": [],
"reputation": {
"points": 10,
"tier": "explorer",
"tier_label": "Explorer"
}
}
},
"author": {
"id": 9,
"name": "Steve",
"username": "steve",
"avatar_url": "https://cdn.moddex.gg/avatars/9-96.webp",
"profile_url": "https://moddex.gg/user/steve",
"roles": [
"moderator"
],
"reputation": {
"points": 420,
"tier": "contributor",
"tier_label": "Contributor"
}
},
"project": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
}
},
"url": "https://moddex.gg/mod/sodium/reviews/77",
"created_at": "2026-09-01T10:00:00Z",
"edited_at": null,
"updated_at": "2026-09-02T09:00:00Z"
}
],
"links": {
"first": "https://moddex.gg/api/v2/reviews?page=1",
"last": "https://moddex.gg/api/v2/reviews?page=94",
"prev": null,
"next": "https://moddex.gg/api/v2/reviews?page=2"
},
"meta": {
"current_page": 1,
"last_page": 94,
"per_page": 20,
"total": 1869
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
id
integer
is_quick_rating
boolean
Stars only: no title or text.
title
string|null
Plain text.
content
string|null
The Markdown the author wrote. Plain text: escape it.
content_html
string|null
Sanitized HTML. Spoilers are wrapped in <span data-spoiler>.
rating
number
0.5 to 5 in steps of 0.5.
categories
object
Each 0.5 to 5, or null when not rated.
gameplay
number|null
performance
number|null
aesthetics
number|null
minecraft_version
string|null
As the reviewer entered it; may list several, comma-separated.
playtime_hours
integer|null
completion_hours
integer|null
play_status
string|null
One of playing, played, completed, plan_to_play, on_hold, dropped.
pack_version
string|null
The modpack version reviewed.
helpful_votes
integer
unhelpful_votes
integer
is_verified_developer
boolean
Written by one of the project's verified developers.
public_moderator_note
string|null
Plain text.
images
object[]
url
string
caption
string|null
Plain text.
developer_response
object|null
The developer's reply, if any.
content
string
Plain text.
responded_at
string|null
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
project
object
The project summary: id, name, slug, type, logo_url, available, rating and links.
url
string|null
The review's page on ModDex.
created_at
string|null
edited_at
string|null
updated_at
string|null
links
object
first
string
last
string
prev
string|null
next
string|null
meta
object
current_page
integer
last_page
integer
per_page
integer
total
integer
Show a review.
One approved review, written or a quick rating (stars only). Pending, rejected and deleted reviews, and reviews of a project that no longer has a page, are 404.
Text is profanity-masked unless unmasked=1.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/reviews/77" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/reviews/77"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/reviews/77';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/reviews/77'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Found):
{
"data": {
"id": 77,
"is_quick_rating": false,
"title": "Essential",
"content": "Doubles my FPS.",
"content_html": "<p>Doubles my FPS.</p>",
"rating": 5,
"categories": {
"gameplay": null,
"performance": 5,
"aesthetics": null
},
"minecraft_version": "1.21.1",
"playtime_hours": 300,
"completion_hours": null,
"play_status": "playing",
"pack_version": null,
"helpful_votes": 12,
"unhelpful_votes": 0,
"is_verified_developer": false,
"public_moderator_note": null,
"images": [
{
"url": "https://cdn.moddex.gg/review-images/77/1.webp",
"caption": null
}
],
"developer_response": {
"content": "Thanks!",
"responded_at": "2026-09-02T09:00:00Z",
"author": {
"id": 3,
"name": "jellysquid3",
"username": "jellysquid3",
"avatar_url": null,
"profile_url": "https://moddex.gg/user/jellysquid3",
"roles": [],
"reputation": {
"points": 10,
"tier": "explorer",
"tier_label": "Explorer"
}
}
},
"author": {
"id": 9,
"name": "Steve",
"username": "steve",
"avatar_url": "https://cdn.moddex.gg/avatars/9-96.webp",
"profile_url": "https://moddex.gg/user/steve",
"roles": [
"moderator"
],
"reputation": {
"points": 420,
"tier": "contributor",
"tier_label": "Contributor"
}
},
"project": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
}
},
"url": "https://moddex.gg/mod/sodium/reviews/77",
"created_at": "2026-09-01T10:00:00Z",
"edited_at": null,
"updated_at": "2026-09-02T09:00:00Z"
}
}
Example response (404, Not public):
{
"message": "Not found.",
"code": "not_found",
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
id
integer
is_quick_rating
boolean
Stars only: no title or text.
title
string|null
Plain text.
content
string|null
The Markdown the author wrote. Plain text: escape it.
content_html
string|null
Sanitized HTML. Spoilers are wrapped in <span data-spoiler>.
rating
number
0.5 to 5 in steps of 0.5.
categories
object
Each 0.5 to 5, or null when not rated.
gameplay
number|null
performance
number|null
aesthetics
number|null
minecraft_version
string|null
As the reviewer entered it; may list several, comma-separated.
playtime_hours
integer|null
completion_hours
integer|null
play_status
string|null
One of playing, played, completed, plan_to_play, on_hold, dropped.
pack_version
string|null
The modpack version reviewed.
helpful_votes
integer
unhelpful_votes
integer
is_verified_developer
boolean
Written by one of the project's verified developers.
public_moderator_note
string|null
Plain text.
images
object[]
url
string
caption
string|null
Plain text.
developer_response
object|null
The developer's reply, if any.
content
string
Plain text.
responded_at
string|null
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
project
object
The project summary: id, name, slug, type, logo_url, available, rating and links.
url
string|null
The review's page on ModDex.
created_at
string|null
edited_at
string|null
updated_at
string|null
Catalog vocabulary
The values /v2/projects filters accept, for building a filter UI or validating input. The
lists are small and rarely change, so cache them (responses are max-age=3600).
List the catalog filters.
Every /v2/projects parameter, with:
- its type
- whether it takes a comma-separated list, and how many values
- its
_excludeand any/allmodecompanions - for small vocabularies, every valid value as
{slug, name}
Also every sort with its default direction, and the paging limits. Minecraft versions are
listed by /v2/minecraft-versions; minecraft_version_groups are the values mc_exact=0 takes.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/catalog/filters" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/catalog/filters"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/catalog/filters';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/catalog/filters'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Success):
{
"data": {
"parameters": [
{
"name": "q",
"type": "string",
"list": false,
"values": null,
"description": "Full-text search, 3 to 200 characters. Returns at most 1000 matches."
},
{
"name": "loaders",
"type": "slug",
"list": true,
"max_values": 50,
"exclude_parameter": "loaders_exclude",
"mode_parameter": null,
"values": [
{
"slug": "fabric",
"name": "Fabric"
},
{
"slug": "neoforge",
"name": "NeoForge"
}
],
"description": "Mod loader slugs. With `minecraft_versions`, one file must carry both the loader and the version."
},
{
"name": "featured",
"type": "boolean",
"list": false,
"min": null,
"max": null,
"values": null,
"description": "Only staff picks."
}
],
"modes": [
"any",
"all"
],
"minecraft_version_groups": [
"1.21",
"1.20",
"pre-1.7"
],
"sorts": [
{
"sort": "relevance",
"default_direction": "desc"
},
{
"sort": "bayesian_rating",
"default_direction": "desc"
},
{
"sort": "name",
"default_direction": "asc"
}
],
"default_sort": "bayesian_rating",
"default_sort_with_q": "relevance",
"per_page": {
"default": 20,
"max": 50
},
"max_page_depth": 10000
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
parameters
object[]
One entry per /v2/projects parameter.
/v2/projects parameter.name
string
type
string
boolean takes 1/0/true/false; date takes ISO 8601. One of string, enum, slug, minecraft_version, project_id, boolean, number, integer, date.
list
boolean
Takes a comma-separated list.
max_values
integer
List parameters: the most values one request may send.
exclude_parameter
string|null
List parameters: the _exclude twin, if any.
mode_parameter
string|null
List parameters: the any/all companion, if any.
min
number|null
Scalar parameters.
max
number|null
Scalar parameters.
values
object[]|null
Every valid value; null when the vocabulary isn't listed here.
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
description
string
modes
string[]
Values the *_mode parameters take. One of any, all.
minecraft_version_groups
string[]
Version groups for mc_exact=0, newest first.
sorts
object[]
sort
string
default_direction
string
One of asc, desc.
default_sort
string
default_sort_with_q
string
per_page
object
default
integer
max
integer
max_page_depth
integer
page × per_page may not exceed this.
List Minecraft versions.
Every version the catalog knows, newest first. Each version is a valid minecraft_versions
filter value.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/minecraft-versions?type=release" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/minecraft-versions"
);
const params = {
"type": "release",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/minecraft-versions';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'type' => 'release',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/minecraft-versions'
params = {
'type': 'release',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Success):
{
"data": [
{
"version": "1.21.1",
"type": "release",
"released_at": "2024-08-08"
},
{
"version": "24w33a",
"type": "snapshot",
"released_at": "2024-08-15"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
Newest first.
version
string
What filters and project responses use.
type
string
Release type, such as release or snapshot.
released_at
string|null
Release date (ISO 8601 date), when known.
List mod loaders.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/loaders" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/loaders"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/loaders';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/loaders'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Success):
{
"data": [
{
"slug": "fabric",
"name": "Fabric"
},
{
"slug": "forge",
"name": "Forge"
},
{
"slug": "neoforge",
"name": "NeoForge"
},
{
"slug": "quilt",
"name": "Quilt"
}
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
slug
string
What the matching /v2/projects filter takes.
name
string
Display name.
List tags.
Genres, features, themes and environments: every value the matching /v2/projects filter
takes. Not paginated.
Response
Response Fields
data
object[]
slug
string
What the matching filter (genres, features, themes, environment) takes.
name
string
type
string
One of genre, feature, theme, environment.
description
string|null
Plain text.
category
string|null
The group a feature is listed under; null for other types.
Sync
Follow what changes on ModDex, for example to post new reviews or to keep the projects you show up to date. Each feed lists changes oldest first and is read forward with a cursor.
- Start with
since(changes at or after that time). - Follow
meta.next_cursor(orlinks.next) whilemeta.has_moreis true. - Store the last
next_cursor, and pass it again later to get what changed since. On the last pagelinks.nextis null, butnext_cursoris still set.
A cursor carries its since, so don't send both. A cursor that has been edited, or belongs to the
other feed, is a 422 with code: invalid_cursor; start over without it.
Delivery is at least once. A row that changes again while you read comes round again, so apply
rows by id. A change reaches the feed 5 minutes after it's made, so nothing that commits late is
skipped. Responses are cached for up to 5 minutes as well, so allow 10 minutes in total.
Sync projects.
Every project change in order. Each row is one of:
- a project that still has a page on ModDex, in the list shape (as in "List and search
projects"), including delisted projects (
available: false) - a tombstone,
{id, removed: true, reason}, for a project that no longer resolves.reasonisdeleted, ormergedwithcanonical_id, the project the listing now belongs to (which has its own row in the feed)
If you store projects, delete a tombstoned one and its reviews.
Tag, loader and Minecraft version changes bump a project back into the feed. Rating, download and other counts change often, so expect popular projects to come round regularly.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/sync/projects?since=2026-10-01T00%3A00%3A00Z" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/sync/projects"
);
const params = {
"since": "2026-10-01T00:00:00Z",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/sync/projects';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'since' => '2026-10-01T00:00:00Z',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/sync/projects'
params = {
'since': '2026-10-01T00:00:00Z',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, A live row and two tombstones):
{
"data": [
{
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
},
"summary": "A modern rendering engine for Minecraft.",
"downloads_count": 98000000,
"last_updated_at": "2026-09-30T12:00:00Z",
"published_at": "2020-01-07T00:00:00Z",
"curseforge": {
"id": 394468,
"slug": "sodium",
"url": "https://www.curseforge.com/minecraft/mc-mods/sodium"
},
"modrinth": {
"id": "AANobbMI",
"slug": "sodium",
"url": "https://modrinth.com/mod/sodium"
},
"minecraft_versions": [
"1.21.1"
],
"loaders": [
{
"slug": "fabric",
"name": "Fabric"
}
],
"genres": [],
"features": [
{
"slug": "performance-optimization",
"name": "Performance & Optimization"
}
],
"themes": [],
"environment": [
{
"slug": "client-only",
"name": "Client Only"
}
],
"client_side": "required",
"server_side": "unsupported",
"counts": {
"dependencies": 0,
"dependents": 4200,
"modpack_dependents": 3900
},
"featured": null
},
{
"id": 5678,
"removed": true,
"reason": "merged",
"canonical_id": 1234
},
{
"id": 9012,
"removed": true,
"reason": "deleted"
}
],
"links": {
"next": "https://moddex.gg/api/v2/sync/projects?cursor=eyJmZWVkIjoicHJvamVjdHMi",
"prev": null
},
"meta": {
"per_page": 100,
"next_cursor": "eyJmZWVkIjoicHJvamVjdHMi",
"prev_cursor": null,
"has_more": true
}
}
Example response (422, Edited cursor):
{
"message": "The cursor is invalid.",
"code": "invalid_cursor",
"hint": "Pass back a next_cursor exactly as a response gave it, to the same feed. To start over, omit cursor.",
"docs_url": "https://moddex.gg/api/docs"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
Live rows in the list shape, or tombstones: tell them apart by removed.
removed.id
integer
removed
boolean
Present, and true, only on a tombstone.
reason
string
One of deleted, merged.
canonical_id
integer
With reason: merged: the project this listing was merged into.
links
object
next
string|null
This feed continued from next_cursor; null once has_more is false (keep next_cursor to poll later).
prev
null
The feeds only go forward.
meta
object
per_page
integer
next_cursor
string
Always set. On the last page it points just past the last row, ready to poll with later.
prev_cursor
null
The feeds only go forward.
has_more
boolean
True when more rows are ready now.
Sync reviews.
Every public written review that changed, in order, in the review shape (as in "Show a
review"). Quick ratings (stars only) count toward each project's rating but aren't in this
feed.
This feed has no tombstones. A review leaves ModDex when it is unapproved, deleted, its author deletes their account, or its project is removed, and some of those leave no trace to send. If you store reviews, check them against "List public review IDs" at least daily and delete every one it doesn't list. A project tombstone in the projects feed removes that project's reviews too.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/sync/reviews?since=2026-10-01T00%3A00%3A00Z" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/sync/reviews"
);
const params = {
"since": "2026-10-01T00:00:00Z",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/sync/reviews';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'since' => '2026-10-01T00:00:00Z',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/sync/reviews'
params = {
'since': '2026-10-01T00:00:00Z',
}
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Reviews):
{
"data": [
{
"id": 77,
"is_quick_rating": false,
"title": "Essential",
"content": "Doubles my FPS.",
"content_html": "<p>Doubles my FPS.</p>",
"rating": 5,
"categories": {
"gameplay": null,
"performance": 5,
"aesthetics": null
},
"minecraft_version": "1.21.1",
"playtime_hours": 300,
"completion_hours": null,
"play_status": "playing",
"pack_version": null,
"helpful_votes": 12,
"unhelpful_votes": 0,
"is_verified_developer": false,
"public_moderator_note": null,
"images": [],
"developer_response": null,
"author": {
"id": 9,
"name": "Steve",
"username": "steve",
"avatar_url": null,
"profile_url": "https://moddex.gg/user/steve",
"roles": [],
"reputation": {
"points": 420,
"tier": "contributor",
"tier_label": "Contributor"
}
},
"project": {
"id": 1234,
"name": "Sodium",
"slug": "sodium",
"type": "mod",
"logo_url": "https://cdn.modrinth.com/data/AANobbMI/icon.png",
"available": true,
"rating": {
"average": 4.8,
"bayesian": 4.6,
"count": 52,
"written_count": 31
},
"links": {
"web": "https://moddex.gg/mod/sodium",
"reviews": "https://moddex.gg/mod/sodium#reviews",
"write_review": "https://moddex.gg/mod/sodium#review-form",
"badge": "https://moddex.gg/badges/projects/sodium/rating.svg?type=mod"
}
},
"url": "https://moddex.gg/mod/sodium/reviews/77",
"created_at": "2026-09-01T10:00:00Z",
"edited_at": null,
"updated_at": "2026-09-01T10:00:00Z"
}
],
"links": {
"next": null,
"prev": null
},
"meta": {
"per_page": 50,
"next_cursor": "eyJmZWVkIjoicmV2aWV3cyJ9",
"prev_cursor": null,
"has_more": false
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object[]
author and project are as of this response; their own changes don't bump a review.
author and project are as of this response; their own changes don't bump a review.id
integer
is_quick_rating
boolean
Stars only: no title or text.
title
string|null
Plain text.
content
string|null
The Markdown the author wrote. Plain text: escape it.
content_html
string|null
Sanitized HTML. Spoilers are wrapped in <span data-spoiler>.
rating
number
0.5 to 5 in steps of 0.5.
categories
object
Each 0.5 to 5, or null when not rated.
gameplay
number|null
performance
number|null
aesthetics
number|null
minecraft_version
string|null
As the reviewer entered it; may list several, comma-separated.
playtime_hours
integer|null
completion_hours
integer|null
play_status
string|null
One of playing, played, completed, plan_to_play, on_hold, dropped.
pack_version
string|null
The modpack version reviewed.
helpful_votes
integer
unhelpful_votes
integer
is_verified_developer
boolean
Written by one of the project's verified developers.
public_moderator_note
string|null
Plain text.
images
object[]
url
string
caption
string|null
Plain text.
developer_response
object|null
The developer's reply, if any.
content
string
Plain text.
responded_at
string|null
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
author
object
id
integer|null
Null for a deleted account.
name
string
"Deleted User" for a deleted account.
username
string|null
avatar_url
string|null
profile_url
string|null
roles
string[]
The staff badge the profile shows, if any. One of admin, moderator, tag_curator.
reputation
object|null
Null for a deleted account.
points
integer
tier
string
tier_label
string
project
object
The project summary: id, name, slug, type, logo_url, available, rating and links.
url
string|null
The review's page on ModDex.
created_at
string|null
edited_at
string|null
updated_at
string|null
links
object
next
string|null
This feed continued from next_cursor; null once has_more is false (keep next_cursor to poll later).
prev
null
The feeds only go forward.
meta
object
per_page
integer
next_cursor
string
Always set. On the last page it points just past the last row, ready to poll with later.
prev_cursor
null
The feeds only go forward.
has_more
boolean
True when more rows are ready now.
List public review IDs.
The ID of every review the reviews feed would serve right now, ascending, unpaginated. If you store reviews, delete any that isn't listed. Refreshed every 5 minutes.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2/sync/reviews/ids" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2/sync/reviews/ids"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2/sync/reviews/ids';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2/sync/reviews/ids'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, IDs):
{
"data": [
3,
77,
104
]
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
integer[]
Review IDs, ascending.
API root.
Identifies the API version and links to the documentation. Every caller gets the same response. Your rate-limit
details are in the X-RateLimit-* headers, not the body.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v2" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v2"
);
const headers = {
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v2';
$response = $client->get(
$url,
[
'headers' => [
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v2'
headers = {
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Success):
{
"data": {
"name": "ModDex API",
"version": "v2",
"docs_url": "https://moddex.gg/api/docs"
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Response
Response Fields
data
object
name
string
version
string
docs_url
string
v1 (deprecated)
Deprecated: frozen, token-only, and switched off six months after v2 becomes generally available. See "Migrating from v1".
User
Endpoints for the authenticated API token holder.
Show the authenticated user.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns the profile for the user associated with the current Sanctum token, including reputation rank, social links, and privacy settings for library, follows, and user-directory visibility.
Example request:
curl --request GET \
--get "https://moddex.gg/api/user" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/user"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/user';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/user'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Success):
{
"data": {
"id": 1,
"name": "Steve",
"username": "steve",
"email": "[email protected]",
"email_verified_at": "2026-01-15T12:00:00+00:00",
"bio": "Minecraft mod enthusiast.",
"avatar_url": "https://moddex.gg/storage/avatars/1.png",
"rank": "contributor",
"social_links": {
"curseforge": null,
"modrinth": "https://modrinth.com/user/steve",
"github": "https://github.com/steve",
"discord_username": "steve#0001",
"discord_server": null,
"reddit": null,
"x": null,
"bluesky": null
},
"library_is_public": true,
"follows_is_public": false,
"user_directory_is_public": true,
"two_factor_enabled": false,
"created_at": "2025-06-01T00:00:00+00:00"
}
}
Example response (401, Unauthenticated):
{
"message": "Unauthenticated."
}
Example response (403, Missing read ability):
{
"message": "Invalid ability provided."
}
Example response (403, Unverified email):
{
"message": "Your email address is not verified."
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Projects
Endpoints for browsing and viewing Minecraft mods and modpacks.
List projects.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns a paginated list of active Minecraft mods and modpacks with community ratings, download counts, taxonomy tags, and supported Minecraft versions. Use type to filter mods vs modpacks, sort to rank by rating or popularity, and featured to surface editor picks.
bayesian_rating adjusts for review count. Projects with few reviews are pulled toward the site-wide average, preventing a single 5-star review from outranking a project with hundreds of reviews.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v1/projects?type=mod&sort=average_rating&direction=desc&featured=1&per_page=15" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v1/projects"
);
const params = {
"type": "mod",
"sort": "average_rating",
"direction": "desc",
"featured": "1",
"per_page": "15",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v1/projects';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'type' => 'mod',
'sort' => 'average_rating',
'direction' => 'desc',
'featured' => '1',
'per_page' => '15',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v1/projects'
params = {
'type': 'mod',
'sort': 'average_rating',
'direction': 'desc',
'featured': '1',
'per_page': '15',
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Success):
{
"data": [
{
"id": 1,
"name": "Create",
"slug": "create",
"summary": "Aesthetic Technology that empowers the Player",
"type": "mod",
"logo_url": "https://...",
"average_rating": 4.5,
"bayesian_rating": 4.2,
"total_ratings": 12,
"total_reviews": 8,
"written_reviews_count": 8,
"downloads_count": 500000,
"minecraft_versions": [
"1.20.1",
"1.21.1"
],
"mod_loaders": [
"Forge",
"NeoForge"
],
"genres": [
"Tech"
],
"last_updated_at": "2026-03-15T00:00:00+00:00"
}
],
"links": {
"first": "...",
"last": "...",
"prev": null,
"next": "..."
},
"meta": {
"current_page": 1,
"last_page": 5,
"per_page": 15,
"total": 72
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a mod.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns full details for a single mod, including category ratings (gameplay, performance, aesthetics), platform-specific data from CurseForge and Modrinth (descriptions, authors, screenshots, download counts), taxonomy tags (genres, features, themes), and external links.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v1/mods/create" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v1/mods/create"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v1/mods/create';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v1/mods/create'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Success):
{
"data": {
"id": 1,
"name": "Create",
"slug": "create",
"summary": "Aesthetic Technology that empowers the Player",
"type": "mod",
"logo_url": "https://...",
"license": "Create Mod License",
"average_rating": 4.5,
"gameplay_rating": 4,
"performance_rating": 4.5,
"aesthetics_rating": 5,
"total_ratings": 12,
"total_reviews": 8,
"written_reviews_count": 8,
"downloads_count": 500000,
"minecraft_versions": [
"1.20.1",
"1.21.1"
],
"mod_loaders": [
"Forge",
"NeoForge"
],
"genres": [
"Tech"
],
"features": [
"Automation & Processing",
"Building Improvements",
"Redstone Improvements"
],
"themes": [
"Industrial",
"Steampunk/Dieselpunk"
],
"platform_urls": {
"curseforge": "https://...",
"modrinth": null,
"source": null,
"issues": null,
"wiki": null,
"discord": null
},
"curseforge": {
"id": 328085,
"description": "<p>Full HTML description...</p>",
"authors": [
{
"name": "simibubi",
"url": null
}
],
"screenshots": [],
"downloads_count": 500000,
"updated_at": "2026-03-15T00:00:00+00:00",
"created_at": "2023-01-01T00:00:00+00:00",
"delisted_at": null
},
"modrinth": null,
"last_updated_at": "2026-03-15T00:00:00+00:00",
"curseforge_created_at": "2023-01-01T00:00:00+00:00"
}
}
Example response (404, Not Found):
{
"message": "Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List mod reviews.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns paginated written reviews for a mod. Only approved, published reviews with written content are included. Quick ratings (star-only, no text) and pending/rejected reviews are excluded. Each review includes category ratings, the author's Minecraft version and playtime context, and community vote counts.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v1/mods/create/reviews?sort=created_at&direction=desc&per_page=15" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v1/mods/create/reviews"
);
const params = {
"sort": "created_at",
"direction": "desc",
"per_page": "15",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v1/mods/create/reviews';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'sort' => 'created_at',
'direction' => 'desc',
'per_page' => '15',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v1/mods/create/reviews'
params = {
'sort': 'created_at',
'direction': 'desc',
'per_page': '15',
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Success):
{
"data": [
{
"id": 1,
"is_quick_rating": false,
"title": "Amazing mod!",
"content": "This mod completely changed how I play Minecraft...",
"rating": 4.5,
"gameplay_rating": 4,
"performance_rating": 4.5,
"aesthetics_rating": 5,
"minecraft_version": "1.20.1",
"playtime_hours": 500,
"play_status": "completed",
"pack_version": null,
"helpful_votes": 5,
"unhelpful_votes": 0,
"is_verified_developer": false,
"author": {
"id": 1,
"name": "Steve"
},
"project": {
"id": 1,
"name": "Create",
"slug": "create",
"type": "mod"
},
"created_at": "2026-03-01T00:00:00+00:00",
"edited_at": null,
"public_moderator_note": null
}
],
"links": {
"first": "...",
"last": "...",
"prev": null,
"next": "..."
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 3
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Show a modpack.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns full details for a single modpack, including category ratings (gameplay, performance, aesthetics), platform-specific data from CurseForge and Modrinth (descriptions, authors, screenshots, download counts), taxonomy tags (genres, features, themes), and external links.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v1/modpacks/rlcraft" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v1/modpacks/rlcraft"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v1/modpacks/rlcraft';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v1/modpacks/rlcraft'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Success):
{
"data": {
"id": 42,
"name": "RLCraft",
"slug": "rlcraft",
"summary": "A hardcore survival modpack.",
"type": "modpack",
"logo_url": "https://...",
"license": "All Rights Reserved",
"average_rating": 4.7,
"gameplay_rating": 4.8,
"performance_rating": 4.2,
"aesthetics_rating": 4.5,
"total_ratings": 230,
"total_reviews": 95,
"written_reviews_count": 95,
"downloads_count": 25000000,
"minecraft_versions": [
"1.12.2"
],
"mod_loaders": [
"Forge"
],
"genres": [
"Adventure/Exploration",
"Survival",
"RPG",
"Magic"
],
"features": [
"Difficulty: Challenging",
"Realism & Immersion",
"Dragons",
"Combat Focused"
],
"themes": [
"Fantasy",
"Medieval"
],
"platform_urls": {
"curseforge": "https://...",
"modrinth": null,
"source": null,
"issues": null,
"wiki": null,
"discord": null
},
"curseforge": {
"id": 285109,
"description": "<p>Full HTML description...</p>",
"authors": [
{
"name": "Shivaxi",
"url": null
}
],
"screenshots": [],
"downloads_count": 25000000,
"updated_at": "2026-03-15T00:00:00+00:00",
"created_at": "2019-01-01T00:00:00+00:00",
"delisted_at": null
},
"modrinth": null,
"last_updated_at": "2026-03-15T00:00:00+00:00",
"curseforge_created_at": "2019-01-01T00:00:00+00:00"
}
}
Example response (404, Not Found):
{
"message": "Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
List modpack reviews.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns paginated written reviews for a modpack. Only approved, published reviews with written content are included. Quick ratings (star-only, no text) and pending/rejected reviews are excluded. Each review includes category ratings, the author's Minecraft version and playtime context, and community vote counts.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v1/modpacks/rlcraft/reviews?sort=created_at&direction=desc&per_page=15" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v1/modpacks/rlcraft/reviews"
);
const params = {
"sort": "created_at",
"direction": "desc",
"per_page": "15",
};
Object.keys(params)
.forEach(key => url.searchParams.append(key, params[key]));
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v1/modpacks/rlcraft/reviews';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
'query' => [
'sort' => 'created_at',
'direction' => 'desc',
'per_page' => '15',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v1/modpacks/rlcraft/reviews'
params = {
'sort': 'created_at',
'direction': 'desc',
'per_page': '15',
}
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers, params=params)
response.json()Example response (200, Success):
{
"data": [
{
"id": 7,
"is_quick_rating": false,
"title": "Brutal but rewarding",
"content": "RLCraft is the hardest modpack I've ever played...",
"rating": 4.5,
"gameplay_rating": 4.8,
"performance_rating": 4,
"aesthetics_rating": 4.5,
"minecraft_version": "1.12.2",
"playtime_hours": 320,
"play_status": "completed",
"pack_version": "2.9.3",
"helpful_votes": 18,
"unhelpful_votes": 1,
"is_verified_developer": false,
"author": {
"id": 1,
"name": "Steve"
},
"project": {
"id": 42,
"name": "RLCraft",
"slug": "rlcraft",
"type": "modpack"
},
"created_at": "2026-03-01T00:00:00+00:00",
"edited_at": null,
"public_moderator_note": null
}
],
"links": {
"first": "...",
"last": "...",
"prev": null,
"next": "..."
},
"meta": {
"current_page": 1,
"last_page": 1,
"per_page": 15,
"total": 3
}
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Reviews
Endpoints for browsing community reviews.
Show a review.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns full details for a single review by ID. Only approved reviews on a live project are accessible; pending or rejected reviews, and reviews of a removed project, return 404. Includes the review author, associated project, category ratings, Minecraft version context, playtime, and community vote counts.
Example request:
curl --request GET \
--get "https://moddex.gg/api/v1/reviews/1" \
--header "Authorization: Bearer {YOUR_AUTH_KEY}" \
--header "Content-Type: application/json" \
--header "Accept: application/json"const url = new URL(
"https://moddex.gg/api/v1/reviews/1"
);
const headers = {
"Authorization": "Bearer {YOUR_AUTH_KEY}",
"Content-Type": "application/json",
"Accept": "application/json",
};
fetch(url, {
method: "GET",
headers,
}).then(response => response.json());$client = new \GuzzleHttp\Client();
$url = 'https://moddex.gg/api/v1/reviews/1';
$response = $client->get(
$url,
[
'headers' => [
'Authorization' => 'Bearer {YOUR_AUTH_KEY}',
'Content-Type' => 'application/json',
'Accept' => 'application/json',
],
]
);
$body = $response->getBody();
print_r(json_decode((string) $body));import requests
import json
url = 'https://moddex.gg/api/v1/reviews/1'
headers = {
'Authorization': 'Bearer {YOUR_AUTH_KEY}',
'Content-Type': 'application/json',
'Accept': 'application/json'
}
response = requests.request('GET', url, headers=headers)
response.json()Example response (200, Success):
{
"data": {
"id": 1,
"is_quick_rating": false,
"title": "Amazing mod!",
"content": "This mod completely changed how I play Minecraft...",
"rating": 4.5,
"gameplay_rating": 4,
"performance_rating": 4.5,
"aesthetics_rating": 5,
"minecraft_version": "1.20.1",
"playtime_hours": 500,
"play_status": "completed",
"pack_version": null,
"helpful_votes": 5,
"unhelpful_votes": 0,
"is_verified_developer": false,
"author": {
"id": 1,
"name": "Steve"
},
"project": {
"id": 1,
"name": "Create",
"slug": "create",
"type": "mod"
},
"created_at": "2026-03-01T00:00:00+00:00",
"edited_at": null,
"public_moderator_note": null
}
}
Example response (404, Not Found):
{
"message": "Not Found"
}
Received response:
Request failed with error:
Tip: Check that you're properly connected to the network.
If you're a maintainer of ths API, verify that your API is running and you've enabled CORS.
You can check the Dev Tools console for debugging information.
Tags
Endpoints for browsing project taxonomy tags (genres, features, themes, mod loaders, Minecraft versions).
List tags.
requires authentication deprecated:v1 is switched off six months after v2 becomes generally available. Use v2.
Returns the taxonomy tags used to categorize projects. Filter by type to get a specific category: genre (Technology, Magic, Adventure...), feature (Redstone, Worldgen, Mobs...), theme (Automation, Exploration...), or dev_environment. Mod loaders and Minecraft versions are not tags. Read the mod_loaders and minecraft_versions fields on project responses instead.
Recipes
These are worked examples of the integrations people build most often. The code is TypeScript using fetch, typed with a client generated from the OpenAPI spec:
npx openapi-typescript https://moddex.gg/api/docs.openapi -o moddex.d.ts
Every recipe uses this small helper. A 404 from a lookup means "not on ModDex", so it returns null; anything else that isn't a success throws with the error code.
import type { components } from "./moddex";
export type Schemas = components["schemas"];
const API = "https://moddex.gg/api/v2";
export async function moddex<T>(path: string, init: RequestInit = {}): Promise<T | null> {
const response = await fetch(API + path, {
...init,
headers: { "X-Client": "my-app/1.0.0", ...init.headers },
});
if (response.status === 404) {
return null;
}
if (!response.ok) {
const error = (await response.json()) as Schemas["Error"];
throw new Error(`ModDex ${response.status} ${error.code}: ${error.message}`);
}
return (await response.json()) as T;
}
Browser extension on Modrinth or CurseForge
On a project page, one request gets the rating, the links and the newest reviews. Take the slug from the page URL:
const slug = location.pathname.split("/")[2]; // modrinth.com/mod/sodium
const page = await moddex<Schemas["LookupReviewListResponse"]>(`/lookup/modrinth/${encodeURIComponent(slug)}/reviews?per_page=5`);
if (page !== null) {
const { rating, links } = page.meta.project;
// rating.average is null when nobody has rated the project yet.
renderSummary(rating.average, rating.count, links.web, links.write_review);
page.data.forEach(renderReview);
}
GET /api/v2/lookup/modrinth/sodium/reviews?per_page=5
{
"data": [{"id": 77, "title": "Essential", "content_html": "<p>Doubles my FPS.</p>", "rating": 5, "author": {"name": "Steve", "profile_url": "https://moddex.gg/user/steve"}}],
"meta": {
"current_page": 1, "last_page": 7, "per_page": 5, "total": 31,
"project": {"id": 1234, "name": "Sodium", "rating": {"average": 4.8, "bayesian": 4.6, "count": 52, "written_count": 31}, "links": {"web": "https://moddex.gg/mod/sodium", "write_review": "https://moddex.gg/mod/sodium#review-form"}},
"matched": {"key": "modrinth_slug", "value": "sodium", "via_facet": false, "via_alias": false, "alternatives": []}
}
}
(Shortened: every object carries all its fields; see "Look up by platform and value, with the project's reviews".)
On a list page (search results, a collection), look the whole page up in one batch. Links carry the project type, so pass the cards' links rather than bare slugs, and sort them so the same page hits the same cache entry:
const urls = [...document.querySelectorAll<HTMLAnchorElement>("a.project-card")].map((a) => a.href).sort();
const batch = await moddex<Schemas["BatchLookupResponse"]>(`/lookup/batch?urls=${urls.map(encodeURIComponent).join(",")}`);
for (const [url, project] of Object.entries(batch?.data.urls ?? {})) {
if (project !== null && !("ambiguous" in project)) {
renderBadge(url, project.rating, project.links.web);
}
}
Encode each link on its own and join them with plain commas. If you encode the joined list (URLSearchParams, urlencode), the commas between links are encoded too, and the request is a 422.
Mount ModDex content in a Shadow DOM (see Output safety), and set anything that isn't *_html with textContent:
function renderReview(review: Schemas["Review"]): void {
const host = document.createElement("div");
const root = host.attachShadow({ mode: "closed" });
const title = document.createElement("h4");
title.textContent = review.title ?? "";
const body = document.createElement("div");
body.innerHTML = review.content_html ?? "";
root.append(title, body);
document.querySelector("#moddex-reviews")?.append(host);
}
Credit ModDex next to the reviews (see Attribution), and point "Write a review" at links.write_review.
The browser's HTTP cache does the caching for you and revalidates with the ETag. A project that isn't on ModDex returns a 404 that's cached for 60 seconds.
Launcher or mod manager
Show a rating next to each installed mod. Hash the jars in the mods folder and look them up 100 at a time:
import { createHash } from "node:crypto";
import { readFile, readdir } from "node:fs/promises";
const jars = (await readdir(modsDir)).filter((name) => name.endsWith(".jar"));
const sha1ByJar = new Map<string, string>();
for (const jar of jars) {
sha1ByJar.set(jar, createHash("sha1").update(await readFile(`${modsDir}/${jar}`)).digest("hex"));
}
const hashes = [...sha1ByJar.values()];
for (let start = 0; start < hashes.length; start += 100) {
const chunk = hashes.slice(start, start + 100).join(",");
const result = await moddex<Schemas["FileBatchLookupResponse"]>(`/lookup/files/batch?sha1=${chunk}`);
for (const [sha1, match] of Object.entries(result?.data.sha1 ?? {})) {
if (match !== null) {
showRating(sha1, match.project.rating, match.project.links.web);
}
}
}
SHA1 matching works for files published on Modrinth. For CurseForge files, use the file IDs your launcher already has from its CurseForge manifest: /lookup/files/batch?curseforge_file_id=5432101,5432102. ModDex doesn't store CurseForge fingerprints, so a CurseForge jar can't be matched by its content.
Discord bot
When someone pastes a link, look it up:
const found = await moddex<Schemas["ExplicitLookupResponse"]>(`/lookup?url=${encodeURIComponent(pastedLink)}`);
if (found !== null) {
reply(`${found.data.name}: ${found.data.rating.average ?? "unrated"} ★ (${found.data.rating.count} ratings) ${found.data.links.web}`);
}
For a search command, q takes 3 to 200 characters and sorts by relevance:
const results = await moddex<Schemas["ProjectListResponse"]>(`/projects?q=${encodeURIComponent(query)}&per_page=5`);
For a "new reviews" channel, follow the reviews sync feed and post the ones for projects you track. (Polling /v2/reviews?since= would miss reviews approved after moderation, because they keep the date they were written.) The feed lists a review when it becomes public and again whenever it changes, so keep track of what you've already posted:
const tracked = new Set([1234, 5678]);
const posted = new Set<number>();
const startedAt = new Date().toISOString();
let cursor: string | null = null; // store it between runs
async function postNewReviews(): Promise<void> {
for (;;) {
const page: Schemas["ReviewSyncResponse"] | null = await moddex<Schemas["ReviewSyncResponse"]>(cursor === null ? `/sync/reviews?since=${encodeURIComponent(startedAt)}` : `/sync/reviews?cursor=${encodeURIComponent(cursor)}`);
if (page === null) {
return;
}
for (const review of page.data) {
if (tracked.has(review.project.id) && !posted.has(review.id)) {
posted.add(review.id);
post(`${review.project.name}: ${review.rating} ★ ${review.url}`);
}
}
cursor = page.meta.next_cursor;
if (!page.meta.has_more) {
return;
}
}
}
The first call starts from since, so the bot only posts reviews from when it started. After that, call it every few minutes. A review reaches the feed 5 minutes after it changes.
Run a bot from a server with a token, and ask for a higher limit if many servers use it.
Website widget
To show staff picks with their blurbs:
const picks = await moddex<Schemas["ProjectListResponse"]>("/projects?featured=1&per_page=6");
picks?.data.forEach((project) => card(project.name, project.featured?.blurb ?? project.summary, project.links.web));
In a README, use the rating badge. The links.badge URL is an SVG that always shows the current rating.
[](https://moddex.gg/mod/sodium?ref=my-readme)
Catalog UI
Build the filter panel from /v2/catalog/filters: every parameter, its type, whether it takes a list, its _exclude and any/all companions, and the valid values for small vocabularies. Every slug in a response is a valid filter value, so "more like this" is one step:
const project = await moddex<Schemas["ProjectResponse"]>("/projects/1234");
if (project !== null && project.data.genres.length > 0) {
const genres = project.data.genres.map((genre) => genre.slug).join(",");
const more = await moddex<Schemas["ProjectListResponse"]>(`/projects?type=${project.data.type}&genres=${genres}&genres_mode=any`);
}
Migrating from v1
v1 (/api/v1) is frozen: it gets security fixes only and is switched off six months after v2 becomes generally available. After that, v1 answers 410 with code: api_version_retired. Until then, v1 responses carry Deprecation and Sunset headers once the date is set.
The main differences:
- v2 is public. v1 needed a token from a verified account; in v2 a token only raises your limits.
mods/{slug}andmodpacks/{slug}are gone. Lookup replaces both, and takes ModDex, CurseForge and Modrinth IDs, slugs and links.- An unrated project's averages are
nullinstead of0.0. - Descriptions, rating histograms and follower counts are left out unless you ask for them with
include. - Genres, features, themes, loaders and environments are
{slug, name}objects. v1 returned names only. - Review text is masked by default. Add
unmasked=1to get the raw text v1 returned. - Every error has the same shape, with a stable
code(see Conventions).
Routes
| v1 | v2 |
|---|---|
GET /v1/projects |
GET /v2/projects (default sort is now bayesian_rating desc, not name) |
GET /v1/mods/{slug} |
GET /v2/lookup/moddex/{slug}?type=mod |
GET /v1/modpacks/{slug} |
GET /v2/lookup/moddex/{slug}?type=modpack |
GET /v1/mods/{slug}/reviews |
GET /v2/lookup/moddex/{slug}/reviews?type=mod |
GET /v1/modpacks/{slug}/reviews |
GET /v2/lookup/moddex/{slug}/reviews?type=modpack |
GET /v1/reviews/{id} |
GET /v2/reviews/{id} |
GET /v1/tags |
GET /v2/tags (genres, features, themes, environments; type=dev_environment is now type=environment), /v2/loaders, /v2/minecraft-versions |
GET /api/user |
unchanged; still the way to check a token |
Project fields
| v1 | v2 |
|---|---|
average_rating (0.0 when unrated) |
rating.average (null when unrated) |
bayesian_rating |
rating.bayesian |
total_ratings |
rating.count |
total_reviews, written_reviews_count |
rating.written_count |
gameplay_rating, performance_rating, aesthetics_rating |
ratings.categories.* with include=ratings (histograms; the average is the count-weighted mean) |
mod_loaders[] (names) |
loaders[] ({slug, name}) |
genres[], features[], themes[] (names) |
genres[], features[], themes[] ({slug, name}) |
platform_urls.curseforge, platform_urls.modrinth |
curseforge.url, modrinth.url |
platform_urls.source, .issues, .wiki, .discord |
unchanged |
curseforge.description |
curseforge.description_html with include=description |
modrinth.description |
modrinth.description and modrinth.description_html with include=description |
curseforge.authors, modrinth.authors |
authors[]: one credit list with each platform's URL and username |
curseforge_created_at |
curseforge.created_at; published_at is the earliest platform date |
sources[].mod_loaders (names) |
sources[].loaders ({slug, name}) |
license (a string) |
license.name, with license.open_source and license.categories |
| (none) | available, links, featured, counts, latest_version, environment, community_tags_count |
Review fields
| v1 | v2 |
|---|---|
content (raw) |
content (masked unless unmasked=1) and content_html (sanitized) |
gameplay_rating, performance_rating, aesthetics_rating |
categories.gameplay, .performance, .aesthetics |
author: {id, name} |
author: {id, name, username, avatar_url, profile_url, roles, reputation} |
project: {id, name, slug, type} |
project: the project summary, with rating and links |
| (none) | content_html, completion_hours, images, developer_response, url, updated_at |
Review sorts change from sort=created_at|rating|helpful_votes|unhelpful_votes plus direction to sort=newest|oldest|rating|helpful, and per_page defaults to 20 instead of 15.
What each version lists
/v1/projects lists every project whose status is active. /v2/projects lists what the website's catalog lists: it leaves out projects delisted on every platform, and includes staff-archived ones. Looking a project up directly works the same in both, delisted or not; v2 marks a delisted project available: false, and gives null for the URL of a listing its platform no longer shows.
API changelog
Additive changes (a new endpoint, field, parameter, include block or error code) ship at any time and are listed here. Build clients that ignore fields they don't know. Breaking changes (removing or renaming anything, changing a type or a default) only come with a new version: the old one keeps working for at least six months, and says so in Deprecation and Sunset headers. Changes are announced in the ModDex Discord.
2026-10-19: v2 public launch
- v2 is public: no token needed, per-IP limits, CORS for browser clients.
- Lookup by ModDex, CurseForge and Modrinth ID, slug and link, singly, combined or in batches of 100; lookup by Modrinth SHA1 and CurseForge file ID.
- Catalog search with every website filter, plus
/v2/catalog/filters,/v2/minecraft-versions,/v2/loadersand/v2/tags. - Projects: files, dependencies, dependents, modpack contents, similar projects and community tags.
- Reviews: per project and a global newest-first list.
- Cursor sync feeds for projects and reviews, with tombstones and a review ID list.
- A typed OpenAPI 3.1 spec.
- v1 is deprecated. See Migrating from v1.
Attribution
When you show ModDex ratings or reviews, credit ModDex where you show them:
- the words "Reviews from ModDex", linked to the project's
links.web - optionally, the ModDex logo next to them
?ref=<your-app>on links back to ModDex, so we can see which integrations send readers and tell you
Logos, served from ModDex itself (no third-party request):
| Asset | SVG | PNG |
|---|---|---|
| Icon | moddex-icon.svg | moddex-icon-512.png |
| Wordmark, for dark backgrounds | moddex-logo-on-dark.svg | moddex-logo-on-dark.png |
| Wordmark, for light backgrounds | moddex-logo-on-light.svg | moddex-logo-on-light.png |
Don't recolor or distort the logo. The rating badge (links.badge) is the simplest way to show a live rating anywhere an image can go.
Using the API means accepting the Terms of Service, including their API section: personal and non-commercial use only, credit ModDex, and remove content within 7 days of its removal from ModDex.