/api/system/load-password
POSTLoad the file-decryption password into RAM. While the password is loaded, encrypted (Type 10) coin files can be decrypted in memory as needed, and coin encryption operations become possible.
This endpoint replaces /api/system/login. The old URL is no longer registered. Its counterpart, /api/system/logout, is replaced by /api/system/shutdown, which deletes the password from RAM and shuts the core down.
Description
/api/system/load-password accepts a password in a form-encoded POST body and holds the derived key in RAM. It is deliberately not called "login": no account exists, and nothing is stored on disk. The password is the only thing standing between the encrypted coin files and their authenticity numbers — the server keeps it (as a derived key) in memory until /api/system/shutdown is called or the process exits.
How the password is verified: encrypted Type 10 coin files intentionally contain no password check of any kind — nothing on disk can prove a password right or wrong. The core verifies a candidate password by decrypting one coin in memory and asking the RAIDA whether the resulting authenticity numbers are genuine, using the Detect Hash command (Group 1, Code 12): each RAIDA receives a SHA-256 hash bound to its own challenge, never the ANs themselves, so a wrong guess exposes nothing. If the RAIDA quorum rejects the hash, the response is a definitive 401 bad password. This requires network access; servers that do not support Detect Hash yet are handled by an encrypted-detect fallback automatically.
- POST only. GET requests are rejected with
405— a password in a URL would be written toClient_Data/main.logand to any proxy or browser history logs. - Lost password = lost coins. Once files are encrypted, there is no recovery if the password is forgotten. The GUI must warn the user and require the password to be typed twice when encrypting for the first time.
- UTF-8 byte exactness. The key is derived from the raw bytes the client sends. Encode non-ASCII characters as UTF-8 (form-encode with
--data-urlencode/FormData) so every client derives the same key. - Use HTTPS in any deployment that is not loopback-only.
Client Flow — what to call, in what order
- Call
GET /api/system/encryption-statusat startup, before showing the dashboard.- If encrypted files exist and no key is loaded, prompt for the password before the dashboard appears.
- If no encrypted files exist, no prompt is needed. The wallet is decrypted.
- Send the password with
POST /api/system/load-password. - On
401 bad password, tell the user the password is wrong and let them retry — this verdict is definitive (a RAIDA quorum rejected it). On503, the verdict is inconclusive (network/scan trouble): keep the wallet read-only and retry; do NOT tell the user the password was wrong. On200withkey_state: "confirmed", show the dashboard. - To encrypt a decrypted wallet, call
/api/system/encrypt_existing_files. To decrypt, call/api/system/decrypt_existing_files. - When the user logs out, call
POST /api/system/shutdown— it deletes the password from RAM and shuts the core down; the GUI should then exit too.
Parameters
| Parameter | Location | Type | Required | Description |
|---|---|---|---|---|
password |
POST body (form-encoded) | string | Required | The user's password as raw UTF-8 bytes. Any characters are accepted. Minimum 1 byte; maximum 4096 bytes (HTTP layer ceiling). |
Response
A 200 always carries key_state — the client MUST branch on it, not just on the status code.
200 — confirmed (encrypted files exist, RAIDA verified the password)
{
"command": "load-password",
"success": true,
"key_set": true,
"key_state": "confirmed",
"raida": { "pass": 25, "fail": 0, "usable": 25 }
}
200 — establishing_ready (no encrypted files yet; password held for first encryption)
{
"command": "load-password",
"success": true,
"key_set": true,
"key_state": "establishing_ready",
"message": "Password held for first encryption; nothing to verify against",
"raida": { "pass": 0, "fail": 0, "usable": 0 }
}
200 — candidate (verification inconclusive; wallet stays read-only)
{
"command": "load-password",
"success": true,
"key_set": true,
"key_state": "candidate",
"message": "Wallet is read-only until RAIDA confirmation succeeds",
"raida": { "pass": 9, "fail": 2, "usable": 11 }
}
Response Fields
| Field | Type | Description |
|---|---|---|
key_state | string | confirmed — RAIDA quorum verified the password; full read/write. candidate — could not reach a quorum verdict; wallet read-only, retry later. establishing_ready — no Type 10 files exist; password held in RAM for the first encrypt run. establishing — a first-encryption run is currently in flight. |
key_set | bool | true on every 200: a password/derived key is now in RAM. |
raida | object | Per-verification RAIDA tallies: pass (servers that confirmed the ANs), fail (servers that rejected them), usable (servers that answered). Zeroes when there was nothing to verify against. |
Error Responses
400 — Password missing
{
"error": true,
"message": "Missing required parameter: password",
"code": 400
}
405 — GET not allowed
{
"error": true,
"message": "Use POST: a password in a GET URL would be written to server and proxy logs",
"code": 405
}
401 — Bad password (definitive)
{
"error": true,
"message": "bad password",
"code": 401,
"detail": "(or coins are counterfeit)",
"key_state": "none",
"key_set": false,
"raida": { "pass": 0, "fail": 25, "usable": 25 }
}
A RAIDA quorum rejected the derived authenticity numbers. The candidate key has been cleared from RAM; prompt the user to retype the password. This is the ONLY response that means "wrong password" — never infer a wrong password from a 503. (The detail field notes the one other possibility: the coin used for verification is itself counterfeit.)
503 — Inconclusive or cannot scan (NOT a wrong password)
Two messages share this code: Corrupt Type 10 coin file present; repair or remove before loading password (run copy_undecryptable to collect the damaged files) and Unable to scan wallet for encrypted files; try again (transient filesystem/scan trouble). In both cases keep the wallet locked and let the user retry — do not display "wrong password".
Example Usage
curl -X POST \
-H "Content-Type: application/x-www-form-urlencoded; charset=utf-8" \
--data-urlencode "password=¥CheeseCake£" \
"http://localhost:8080/api/system/load-password"
const body = new URLSearchParams();
body.set('password', '¥CheeseCake£');
const res = await fetch('http://localhost:8080/api/system/load-password', {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded; charset=utf-8' },
body: body
});
const data = await res.json();
if (res.status === 401) {
// definitive wrong password — prompt to retype
} else if (res.status === 503) {
// inconclusive — stay locked, offer retry; NOT a wrong password
} else if (data.key_state === 'confirmed' || data.key_state === 'establishing_ready') {
// show the dashboard
} else if (data.key_state === 'candidate') {
// read-only until RAIDA confirmation succeeds — retry load-password later
}
import requests
url = 'http://localhost:8080/api/system/load-password'
resp = requests.post(url, data={'password': '¥CheeseCake£'})
print(resp.json())
# {'command': 'load-password', 'success': True, 'key_set': True, ...}
Related Endpoints
- /api/system/encryption-status — Call this BEFORE prompting: it says whether a password is needed at all.
- /api/system/shutdown — Delete the password from RAM and shut the core down (the GUI log-out).
- /api/system/encrypt_existing_files — Encrypt all plaintext coin files.
- /api/system/decrypt_existing_files — Decrypt all encrypted coin files.
- /api/system/copy_undecryptable — Collect corrupt / cross-salt files when this endpoint returns 503 for corrupt Type 10.
- Detect Hash (protocol) — The RAIDA command used to verify the password.