Public API
The TRS API serves the launcher, the TRS Client and the website. A part of it is public: you can read it without an account, for example for a bot, a widget or a tool. This page lists only these public, read-only endpoints.
Basics
| Base URL | https://trs-launcher.theredstonee.de |
| Prefix | /v1 |
| Transport | HTTPS only |
| Format | JSON (UTF-8), except images and file downloads |
| UUIDs in responses | 32 lowercase hex digits without dashes |
| Timestamps | ISO 8601 in UTC, e.g. 2026-09-23T18:04:59.167Z |
Every response has an X-Request-Id header. Quote it if you report a problem.
Errors
Every error has the same shape. Branch on code, not on message:
{ "error": { "code": "not_found", "message": "Not found" } }
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | A parameter is invalid. |
| 404 | not_found (or a more specific code) | Unknown route or object. |
| 429 | rate_limited | Too many requests. Wait Retry-After seconds. |
| 500 | internal_error | Server error, without details. |
| 503 | database_unavailable | Temporary. Try again later. |
Rate limits
All limits are per IP address and refill evenly across the minute.
| Scope | Limit |
|---|---|
| Every request | 300 / min |
| Circuit library | 240 / min |
| Issues (lists, issues, roadmap, images) | 240 / min |
| Shared screenshots | 240 / min |
| Modpack codes | 60 / min |
| Achievement catalog | 60 / min |
| Blog images | 600 / min |
A 429 response carries the Retry-After header and error.retryAfter (seconds).
Caching
Many responses can be cached. Respect Cache-Control, and use ETag with If-None-Match where it is offered – an
unchanged resource then answers 304 with an empty body.
Status
GET /v1/health
{ "status": "ok", "version": 1, "time": "2026-09-29T10:00:00.000Z" }
503 database_unavailable if the database is down.
Releases
GET /v1/site/releases
The newest launcher release on GitHub with its download files. Cached for 5 minutes.
{
"release": {
"version": "0.14.0",
"tag": "v0.14.0",
"publishedAt": "2026-09-28T…",
"pageUrl": "https://github.com/theredstonee/TRS-Launcher/releases/tag/v0.14.0",
"assets": [
{ "platform": "windows", "name": "TRS-Launcher_0.14.0_x64-setup.exe", "url": "https://github.com/…", "size": 12345678 }
]
}
}
platform is windows, appimage, deb or rpm. release is null if GitHub couldn't be reached and nothing is
cached yet.
Capes
GET /v1/site/capes
The built-in TRS capes. Cached for 5 minutes.
{ "capes": [
{ "id": "redstone", "name": "Redstone", "unlock": "free", "url": "/v1/capes/redstone.png?v=0c1d…",
"scale": 2, "frames": 1, "frameTimeMs": null }
] }
unlock is free, code or admin. url is relative to the base URL.
GET /v1/capes/{id}
Metadata of one approved cape: { "cape": { id, name, kind, unlock, status, url, width, height, scale, animated, frames, frameTimeMs } }.
Unknown or not approved: 404 cape_not_found.
GET /v1/capes/{id}.png
The texture of an approved cape.
ETagwith the SHA-256 of the image;If-None-Match→304.- With the current
?v=(as inurl):Cache-Control: public, max-age=31536000, immutable. With an outdated?v=:max-age=300. Always use theurlas given.
Texture layout: one frame is 64·scale × 32·scale pixels with the vanilla cape layout. Animated capes stack all
frames vertically, frame 0 on top. Show frame floor(now_ms / frameTimeMs) mod frames so everyone sees the same
frame.
Circuit library
The redstone circuits of the TRS Client. The circuit format is described in
docs/circuit-format.md.
GET /v1/circuits/index
All published circuits with their revision:
{ "version": "3b1f…", "circuits": [
{ "id": "not_gate", "rev": 1, "updatedAt": "2026-09-27T12:00:00.000Z", "minVersion": "1.8" },
{ "id": "t_flipflop_copper", "rev": 3, "updatedAt": "…", "minVersion": "1.21", "maxVersion": "1.21.4" }
] }
ETag: "<version>";If-None-Match→304.Cache-Control: public, max-age=60, stale-while-revalidate=600.revgrows with every change. Treat it as an opaque token.maxVersionis missing when there is no upper limit.
GET /v1/circuits/{id}?rev={rev}
One circuit in the client format plus rev, updatedAt and author ({ uuid, name }, or null for the TRS team).
| Request | Answer |
|---|---|
rev = current revision | 200, Cache-Control: public, max-age=31536000, immutable |
rev = another number | 404 rev_mismatch with the current revision in details.rev – reload the index |
without rev | 200, Cache-Control: public, max-age=60 |
| unknown or not published | 404 circuit_not_found |
GET /v1/circuits/{id}/export?format=nbt|json
Download a circuit as a vanilla structure file (.nbt, loadable with a structure block) or as JSON.
GET /v1/site/circuits and GET /v1/site/circuits/{id}
The data of the website's circuit pages: the circuit plus size, block count, materials, version range and publish date.
Shared modpacks
Players share modpacks by code (TRS-XXXX-XXXX) or link (https://trs-launcher.theredstonee.de/p/TRS-XXXX-XXXX).
GET /v1/packs/code/{code}
The code is not case-sensitive and works with or without TRS- and dashes (O is read as 0, I and L as 1).
{ "pack": {
"code": "TRS-7K2M-Q9XA", "url": "https://trs-launcher.theredstonee.de/p/TRS-7K2M-Q9XA",
"name": "Redstone Pack", "summary": "Tech & Redstone", "packVersion": "1.2.0", "revision": 3,
"mcVersion": "1.21.1", "loader": { "kind": "fabric", "version": "0.16.9" },
"modrinthFiles": 42, "ownJars": 1, "otherFiles": 57, "bytes": 812345,
"owner": { "uuid": "…", "name": "Alex" }, "createdAt": "…", "updatedAt": "…", "expiresAt": null
} }
modrinthFiles counts every file in the index (a Modrinth, CurseForge or GitHub link). The name stays so older clients keep working. ownJars > 0 means jar files stored in the pack. Unknown, expired or removed: 404 pack_not_found.
GET /v1/packs/code/{code}/contents
What is inside: { "contents": { "mods": [], "resourcePacks": [], "shaderPacks": [] } }. Each entry has name,
file, source (modrinth, curseforge, github or pack) and, for Modrinth files, projectId, title, version and url.
.mrpack itself needs an account.Blog and news
| Request | Answer |
|---|---|
GET /v1/site/blog | Update posts (from the changelog) and news posts, newest first |
GET /v1/site/blog/{version} | One update post with its text as Markdown, or 404 not_found |
GET /v1/site/news?limit=10 | News posts with Markdown (limit 1–20) |
GET /v1/site/news/{slug} | One news post, or 404 post_not_found |
GET /v1/site/blog/media/{id}.{jpg|png} | Images of published posts ({id}.t.{ext} = preview) |
GET /feed.xml | RSS feed of all posts |
News texts come in { en, de?, es? }; missing languages fall back to English.
Issues and roadmap
The public issue tracker.
| Request | Answer |
|---|---|
GET /v1/issues | A page of issues: { issues, total, page, pages, per, errors } |
GET /v1/issues/roadmap | The roadmap board with six columns |
GET /v1/issues/summary | Counters: { open, total, byStatus } |
GET /v1/issues/{number} | { issue, comments, history }, or 404 issue_not_found |
GET /v1/issues/uploads/{id} | An image of a visible issue or comment (?thumb=1 = preview) |
Query parameters of GET /v1/issues:
| Parameter | Values |
|---|---|
sort | top (default), new, activity |
type | bug, feature |
area | launcher, client, website |
status | comma list of open, planned, in_progress, in_review, done, rejected, duplicate |
closed | 1 = include closed issues |
q | search text (≤ 80 characters); #57 also finds number 57 |
filter | search syntax like on the website, e.g. status:planned,in-progress area:client |
page, per | page from 1; per ≤ 50, default 20 |
Without a status filter, only open issues are listed. The log excerpt of a bug report is never public.
{ "number": 57, "url": "https://trs-launcher.theredstonee.de/issues/57",
"type": "feature", "area": "launcher", "status": "planned", "title": "Share modpacks by code",
"author": { "uuid": "…", "name": "Alex" }, "score": 12, "up": 14, "down": 2, "comments": 3,
"priority": "low", "tags": ["ui"], "fixedIn": null, "createdAt": "…", "activityAt": "…" }
(shortened)
Team
GET /v1/site/team
The public team page: groups by role with members (name, skin, TRS cape, titles, links). Cached for 60 seconds.
Achievements
GET /v1/achievements
The achievement catalog, sorted by order. Secret achievements are always hidden (hidden: true, no title or
description).
{ "achievements": [
{ "id": "play_10h", "category": "playtime", "secret": false, "hidden": false,
"title": { "en": "Settling in", "de": "…", "es": "…" },
"description": { "en": "Play for 10 hours", "de": "…", "es": "…" },
"icon": "clock", "points": 20, "rarity": "uncommon", "goal": 600, "unit": "minutes",
"verified": true, "reward": null, "order": 5 }
] }
Shared screenshots
A shared screenshot link (/s/<id>) is public for 30 days.
| Request | Answer |
|---|---|
GET /v1/shares/{id} | { share: { id, url, imageUrl, mime, width, height, createdAt, expiresAt } }, or 404 share_not_found |
GET /v1/shares/{id}/image | The image (?thumb=1 = preview), with ETag |
Nothing about the owner is public.