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.json
manifests
— 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
, OPTIONS
Access-Control-Allow-Origin: *
, Vary: Origin
OPTIONS
.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