API

The API returns JSON. Reading is open to everyone. Changing content needs an API key.

A machine-readable description is available at /openapi/v1.json.

Reading

Only items that are active, published and public are returned.

Method Address Returns
GET /api/projects All projects
GET /api/projects/{slug} One project
GET /api/projects/{slug}/releases Every uploaded file, newest first
GET /api/projects/{slug}/releases/latest The newest uploaded file
GET /api/products All products
GET /api/products/{slug} One product
GET /api/posts All posts, newest first
GET /api/posts/{slug} One post

The slug is the short name in the address, for example my-app.

curl https://example.com/api/projects/my-app/releases/latest
{
  "releaseID": 3,
  "version": "1.2.0",
  "fileName": "MyApp-1.2.0.exe",
  "fileSize": 7829504,
  "sha256": "9f2c...",
  "platform": "WINDOWS",
  "architecture": "amd64",
  "notes": "",
  "downloadCount": 12,
  "uploadedOn": "2026-10-25T17:40:00Z",
  "downloadUrl": "/files/3/MyApp-1.2.0.exe"
}

Downloading

Address What happens
/download/{slug}/latest Redirects to the newest file
/download/{slug}/{version} Redirects to that version
/download/{slug}/latest?platform=WINDOWS Newest file for one platform
/files/{id}/{fileName} The file itself. Resumable downloads are supported

Use the /download/... links on web pages and in scripts. They keep working when a new version is uploaded.

Changing content

Send your key in the X-Api-Key header. The key is the Api:Key setting. If it is not set, or shorter than 16 characters, every change is refused.

Method Address Does
POST /api/projects Add a project (JSON body)
PUT /api/projects/{slug} Replace a project's fields (JSON body)
DELETE /api/projects/{slug} Delete a project and its files
POST /api/projects/{slug}/releases Upload a file (form data, see below)
DELETE /api/releases/{id} Delete one uploaded file
POST /api/products Add a product (JSON body)
PUT /api/products/{slug} Replace a product's fields
DELETE /api/products/{slug} Delete a product
POST /api/posts Add a post (JSON body)
PUT /api/posts/{slug} Replace a post's fields
DELETE /api/posts/{slug} Delete a post

The JSON body uses the same field names as the data classes (name, summary, description, ...). Leave slug empty and it is made from the name or title. description and content are Markdown.

curl -X POST https://example.com/api/posts \
  -H "X-Api-Key: YOUR_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{"title": "Hello", "content": "My **first** post."}'

Uploading a release

Send a form with the file in a field called file:

Field Required Example
file yes the .exe, .zip or installer
version yes 1.2.0 (letters, numbers and . _ + - only)
platform no WINDOWS, LINUX, MAC
architecture no amd64, arm64
notes no short release notes
curl -X POST https://example.com/api/projects/my-app/releases \
  -H "X-Api-Key: YOUR_API_KEY" \
  -F file=@MyApp-1.2.0.exe -F version=1.2.0 -F platform=WINDOWS -F architecture=amd64

The checksum is calculated by the server. Uploading also sets the project's version.

Status codes

Code Meaning
200 / 201 / 204 Done
400 Something in the request is wrong, such as a bad version
401 Missing or wrong API key
404 No such project, product, post or file
An unhandled error has occurred. Reload 🗙

Rejoining the server...

Rejoin failed... trying again in seconds.

Failed to rejoin.
Please retry or reload the page.

The session has been paused by the server.

Failed to resume the session.
Please retry or reload the page.