openssl genpkey -algorithm Ed25519 -out priv.pem openssl pkey -in priv.pem -pubout -outform DER | tail -c 32 | xxd -p -c 64The hex string is your public key — paste it into the dashboard's Signing key form. Keep
priv.pem safe; the marketplace never sees it.
com.example.todo.
.zip containing
manifest.json at the root and any index.html/*.js/*.css
your app needs. The manifest declares app_id, name, version (SemVer),
publisher, and (optional) capabilities.bundle.zip and sign the
string app_id|version|sha256_hex with your private key. The signature is
base64-encoded.
SHA=$(openssl dgst -sha256 -binary bundle.zip | xxd -p -c 64) printf '%s|%s|%s' "$APP_ID" "$VER" "$SHA" \ | openssl pkeyutl -sign -inkey priv.pem -rawin \ | base64 -w0
{
"app_id": "com.example.todo",
"name": "Todo",
"version": "1.2.0",
"description": "A simple todo list",
"category": "productivity",
"publisher": "Example Inc.",
"entry": "index.html",
"permissions": [],
"capabilities": ["filesystem.read", "notifications"],
"jpos_min_version": "0.1.0",
"icon": "icon.png",
"homepage": "https://example.com"
}
Everything the portal does, you can do from a script. Auth via session cookie or — for CI / publishing pipelines — the bootstrap bearer token + X-Publisher-Id header.
POST /api/publisher/auth/request — body { "email": "..." }GET /api/publisher/auth/verify?token=… — sets cookie, redirects to dashboardPOST /api/publisher/auth/logoutGET /api/publisher/mePOST /api/publisher/keys — body { "ed25519_pubkey": "<hex>" }GET /api/publisher/packagesPOST /api/publisher/packages — body { "app_id", "name", … }GET /api/publisher/packages/:id/statsPOST /api/publisher/packages/:id/versions — multipart (manifest, bundle, signature)POST /api/publisher/packages/:id/versions/:v/yankPOST /api/publisher/packages/:id/versions/:v/unyank