Desktop downloads
The download resource serves the desktop application builds a deployment has stored. It also serves a SHA-256 checksum for each build and the release feed files beside them. Every route here is unauthenticated. A request that sends a credential anyway receives the same status and body. No route here declares a rate limit bucket, and none draws on the global allowance.
Prefix and mounting
Section titled “Prefix and mounting”LafON registers the routes under /dl, and the desktop routes under /dl/desktop. A client builds the URL against api_client from the instance endpoints object.
LafON mounts the prefix at the root and at /v1. Every desktop route below also answers under /v1/dl/desktop/....
Every other route on this reference takes the /v1 form, and HTTP API states that a client MUST use it.
Methods
Section titled “Methods”Every route answers GET. The checksum routes, the artifact routes, and the catch-all also bind HEAD. Get latest desktop version and List desktop versions bind GET alone, and a HEAD still reaches them under the shared rule for HEAD.
A HEAD on either JSON route runs the same resolution as the GET and returns its status and headers with no body. It can therefore answer 404.
A checksum route answers a HEAD with 200 and no body. The headers are Content-Type, Content-Disposition, Cache-Control, and the Content-Length of the checksum line.
Artifact and catch-all HEAD requests return 200 with Content-Type, Content-Disposition, Accept-Ranges, Cache-Control and Content-Length, plus ETag and Last-Modified when available. They ignore Range and never return 206, 416 or a presigned URL redirect. Country redirects still return 302 for HEAD, as for GET.
Release channels
Section titled “Release channels”| Value | Name | Description |
|---|---|---|
| stable | Stable | The channel a deployment publishes for general use |
| canary | Canary | The channel that receives a build ahead of stable |
The channel selects the release series and product name. A canary file is named Fluxer-Canary or Fluxer Canary, and a stable file is named Fluxer.
Platforms and architectures
Section titled “Platforms and architectures”| Value | Name | Description |
|---|---|---|
| win32 | Windows | The Windows build target |
| darwin | macOS | The macOS build target |
| linux | Linux | The Linux build target |
The path segment with one of those values is named plat.
| Value | Name | Description |
|---|---|---|
| x64 | x64 | The 64-bit x86 architecture |
| arm64 | ARM64 | The 64-bit ARM architecture |
A channel, a platform, and an architecture together name one coordinate.
Package formats
Section titled “Package formats”| Value | Name | Description |
|---|---|---|
| setup | Setup | The Windows installer executable |
| portable | Portable | The Windows archive that stores its data beside the executable |
| dmg | DMG | The macOS disk image |
| zip | ZIP | The macOS application archive |
| appimage | AppImage | The Linux portable application image |
| deb | DEB | The Debian package |
| rpm | RPM | The RPM package |
| tar_gz | TAR.GZ | The Linux compressed tarball |
The registry is closed, and a format outside it returns 400 INVALID_FORM_BODY.
Each format resolves on one platform. setup and portable resolve on win32, dmg and zip on darwin, and appimage, deb, rpm, and tar_gz on linux. A format paired with any other platform returns 404.
On darwin a dmg or zip request tries the universal file before the architecture-specific one, so x64 and arm64 can resolve to the same file.
Checksum requests
Section titled “Checksum requests”A client appends .sha256 to the format segment to read the checksum, and sends the bare format to read the file. tar_gz.sha256 is the checksum of tar_gz.
Use the lowercase .sha256 suffix with a valid package format. An invalid format or suffix returns 400 INVALID_FORM_BODY.
Version info object
Section titled “Version info object”A version info object describes one release at a coordinate and the file it has for each format.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| version | string | The release version in MAJOR.MINOR.PATCH form |
| pub_date1 | ISO8601 timestamp | The moment the release was published |
| minimum_system_version?2 | ?string | The lowest operating system version the release supports |
| files3 | map[string, version file object] | The download entry for each package format the release has |
1 Publication time reported for the release
2 Present when the release specifies a minimum system version
3 A format that resolves no file is absent from the map
Example
Section titled “Example”{ "version": "1.4.2", "pub_date": "2026-08-19T11:04:00.000Z", "minimum_system_version": "10.15.0", "files": { "dmg": { "url": "https://api.example.com/dl/desktop/stable/darwin/arm64/1.4.2/dmg", "sha256": "3b1f5c0d9e7a24486cf0b1d3a5e87209cc4d61fba0937e5528d1c4a67b0e93f2", "checksum_url": "https://api.example.com/dl/desktop/stable/darwin/arm64/1.4.2/dmg.sha256" } }}Version file object
Section titled “Version file object”A version file object is the download entry for one format of one release.
Structure
Section titled “Structure”| Field | Type | Description |
|---|---|---|
| url1 | string | The absolute URL of the versioned download for this format |
| sha2562 | ?string | The hash of the file as 64 lowercase hexadecimal characters, or null where no checksum was found |
| checksum_url1 | ?string | The absolute URL of the checksum file, or null where sha256 is null |
1 Built from api_client in the instance endpoints object, with no /v1 segment
2 A 64-character lowercase hexadecimal hash, or null when no valid checksum is available
Checksum files
Section titled “Checksum files”A checksum response is one sha256sum line: the hash, two spaces, the resolved filename, and a trailing newline.
2f6d1a4b8c3e07f95ab61d4c2e8035971fd0ba46c7e213985cd0f74a6b1e82c3 Fluxer-1.4.2-linux-x86_64.AppImageThe response has Content-Type: text/plain; charset=utf-8, a Content-Disposition of attachment naming the resolved filename with .sha256 appended, and a Content-Length counting the encoded line. It sets no Accept-Ranges, ETag, or Last-Modified, and it ignores a Range header.
A missing or invalid checksum returns 404.
Artifact resolution
Section titled “Artifact resolution”Use latest for the release currently offered at a channel, platform and architecture, or a versioned URL to request a specific release. A missing file returns 404 with the plain text body Not Found.
Response headers and caching
Section titled “Response headers and caching”Every artifact response has Accept-Ranges: bytes and a Content-Disposition of attachment naming the resolved file, unless the stored object has its own Content-Disposition. The filename is percent-encoded inside the header, so a name containing a space is written with %20.
| Response | Cache-Control |
|---|---|
| Latest version metadata and the version list | public, max-age=300 |
| Latest artifact and latest checksum | no-store |
Versioned artifact and versioned checksum under desktop/ | public, max-age=31536000 |
A release feed filename, and anything under desktop-test/ | public, max-age=300 |
Any desktop/ artifact on a deployment that configures country redirects | private, no-store |
| A redirect to a presigned storage URL | no-store |
A release feed filename is any of these:
manifest.json- A name ending in
.ymlor.yaml - A name beginning
RELEASES - A name beginning
releasesorassetsand ending in.json
Redirects
Section titled “Redirects”The deployment settings below answer a download with 302.
A hosted deployment can list countries whose downloads of a file under desktop/ LafON can redirect to GitHub release assets. Once the list is set, every response for such a file has Cache-Control: private, no-store, including a response LafON serves from storage.
A deployment that issues presigned download URLs answers a GET with 302 to a storage URL valid for 900 seconds. That redirect has Cache-Control: no-store and Accept-Ranges: bytes. The setting is off by default.
Test builds
Section titled “Test builds”Every route accepts the test query parameter. 1 or true, matched without regard to case, selects test releases. Any other value is false.
On the desktop routes the flag makes LafON resolve every file under desktop-test/. On Download stored object it rewrites a key beginning desktop/ and leaves any other key unchanged, and a path that already names desktop-test/ resolves there with no flag at all.
A url and a checksum_url built for a request that sent the flag repeat ?test=1, so a client following either one stays on the test prefix.
Get latest desktop version
Section titled “Get latest desktop version”GET/v1/dl/desktop/{channel}/{plat}/{arch}/latestReturns the version info object for the newest release at the coordinate.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| channel | string | The release channel to resolve |
| plat | string | The platform to resolve |
| arch | string | The architecture to resolve |
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| test? | string | The test build flag, 1 or true to resolve under desktop-test/ |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | version info object | A release resolved at the coordinate |
| 400 | error response | A path or query value fails its schema and the request returns INVALID_FORM_BODY |
| 404 | Not Found | No release resolved at the coordinate |
A client reads files for the format it wants. A format whose file resolved no checksum reports sha256 and checksum_url as null.
Response headers
Section titled “Response headers”The 200 has Cache-Control: public, max-age=300. The 404 has Content-Type: text/plain.
List desktop versions
Section titled “List desktop versions”GET/v1/dl/desktop/{channel}/{plat}/{arch}/versionsReturns the releases stored at the coordinate, newest first.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| channel | string | The release channel to resolve |
| plat | string | The platform to resolve |
| arch | string | The architecture to resolve |
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| limit? | integer | The maximum number of releases to return (1 through 100, default 25) |
| before?1 | string | The version to page below, exclusive |
| after?1 | string | The version to page above, exclusive |
| test? | string | The test build flag, 1 or true to resolve under desktop-test/ |
1 Compared component by component as numbers, and both bounds can be sent together to select a range
Response body
Section titled “Response body”| Field | Type | Description |
|---|---|---|
| versions | array[version info object] | The releases on this page, ordered newest first |
| has_more | boolean | Whether the filtered set held more releases than limit |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | response body | The listing completed, possibly with no release |
| 400 | error response | A path or query value fails its schema and the request returns INVALID_FORM_BODY |
This route never answers 404. A coordinate that holds no object returns 200 with an empty array.
Only available files are listed. This response omits minimum_system_version and reports sha256 only when a valid checksum is available.
Response headers
Section titled “Response headers”The 200 has Cache-Control: public, max-age=300.
Download latest desktop artifact
Section titled “Download latest desktop artifact”GET/v1/dl/desktop/{channel}/{plat}/{arch}/latest/{format}Streams the newest file at the coordinate for one package format.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| channel | string | The release channel to resolve |
| plat | string | The platform to resolve |
| arch | string | The architecture to resolve |
| format | string | The package format to resolve |
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| test? | string | The test build flag, 1 or true to resolve under desktop-test/ |
Request headers
Section titled “Request headers”| Field | Type | Description |
|---|---|---|
| Range? | string | The standard byte range, answered with 206 and a Content-Range header |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | artifact bytes | The complete file was streamed |
| 206 | artifact bytes | The requested byte range was streamed |
| 302 | empty | The deployment redirects this download |
| 400 | error response | A path or query value fails its schema and the request returns INVALID_FORM_BODY |
| 404 | Not Found | No file resolved for the format at the coordinate |
| 416 | empty | The requested range is unsatisfiable |
The stored file keeps its own name, so the resolved filename has the release version even though the request named latest. A client that follows this route on every check reads a different file once a newer release is stored at the coordinate.
Response headers
Section titled “Response headers”The 200 has Content-Type1, Content-Disposition2, Content-Length, Accept-Ranges: bytes, Cache-Control: no-store, ETag3, and Last-Modified3. The 206 has the 200 headers plus Content-Range. The 302 has Location, Accept-Ranges: bytes, and Cache-Control. The 404 has Content-Type: text/plain. The 416 has Accept-Ranges: bytes, Content-Range: bytes */{size}, and Cache-Control.
1 The stored media type, and application/octet-stream where storage reports none
2 attachment naming the resolved filename, percent-encoded
3 Sent where storage reports the value
Download latest desktop checksum
Section titled “Download latest desktop checksum”GET/v1/dl/desktop/{channel}/{plat}/{arch}/latest/{format}.sha256Returns the checksum file for the newest file at the coordinate.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| channel | string | The release channel to resolve |
| plat | string | The platform to resolve |
| arch | string | The architecture to resolve |
| format1 | string | The package format to resolve, followed by .sha256 |
1 The complete segment matches [a-z_]+\.sha256 for the route to claim it, and the part before the suffix names a format in the closed registry
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| test? | string | The test build flag, 1 or true to resolve under desktop-test/ |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | checksum line | The file and a valid hash both resolved |
| 400 | error response | A path or query value fails its schema and the request returns INVALID_FORM_BODY |
| 404 | Not Found | No file resolved for the format, or the resolved file has no valid hash |
This hash is the value Get latest desktop version reports as sha256 for the same format. The line names the file this coordinate’s latest download streams.
Response headers
Section titled “Response headers”The 200 has Content-Type: text/plain; charset=utf-8, Content-Disposition, Content-Length, and Cache-Control: no-store. The 404 has Content-Type: text/plain.
Download desktop artifact
Section titled “Download desktop artifact”GET/v1/dl/desktop/{channel}/{plat}/{arch}/{version}/{format}Streams one released file by version and package format.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| channel | string | The release channel to resolve |
| plat | string | The platform to resolve |
| arch | string | The architecture to resolve |
| version1 | string | The release version to resolve |
| format | string | The package format to resolve |
1 Three decimal components matching ^\d+\.\d+\.\d+$, so a two-component or suffixed version returns 400 INVALID_FORM_BODY
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| test? | string | The test build flag, 1 or true to resolve under desktop-test/ |
Request headers
Section titled “Request headers”| Field | Type | Description |
|---|---|---|
| Range? | string | The standard byte range, answered with 206 and a Content-Range header |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | artifact bytes | The complete file was streamed |
| 206 | artifact bytes | The requested byte range was streamed |
| 302 | empty | The deployment redirects this download |
| 400 | error response | A path or query value fails its schema and the request returns INVALID_FORM_BODY |
| 404 | Not Found | No file resolved for the version and format |
| 416 | empty | The requested range is unsatisfiable |
Response headers
Section titled “Response headers”The 200 has Content-Type, Content-Disposition, Content-Length, Accept-Ranges: bytes, Cache-Control1, ETag2, and Last-Modified2. The 206 has the 200 headers plus Content-Range. The 302 has Location, Accept-Ranges: bytes, and Cache-Control. The 404 has Content-Type: text/plain. The 416 has Accept-Ranges: bytes, Content-Range: bytes */{size}, and Cache-Control.
1 public, max-age=31536000 for a released file, and public, max-age=300 under desktop-test/ or for a release feed filename
2 Sent where storage reports the value
Download desktop checksum
Section titled “Download desktop checksum”GET/v1/dl/desktop/{channel}/{plat}/{arch}/{version}/{format}.sha256Returns the checksum file for one released file.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| channel | string | The release channel to resolve |
| plat | string | The platform to resolve |
| arch | string | The architecture to resolve |
| version | string | The release version to resolve |
| format1 | string | The package format to resolve, followed by .sha256 |
1 The complete segment matches [a-z_]+\.sha256 for the route to claim it, and the part before the suffix names a format in the closed registry
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| test? | string | The test build flag, 1 or true to resolve under desktop-test/ |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | checksum line | The file and a valid hash both resolved |
| 400 | error response | A path or query value fails its schema and the request returns INVALID_FORM_BODY |
| 404 | Not Found | No file resolved for the version and format, or no valid hash was found for it |
Returns 404 when the requested file has no available checksum.
Response headers
Section titled “Response headers”The 200 has Content-Type: text/plain; charset=utf-8, Content-Disposition, Content-Length, and Cache-Control1. The 404 has Content-Type: text/plain.
1 public, max-age=31536000 for a released file, and public, max-age=300 under desktop-test/
Download stored object
Section titled “Download stored object”GET/dl/{path}Downloads a file by path. Use this route for release feeds, which have no format or version segment.
Path parameters
Section titled “Path parameters”| Field | Type | Description |
|---|---|---|
| path1 | string | The download path, which can contain / separators |
1 Taken from the request path with the /dl prefix removed, then normalised. It begins desktop/ or desktop-test/ after normalisation, and every other key returns 404
Query parameters
Section titled “Query parameters”| Field | Type | Description |
|---|---|---|
| test? | string | The test build flag, 1 or true to rewrite a desktop/ key to desktop-test/ |
Request headers
Section titled “Request headers”| Field | Type | Description |
|---|---|---|
| Range? | string | The standard byte range, answered with 206 and a Content-Range header |
Response
Section titled “Response”| Status | Body | Condition |
|---|---|---|
| 200 | object bytes | The complete object was streamed |
| 206 | object bytes | The requested byte range was streamed |
| 302 | empty | The deployment redirects this download |
| 400 | error response | The test value fails its schema and the request returns INVALID_FORM_BODY |
| 404 | Not Found | The key is outside the permitted prefixes, the request has the /v1 prefix, or storage holds no such object |
| 416 | empty | The requested range is unsatisfiable |
LafON also rejects the key when it is empty, when normalisation leaves it beginning .. or /, or when any segment is ., .., or contains a NUL character. Each of those returns the same 404, so a caller cannot tell a traversal attempt from a missing object.
A request can name desktop/stable/linux-x64/manifest.json or desktop/stable/linux/x64/manifest.json. For the hyphen form, LafON returns that object when storage holds it, and otherwise returns the object at the slash form.
Response headers
Section titled “Response headers”The 200 has Content-Type, Content-Disposition, Content-Length, Accept-Ranges: bytes, Cache-Control1, ETag2, and Last-Modified2. The 206 has the 200 headers plus Content-Range. The 302 has Location, Accept-Ranges: bytes, and Cache-Control. The 404 has Content-Type: text/plain. The 416 has Accept-Ranges: bytes, Content-Range: bytes */{size}, and Cache-Control.
1 public, max-age=31536000 for a released artifact, and public, max-age=300 for a release feed filename or a key under desktop-test/
2 Sent where storage reports the value
