Public endpoints return JSON unless noted. No authentication required.
All theme endpoints support ETag-based caching via If-None-Match.
/api/themes
List all available themes.
ETag reflects the entire manifest. Changes when any theme is updated.
q
—
Search by name, description, or tags
tags
—
Comma-separated tag filter (AND logic)
core_version
—
Filter to themes compatible with this pure-admin-core version (e.g. 2.0.0)
/api/themes/:slug
Get metadata for a single theme. Response includes content_sha which matches the ETag header.
ETag is the theme's content_sha — only changes when this specific theme is updated.
/api/themes/:slug/download
Download the theme as a ZIP package. Contains CSS, SCSS, fonts, theme.json (with integrity checksums), and README. Defaults to the latest version.
version
—
Specific version to download (e.g. 2.0.2). Omit for latest.
/api/bundle
Download a ZIP bundle of multiple themes, structured for the Pure Admin demo server. Includes a generated themes.json with correct paths.
themes
—
Comma-separated theme slugs. Omit to include all themes.
/api/tools/:name
Download a specific tool script. Returns the X-Tool-Version header for update checking.
Scripts include self-update: set PUREADMIN_AUTO_UPDATE=1 to auto-update on run.
Response: application/javascript/api/tools/template
Download a theme repository template as a ZIP. Contains theme.json, starter SCSS, package.json with build/pack/publish scripts, .gitignore, and README.
id
—
Theme slug (lowercase, hyphens). Used in filenames and package name. Default: my-theme
name
—
Display name for the theme. Default: humanized id
All theme API responses include an
ETag
header. Send If-None-Match
with the ETag value to receive
304 Not Modified
when content hasn't changed.
| Endpoint | ETag source | Changes when |
|---|---|---|
| /api/themes | Manifest etag | Any theme is updated |
| /api/themes/:slug | Theme's content_sha | Only when that specific theme changes |
Each theme ZIP contains a
theme.json
with SHA-256 checksums for every file in the package, a metadata hash, and a
content_sha
that matches the ETag
returned by the API. Clients can verify downloads by comparing the
checksums.content_sha
in theme.json against the ETag they received.
// theme.json inside the ZIP
{
"checksums": {
"files": {
"css/audi.css": "sha256:bead...",
"assets/fonts/FiraSans.woff2": "sha256:ab12..."
},
"metadata": "sha256:ef56...",
"content_sha": "sha256:9a53..." // matches ETag
},
"external_domains": ["fonts.googleapis.com"],
"scripts": []
}
curl -fsSL -o audi.zip https://pureadmin.io/api/themes/audi/download
# First request — save the ETag
curl -sI https://pureadmin.io/api/themes/audi | grep etag
# etag: "sha256:61df..."
# Subsequent requests — 304 if unchanged
curl -s -o /dev/null -w "%{http_code}" \
-H 'If-None-Match: "sha256:61df..."' \
https://pureadmin.io/api/themes/audi
# 304
curl -fsSL -o themes.zip https://pureadmin.io/api/bundle\nunzip themes.zip -d themes/
ARG THEMES_URL=https://pureadmin.io/api/bundle
RUN curl -fsSL -o /tmp/themes.zip "${THEMES_URL}" && \
unzip -o /tmp/themes.zip -d themes/ && \
rm /tmp/themes.zip
const res = await fetch('https://pureadmin.io/api/themes');\nconst etag = res.headers.get('etag');\nconst { themes } = await res.json();\n\n// Later: skip if unchanged\nconst res2 = await fetch('https://pureadmin.io/api/themes', {\n headers: { 'If-None-Match': etag }\n});\nif (res2.status === 304) console.log('No changes');
# Scaffold a new theme project with the CLI
npx @keenmate/pureadmin init my-theme "My Theme"
cd my-theme && npm install
# Build, pack, publish
npx @keenmate/pureadmin build
npx @keenmate/pureadmin pack
npx @keenmate/pureadmin publish --api-key KEY
# Get the ETag from the API
ETAG=$(curl -sI https://pureadmin.io/api/themes/audi | grep -i etag | awk '{print $2}' | tr -d '"\r')
# Download and extract content_sha from the ZIP
curl -fsSL -o audi.zip https://pureadmin.io/api/themes/audi/download
SHA=$(unzip -p audi.zip theme.json | python3 -c "import sys,json; print(json.load(sys.stdin)['checksums']['content_sha'])")
# Compare
[ "$ETAG" = "$SHA" ] && echo 'Integrity OK' || echo 'MISMATCH'