/api/system/encryption-status

GET

Lightweight probe used by clients to decide whether to prompt the user for a login password.

Description

Scans every registered wallet's coin folders (Bank, Fracked, Limbo, Suspect, Grade, Pending, Import, Imported) and reports:

  • stateencrypted (every coin file is Type 10), decrypted (no Type 10 files; includes an empty wallet), or mixed (both kinds present — typically an interrupted encrypt/decrypt run that should be finished by re-running the same bulk endpoint).
  • key_state — where the session stands: none, establishing_ready, establishing, candidate, or confirmed (see load-password for the meanings).
  • login_requiredtrue if encrypted files exist AND the session is not confirmed. The client can branch on this single flag instead of running its own scan.
  • File counts, including two support signals: corrupt_type10 (damaged Type 10 files) and salt_domains (distinct password salts seen — more than 1 means files from another wallet/password are mixed in). Either being abnormal is the cue to run copy_undecryptable.
File-size rule of thumb

Encrypted Type 10 coin files are exactly 612 bytes; plaintext Type 9 files are 439 bytes. Handy for eyeballing a wallet folder, but always trust this endpoint over file sizes.

Use this before login

This endpoint is the recommended first call for a fresh client, before showing the dashboard. It tells you whether the user even needs a password prompt — a decrypted wallet skips the login step entirely.

Parameters

None.

Response

Success — 200 OK

Encrypted wallet; user has not logged in yet
{
  "command": "encryption-status",
  "success": true,
  "key_state": "none",
  "state": "encrypted",
  "encrypted_count": 372,
  "plaintext_count": 0,
  "legacy_unsupported_files": 0,
  "corrupt_type10": 0,
  "salt_domains": 1,
  "encrypted_files_exist": true,
  "login_required": true,
  "key_set": false
}
Decrypted wallet — no password needed
{
  "command": "encryption-status",
  "success": true,
  "key_state": "none",
  "state": "decrypted",
  "encrypted_count": 0,
  "plaintext_count": 372,
  "legacy_unsupported_files": 0,
  "corrupt_type10": 0,
  "salt_domains": 0,
  "encrypted_files_exist": false,
  "login_required": false,
  "key_set": false
}
Interrupted run — offer "Finish Encrypting"
{
  "command": "encryption-status",
  "success": true,
  "key_state": "confirmed",
  "state": "mixed",
  "encrypted_count": 200,
  "plaintext_count": 172,
  "legacy_unsupported_files": 0,
  "corrupt_type10": 0,
  "salt_domains": 1,
  "encrypted_files_exist": true,
  "login_required": false,
  "key_set": true
}

Response Fields

FieldTypeDescription
statestringencrypted | decrypted | mixed. Drives the Security menu: show "Decrypt coins" when encrypted, "Encrypt coins" when decrypted, "Finish Encrypting/Decrypting" when mixed.
key_statestringnone | establishing_ready | establishing | candidate | confirmed. Only confirmed allows coin writes when encrypted files exist.
encrypted_countintType 10 (encrypted) coin files across all registered wallets.
plaintext_countintPlaintext Type 9 coin files.
legacy_unsupported_filesintLeftovers from the removed legacy encryption scheme. Should be 0; restore such files from a plaintext backup.
corrupt_type10intType 10 files whose header/CRC cannot be parsed. If > 0, load-password refuses with 503; collect them with copy_undecryptable.
salt_domainsintDistinct password-salt domains across all Type 10 files. Normal: 1 (or 0 when decrypted). More than 1 means files encrypted under another wallet's password are mixed in — they will NOT decrypt with this wallet's password.
encrypted_files_existboolencrypted_count > 0.
login_requiredboolConvenience: encrypted files exist AND key_state != "confirmed". Branch on this in the client.
key_setboolLegacy compatibility flag: some password/key material is held in RAM. Prefer key_state.

503 — Scan failed

Unable to scan wallet for encrypted files — the folder walk failed or was incomplete. Treat as transient: keep the user at the prompt and retry; do not guess a state.

Decision table for clients

statelogin_requiredWhat the client should do
decryptedfalseNo password prompt. Show the dashboard. The Security menu offers "Encrypt coins".
encrypted / mixedtruePrompt for the password BEFORE the dashboard appears and POST to /api/system/load-password. Stay off the dashboard until key_state is confirmed.
encryptedfalseSession already confirmed. Show the dashboard; Security menu offers "Decrypt coins".
mixedfalseSession confirmed but a bulk run was interrupted. Offer "Finish Encrypting" / "Finish Decrypting" (re-run the same bulk endpoint — both are idempotent).

Example Usage

curl "http://localhost:8080/api/system/encryption-status"
const res = await fetch('http://localhost:8080/api/system/encryption-status');
const s = await res.json();

if (s.login_required) {
  // show password prompt BEFORE the dashboard,
  // then POST /api/system/load-password
} else if (s.state === 'decrypted') {
  // no prompt; Security menu offers "Encrypt coins"
} else if (s.state === 'mixed') {
  // offer "Finish Encrypting" / "Finish Decrypting"
}
if (s.corrupt_type10 > 0 || s.salt_domains > 1) {
  // surface a support warning; see /api/system/copy_undecryptable
}
import requests
s = requests.get('http://localhost:8080/api/system/encryption-status').json()
print(s['state'], s['key_state'], s['login_required'])
# encrypted none True

Related Endpoints