API
Resources
Responses and Error Handling
If there is an error, the response will be JSON similar to the following with a non-200 status code:
{
"success": false,
"error": "The error message"
}
Successful GET requests will return the resource's information directly as a JSON response.
Other successful results will return a dictionary with success
equaling true, and
often other keys with information. For example:
{
"success": true,
"release": {
/* same as returned by a GET */
}
}
Paginated Results
Some API endpoints returns results in pages. The page number is specified using the page
query argument, and
the number of items is specified using num
The response will be a dictionary with the following keys:
page
: page number, integer from 1 to maxper_page
: number of items per page, same asn
page_count
: number of pagestotal
: total number of resultsurls
: dictionary containingnext
: url to next pageprevious
: url to previous page
items
: array of items
Authentication
Not all endpoints require authentication, but it is done using Bearer tokens:
curl https://content.luanti.org/api/whoami/ \
-H "Authorization: Bearer YOURTOKEN"
Tokens can be attained by visiting Settings > API Tokens.
- GET
/api/whoami/
: JSON dictionary with the following keys:is_authenticated
: True on successful API authenticationusername
: Username of the user authenticated as, null otherwise.- 4xx status codes will be thrown on unsupported authentication type, invalid access token, or other errors.
- DELETE
/api/delete-token/
: Deletes the currently used token.
# Logout
curl -X DELETE https://content.luanti.org/api/delete-token/ \
-H "Authorization: Bearer YOURTOKEN"
Packages
- GET
/api/packages/
(List)- See Package Queries
- GET
/api/packages/<username>/<name>/
(Read)- Redirects a JSON object with the keys documented by the PUT endpoint, below.
- Plus:
forum_url
: String or null.
- PUT
/api/packages/<author>/<name>/
(Update)- Requires authentication.
- JSON object with any of these keys (all are optional, null to delete Nullables):
type
: One ofGAME
,MOD
,TXP
.title
: Human-readable title.name
: Technical name (needs permission if already approved).short_description
dev_state
: One ofWIP
,BETA
,ACTIVELY_DEVELOPED
,MAINTENANCE_ONLY
,AS_IS
,DEPRECATED
,LOOKING_FOR_MAINTAINER
.tags
: List of tag names.content_warnings
: List of content warning names.license
: A license name.media_license
: A license name.long_description
: Long markdown description.repo
: Source repository (eg: Git)website
: Website URL.issue_tracker
: Issue tracker URL.forums
: forum topic ID.video_url
: URL to a video.donate_url
: URL to a donation page.translation_url
: URL to send users interested in translating your package.game_support
: Array of game support information objects. Not currently documented,
- Returns a JSON object with:
success
package
: updated packagewas_modified
: bool, whether anything changed
- GET
/api/packages/<username>/<name>/for-client/
- Similar to the read endpoint, but optimised for the Luanti client
long_description
is given as a hypertext object, see/hypertext/
below.info_hypertext
is the info sidebar as a hypertext object.- Query arguments
formspec_version
: Required. See /hypertext/ below.include_images
: Optional, defaults to true. If true, images use<img>
. If false, they're linked.protocol_version
: Optional, used to get the correct release.engine_version
: Optional, used to get the correct release. Ex:5.3.0
.
- GET
/api/packages/<author>/<name>/hypertext/
- Converts the long description to Luanti Markup Language
to be used in a
hypertext
formspec element. - Query arguments:
formspec_version
: Required, maximum supported formspec version.include_images
: Optional, defaults to true. If true, images use<img>
. If false, they're linked.
- Returns JSON dictionary with following key:
head
: markup for suggested styling and custom tags, prepend to the body before displaying.body
: markup for long description.links
: dictionary of anchor name to link URL.images
: dictionary of img name to image URLimage_tooltips
: dictionary of img name to tooltip text.
- Converts the long description to Luanti Markup Language
to be used in a
- GET
/api/packages/<username>/<name>/dependencies/
- Returns dependencies, with suggested candidates
- If query argument
only_hard
is present, only hard deps will be returned.
- GET
/api/dependencies/
- Returns
provides
and raw dependencies for all packages. - Supports Package Queries
- Paginated result, max 300 results per page
- Each item in
items
will be a dictionary with the following keys:type
: One ofGAME
,MOD
,TXP
.author
: Username of the package author.name
: Package name.provides
: List of technical mod names inside the package.depends
: List of hard dependencies.- Each dep will either be a modname dependency (
name
), or a package dependency (author/name
).
- Each dep will either be a modname dependency (
optional_depends
: list of optional dependencies- Same as above.
- Returns
- GET
/api/packages/<username>/<name>/stats/
- Returns daily stats for package, or null if there is no data.
- Daily date is done based on the UTC timezone.
- EXPERIMENTAL. This API may change without warning.
- Query args:
start
: start date, inclusive. Optional. Default: 2022-10-01. UTC.end
: end date, inclusive. Optional. Default: today. UTC.
- An object with the following keys:
start
: start date, inclusive. Ex: 2022-10-22. Mend
: end date, inclusive. Ex: 2022-11-05.platform_minetest
: list of integers per day.platform_other
: list of integers per day.reason_new
: list of integers per day.reason_dependency
: list of integers per day.reason_update
: list of integers per day.
- GET
/api/package_stats/
- Returns last 30 days of daily stats for all packages.
- An object with the following keys:
start
: start date, inclusive. Ex: 2022-10-22.end
: end date, inclusive. Ex: 2022-11-05.package_downloads
: map from package key to list of download integers.
You can download a package by building one of the two URLs:
https://content.luanti.org/packages/${author}/${name}/download/`
https://content.luanti.org/packages/${author}/${name}/releases/${release}/download/`
Examples:
# Edit package
curl -X PUT https://content.luanti.org/api/packages/username/name/ \
-H "Authorization: Bearer YOURTOKEN" -H "Content-Type: application/json" \
-d '{ "title": "Foo bar", "tags": ["pvp", "survival"], "license": "MIT" }'
# Remove website URL
curl -X PUT https://content.luanti.org/api/packages/username/name/ \
-H "Authorization: Bearer YOURTOKEN" -H "Content-Type: application/json" \
-d '{ "website": null }'
Package Queries
Example:
/api/packages/?type=mod&type=game&q=mobs+fun&hide=nonfree&hide=gore
Filter query parameters:
type
: Filter by package type (mod
,game
,txp
). Multiple types are OR-ed together.q
: Query string.author
: Filter by author.tag
: Filter by tags. Multiple tags are AND-ed together.flag
: Filter to show packages with Content Flags.hide
: Hide content based on tags or Content Flags.license
: Filter by license name. Multiple licenses are OR-ed together, ie:&license=MIT&license=LGPL-2.1-only
game
: Filter by Game Support, ex:Warr1024/nodecore
. (experimental, doesn't show items that support every game currently).lang
: Filter by translation support, eg:en
/de
/ja
/zh_TW
.protocol_version
: Only show packages supported by this Luanti protocol version.engine_version
: Only show packages supported by this Luanti engine version, eg:5.3.0
.
Sorting query parameters:
sort
: Sort by (name
,title
,score
,reviews
,downloads
,created_at
,approved_at
,last_release
).order
: Sort ascending (asc
) or descending (desc
).random
: When present, enable random ordering and ignoresort
.
Format query parameters:
limit
: Return at mostlimit
packages.fmt
: How the response is formatted.keys
: author/name only.short
: stuff needed for the Luanti client.vcs
:short
but withrepo
.
Releases
- GET
/api/releases/
(List)- Limited to 30 most recent releases.
- Optional arguments:
author
: Filter by authormaintainer
: Filter by maintainer
- Returns array of release dictionaries with keys:
id
: release IDname
: short release nametitle
: human-readable titlerelease_notes
: string or null, what's new in this release. Markdown.release_date
: Date releasedurl
: download URLcommit
: commit hash or nulldownloads
: number of downloadsmin_minetest_version
: dict or null, minimum supported Luanti version (inclusive).max_minetest_version
: dict or null, minimum supported Luanti version (inclusive).size
: size of zip file, in bytes.package
author
: author usernamename
: technical nametype
:mod
,game
, ortxp
- GET
/api/updates/
(Look-up table)- Returns a look-up table from package key (
author/name
) to latest release id - Query arguments
protocol_version
: Only show packages supported by this Luanti protocol version.engine_version
: Only show packages supported by this Luanti engine version, eg:5.3.0
.
- Returns a look-up table from package key (
- GET
/api/packages/<username>/<name>/releases/
(List)- Returns array of release dictionaries, see above, but without package info.
- GET
/api/packages/<username>/<name>/releases/<id>/
(Read) - POST
/api/packages/<username>/<name>/releases/new/
(Create)- Requires authentication.
- Body can be JSON or multipart form data. Zip uploads must be multipart form data.
title
: human-readable name of the release.release_notes
: string or null, what's new in this release.- For Git release creation:
method
: must begit
.ref
: (Optional) git reference, eg:master
.
- For zip upload release creation:
file
: multipart file to upload, like<input type="file" name="file">
.commit
: (Optional) Source Git commit hash, for informational purposes.
- You can set min and max Luanti Versions using the content's .conf file.
- DELETE
/api/packages/<username>/<name>/releases/<id>/
(Delete)- Requires authentication.
- Deletes release.
Examples:
# Create release from Git
curl -X POST https://content.luanti.org/api/packages/username/name/releases/new/ \
-H "Authorization: Bearer YOURTOKEN" -H "Content-Type: application/json" \
-d '{
"method": "git",
"name": "1.2.3",
"title": "My Release",
"ref": "master",
"release_notes": "some\nrelease\nnotes\n"
}'
# Create release from zip upload
curl -X POST https://content.luanti.org/api/packages/username/name/releases/new/ \
-H "Authorization: Bearer YOURTOKEN" \
-F title="My Release" -F file=@path/to/file.zip
# Create release from zip upload with commit hash
curl -X POST https://content.luanti.org/api/packages/username/name/releases/new/ \
-H "Authorization: Bearer YOURTOKEN" \
-F title="My Release" -F commit="8ef74deec170a8ce789f6055a59d43876d16a7ea" -F file=@path/to/file.zip
# Delete release
curl -X DELETE https://content.luanti.org/api/packages/username/name/releases/3/ \
-H "Authorization: Bearer YOURTOKEN"
Screenshots
- GET
/api/packages/<username>/<name>/screenshots/
(List)- Returns array of screenshot dictionaries with keys:
id
: screenshot IDapproved
: true if approved and visible.title
: human-readable name for the screenshot, shown as a caption and alt text.url
: absolute URL to screenshot.created_at
: ISO time.order
: Number used in ordering.is_cover_image
: true for cover image.
- Returns array of screenshot dictionaries with keys:
- GET
/api/packages/<username>/<name>/screenshots/<id>/
(Read)- Returns screenshot dictionary like above.
- POST
/api/packages/<username>/<name>/screenshots/new/
(Create)- Requires authentication.
- Body is multipart form data.
title
: human-readable name for the screenshot, shown as a caption and alt text.file
: multipart file to upload, like<input type=file>
.is_cover_image
: set cover image to this.
- DELETE
/api/packages/<username>/<name>/screenshots/<id>/
(Delete)- Requires authentication.
- Deletes screenshot.
- POST
/api/packages/<username>/<name>/screenshots/order/
- Requires authentication.
- Body is a JSON array containing the screenshot IDs in their order.
- POST
/api/packages/<username>/<name>/screenshots/cover-image/
- Requires authentication.
- Body is a JSON dictionary with "cover_image" containing the screenshot ID.
Currently, to get a different size of thumbnail you can replace the number in /thumbnails/1/
with any number from 1-3.
The resolutions returned may change in the future, and we may move to a more capable thumbnail generation.
Examples:
# Create screenshot
curl -X POST https://content.luanti.org/api/packages/username/name/screenshots/new/ \
-H "Authorization: Bearer YOURTOKEN" \
-F title="My Release" -F file=@path/to/screnshot.png
# Create screenshot and set it as the cover image
curl -X POST https://content.luanti.org/api/packages/username/name/screenshots/new/ \
-H "Authorization: Bearer YOURTOKEN" \
-F title="My Release" -F file=@path/to/screnshot.png -F is_cover_image="true"
# Delete screenshot
curl -X DELETE https://content.luanti.org/api/packages/username/name/screenshots/3/ \
-H "Authorization: Bearer YOURTOKEN"
# Reorder screenshots
curl -X POST https://content.luanti.org/api/packages/username/name/screenshots/order/ \
-H "Authorization: Bearer YOURTOKEN" -H "Content-Type: application/json" \
-d "[13, 2, 5, 7]"
# Set cover image
curl -X POST https://content.luanti.org/api/packages/username/name/screenshots/cover-image/ \
-H "Authorization: Bearer YOURTOKEN" -H "Content-Type: application/json" \
-d "{ 'cover_image': 123 }"
Reviews
- GET
/api/packages/<username>/<name>/reviews/
(List)- Returns array of review dictionaries with keys:
user
: dictionary withdisplay_name
andusername
.title
: review titlecomment
: the textrating
: 1 for negative, 3 for neutral, 5 for positiveis_positive
: booleancreated_at
: iso timestampvotes
: dictionary withhelpful
andunhelpful
,
- Returns array of review dictionaries with keys:
- GET
/api/reviews/
(List)- Returns a paginated response. This is a dictionary with
page
,url
, anditems
.- Paginated result
items
: array of review dictionaries, like above- Each review also has a
package
dictionary withtype
,author
andname
- Each review also has a
- Ordered by created at, newest to oldest.
- Query arguments:
page
: page number, integer from 1 to maxn
: number of results per page, max 200author
: filter by review author usernamefor_user
: filter by package authorrating
: 1 for negative, 3 for neutral, 5 for positiveis_positive
: true or false. Default: nullq
: filter by title (case-insensitive, no fulltext search)
- Returns a paginated response. This is a dictionary with
Example:
[
{
"comment": "This is a really good mod!",
"created_at": "2021-11-24T16:18:33.764084",
"is_positive": true,
"title": "Really good",
"user": {
"display_name": "rubenwardy",
"username": "rubenwardy"
},
"votes": {
"helpful": 0,
"unhelpful": 0
}
}
]
Users
- GET
/api/users/<username>/
username
display_name
: human-readable name to be displayed in GUIs.rank
: ContentDB rank.profile_pic_url
: URL to profile picture, or null.website_url
: URL to website, or null.donate_url
: URL to donate page, or null.connections
: objectgithub
: GitHub username, or null.forums
: forums username, or null.
links
: objectapi_packages
: URL to API to list this user's packages.profile
: URL to the HTML profile page.
- GET
/api/users/<username>/stats/
- Returns daily stats for the user's packages, or null if there is no data.
- Daily date is done based on the UTC timezone.
- EXPERIMENTAL. This API may change without warning.
- Query args:
start
: start date, inclusive. Optional. Default: 2022-10-01. UTC.end
: end date, inclusive. Optional. Default: today. UTC.
- A table with the following keys:
from
: start date, inclusive. Ex: 2022-10-22.end
: end date, inclusive. Ex: 2022-11-05.package_downloads
: map of package title to list of integers per day.platform_minetest
: list of integers per day.platform_other
: list of integers per day.reason_new
: list of integers per day.reason_dependency
: list of integers per day.reason_update
: list of integers per day.
Topics
- GET
/api/topics/
(View)- See Topic Queries
Topic Queries
Example:
/api/topics/?q=mobs&type=mod&type=game
Supported query parameters:
q
: Query string.type
: Package types (mod
,game
,txp
).sort
: Sort by (name
,views
,created_at
).show_added
: Show topics that have an existing package.limit
: Return at mostlimit
topics.
Collections
- GET
/api/collections/
- Query args:
author
: collection author username.package
: collections that contain the package.
- Returns JSON array of collection entries:
author
: author username.name
: collection name.title
short_description
created_at
: creation time in iso format.private
: whether collection is private, boolean.package_count
: number of packages, integer.
- Query args:
- GET
/api/collections/<username>/<name>/
- Returns JSON object for collection:
author
: author username.name
: collection name.title
short_description
long_description
created_at
: creation time in iso format.private
: whether collection is private, boolean.items
: array of item objects:package
: short info about the package.description
: custom short description.created_at
: when the package was added to the collection.order
: integer.
- Returns JSON object for collection:
Types
Tags
- GET
/api/tags/
(View)- List of objects with:
name
: technical name.title
: human-readable title.description
: tag description or null.views
: number of views of this tag.
- List of objects with:
Content Warnings
- GET
/api/content_warnings/
(View)- List of objects with
name
: technical nametitle
: human-readable titledescription
: tag description or null
- List of objects with
Licenses
- GET
/api/licenses/
(View)- List of objects with:
name
is_foss
: whether the license is foss
- List of objects with:
Luanti Versions
- GET
/api/minetest_versions/
(View)- List of objects with:
name
: Version name.is_dev
: boolean, is dev version.protocol_version
: protocol version number.
- List of objects with:
Languages
- GET
/api/languages/
(View)- List of objects with:
id
: language code.title
: native language name.has_contentdb_translation
: whether ContentDB has been translated into this language.
- List of objects with:
Misc
- GET
/api/scores/
(View)- See Top Packages Algorithm.
- Supports Package Queries.
- Returns list of:
author
: package author name.name
: package technical name.downloads
: number of downloads.score
: total package score.score_reviews
: score from reviews.score_downloads
: score from downloads.reviews
: a dictionary ofpositive
: int, number of positive reviews.neutral
: int, number of neutral reviews.negative
: int, number of negative reviews.
- GET
/api/homepage/
(View) - get contents of homepage.count
: number of packagesdownloads
: get number of downloadsnew
: new packagesupdated
: recently updated packagespop_mod
: popular modspop_txp
: popular texturespop_game
: popular gameshigh_reviewed
: highest reviewed
- GET
/api/cdb_schema/
(View)- Get JSON Schema of
.cdb.json
, including licenses, tags and content warnings. - See JSON Schema Reference.
- Get JSON Schema of
- POST
/api/hypertext/
- Converts HTML or Markdown to Luanti Markup Language
to be used in a
hypertext
formspec element. - Post data: HTML or Markdown as plain text.
- Content-Type:
text/html
ortext/markdown
. - Query arguments:
formspec_version
: Required, maximum supported formspec version. Ie: 6include_images
: Optional, defaults to true. If true, images use<img>
. If false, they're linked.
- Returns JSON dictionary with following key:
head
: markup for suggested styling and custom tags, prepend to the body before displaying.body
: markup for long description.links
: dictionary of anchor name to link URL.images
: dictionary of img name to image URLimage_tooltips
: dictionary of img name to tooltip text.
- Converts HTML or Markdown to Luanti Markup Language
to be used in a