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 max
  • per_page: number of items per page, same as n
  • page_count: number of pages
  • total: total number of results
  • urls: dictionary containing
    • next: url to next page
    • previous: 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 authentication
    • username: 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)
  • 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 of GAME, MOD, TXP.
      • title: Human-readable title.
      • name: Technical name (needs permission if already approved).
      • short_description
      • dev_state: One of WIP, 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 package
      • was_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/<username>/<name>/for-client/reviews/
    • Returns hypertext representing the package's reviews
    • Query arguments
      • formspec_version: Required. See /hypertext/ below.
    • Returns JSON dictionary with following keys:
      • 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 URL.
      • image_tooltips: dictionary of img name to tooltip text.
    • The hypertext body contains some placeholders that should be replaced client-side:
      • <thumbsup> with a thumbs up icon.
      • <neutral> with a thumbs up icon.
      • <thumbsdown> with a thumbs up icon.
  • 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 keys:
      • 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 URL.
      • image_tooltips: dictionary of img name to tooltip text.
  • 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 of GAME, 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).
      • optional_depends: list of optional dependencies
        • Same as above.
  • 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. M
      • end: 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 ignore sort.

Format query parameters:

  • limit: Return at most limit packages.
  • fmt: How the response is formatted.
    • keys: author/name only.
    • short: stuff needed for the Luanti client.
    • vcs: short but with repo.

Releases 🔗

  • GET /api/releases/ (List)
    • Limited to 30 most recent releases.
    • Optional arguments:
      • author: Filter by author
      • maintainer: Filter by maintainer
    • Returns array of release dictionaries with keys:
      • id: release ID
      • name: short release name
      • title: human-readable title
      • release_notes: string or null, what's new in this release. Markdown.
      • release_date: Date released
      • url: download URL
      • commit: commit hash or null
      • downloads: number of downloads
      • min_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 username
        • name: technical name
        • type: mod, game, or txp
  • 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.
  • 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 be git.
      • 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 ID
      • approved: 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.
  • 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 with display_name and username.
      • title: review title
      • comment: the text
      • rating: 1 for negative, 3 for neutral, 5 for positive
      • is_positive: boolean
      • created_at: iso timestamp
      • votes: dictionary with helpful and unhelpful,
  • GET /api/reviews/ (List)
    • Returns a paginated response. This is a dictionary with page, url, and items.
      • Paginated result
      • items: array of review dictionaries, like above
        • Each review also has a package dictionary with type, author and name
      • Ordered by created at, newest to oldest.
    • Query arguments:
      • page: page number, integer from 1 to max
      • n: number of results per page, max 200
      • author: filter by review author username
      • for_user: filter by package author
      • rating: 1 for negative, 3 for neutral, 5 for positive
      • is_positive: true or false. Default: null
      • q: filter by title (case-insensitive, no fulltext search)

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: object
      • github: GitHub username, or null.
      • forums: forums username, or null.
    • links: object
      • api_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 🔗

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 most limit 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.
  • 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.

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.

Content Warnings 🔗

  • GET /api/content_warnings/ (View)
    • List of objects with
      • name: technical name
      • title: human-readable title
      • description: tag description or null

Licenses 🔗

  • GET /api/licenses/ (View)
    • List of objects with:
      • name
      • is_foss: whether the license is foss

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.

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.

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 of
        • positive: 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 packages
    • downloads: get number of downloads
    • new: new packages
    • updated: recently updated packages
    • pop_mod: popular mods
    • pop_txp: popular textures
    • pop_game: popular games
    • high_reviewed: highest reviewed
  • GET /api/cdb_schema/ (View)
    • Get JSON Schema of .cdb.json, including licenses, tags and content warnings.
    • See JSON Schema Reference.
  • 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 or text/markdown.
    • Query arguments:
      • formspec_version: Required, maximum supported formspec version. Ie: 6
      • 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 URL
      • image_tooltips: dictionary of img name to tooltip text.