JSON endpoints served by /api.php. CORS enabled (GET), ETag and caching
provided out of the box.
Base: /api.php
Required: action ∈ latest, list, search, get, manifest, health
Optional:
pretty — pretty-printed JSON (no value needed)data — override catalog path (safe, same-dir/subdir only). Default: firmwares.jsonmanifests — override manifests folder (safe, same-dir/subdir). Default: manifests/
Content-Type: application/json; charset=utf-8
Cache: Cache-Control: public, max-age=60 (configurable in PHP).
CORS: Access-Control-Allow-Origin: *.
/api.php?action=health healthBasic health check.
{
"status": "ok",
"time": "2025-10-11T00:00:00Z"
}
200 on success.
/api.php?action=latest newestNewest firmware (sorted by version desc; hyphen suffixes like 1.0.0-7 supported).
{
"name": "Firmware 20.5.0",
"version": "20.5.0",
"file": "download/global/Firmware 20.5.0.zip",
"md5": "4ea8aeb49ab60e2c1a3d08949f979600"
}
/api.php?action=list catalogEntire catalog (optionally paginated).
limit — number of items to returnoffset — start index{
"count": 87,
"offset": 0,
"limit": 87,
"items": [
{ "name": "Firmware 20.5.0", "file": "download/global/Firmware 20.5.0.zip", "md5": "..." },
...
]
}
/api.php?action=search&q=<term> searchCase-insensitive search over name and md5. Returns newest → oldest.
{
"query": "20.5",
"count": 1,
"items": [{ "name": "Firmware 20.5.0", "file": "...", "md5": "..." }]
}
/api.php?action=get&name=<firmware-name> lookupLookup one item by exact name; falls back to case-insensitive and fuzzy contains.
{
"name": "Firmware 20.4.0",
"file": "download/global/Firmware 20.4.0.zip",
"md5": "7dabad47ab164a6a41952ce75bb0d24b"
}
Errors: 400 (missing name), 404 (not found).
/api.php?action=manifest&name=<firmware-name> per-versionReturns the manifest JSON from /manifests/<name>.json. Uses catalog to resolve canonical casing.
{
"name": "Firmware 20.5.0",
"file_count": 123,
"files": [
{ "path": "nx/system/file.bin", "sha256": "...", "md5": "..." },
...
]
}
Errors: 400 (missing name), 404 (manifest not found), 500 (invalid JSON / read error).
ETag; clients may send If-None-Match to receive 304 Not Modified.Cache-Control: public, max-age=60 (change $DEFAULT_MAX_AGE_SEC in api.php).list/search ETag is derived from the catalog file’s ino:size:mtime (or content hash).GET, OPTIONSAccess-Control-Allow-Origin: *, Vary: OriginOPTIONS.Fetch newest (browser):
fetch('/api.php?action=latest')
.then(r => r.json())
.then(console.log);
Search (curl):
curl -s "https://switchfirm.org/api.php?action=search&q=20.5"
Get manifest (Node + jq):
curl -s "https://switchfirm.org/api.php?action=manifest&name=Firmware%2020.5.0" | jq .file_count