{"openapi":"3.0.3","info":{"title":"laConsoleAPI — LA admin console API","version":"1.0.0","description":"Admin console API for Last Arzi. Zero-knowledge-aware: the server handles only ciphertext envelopes, key wraps, salts and hashes — never plaintext secrets. Admins authenticate via laBackEnd (POST /api/v1/zk/auth/login) and present that JWT here as `Authorization: Bearer <token>`; every /api/v1/console/* route additionally requires the `admin` role.","contact":{"name":"Last Arzi","url":"https://app.lastarzi.com"}},"servers":[{"url":"/","description":"Current host"}],"tags":[{"name":"System","description":"Health & liveness (public, no auth)"},{"name":"Content","description":"Public, read-only content for the web app — dropdowns + language packs (no auth)"},{"name":"Console","description":"Admin identity, role management, audit & encryption-health (admin JWT)"},{"name":"Dropdowns","description":"Content-managed option lists (admin read + write)"},{"name":"Languages","description":"Server-managed UI translation packs (admin)"},{"name":"Billing","description":"Subscriptions, invoices, refunds (admin)"},{"name":"Integrations","description":"Third-party / partner integrations (admin)"},{"name":"Field Schema","description":"Dynamic asset/liability field schemas (admin)"},{"name":"Postman Templates","description":"Message templates for the Postman feature (admin)"},{"name":"Death Certificate","description":"Death-certificate release review queue + document SAS (admin)"},{"name":"Users","description":"Admin user management / dashboard (admin)"}],"components":{"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"JWT"}},"schemas":{"Error":{"type":"object","properties":{"message":{"type":"string"},"isError":{"type":"boolean"}}},"SubscriptionView":{"type":"object","description":"Billing subscription/order record (non-ZK metadata; no card data is stored).","properties":{"_id":{"type":"string"},"user":{"type":"string","description":"User ObjectId"},"planId":{"type":"string"},"planName":{"type":"string"},"amount":{"type":"number","description":"Major units (e.g. INR rupees)"},"currency":{"type":"string","example":"INR"},"interval":{"type":"string","enum":["monthly","annual","one_time"],"nullable":true},"razorpayOrderId":{"type":"string"},"razorpayPaymentId":{"type":"string"},"status":{"type":"string","enum":["created","active","failed","paused","refunded","canceled"]},"activatedAt":{"type":"string","format":"date-time","nullable":true},"refund":{"type":"object","properties":{"refundId":{"type":"string","nullable":true},"amount":{"type":"number","nullable":true},"reason":{"type":"string","nullable":true},"gateway":{"type":"string","nullable":true,"description":"razorpay | manual"},"refundedAt":{"type":"string","format":"date-time","nullable":true}}},"purgedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Integration":{"type":"object","description":"B2B integration link — lifecycle/status metadata only; never tokens or secrets.","properties":{"integrationId":{"type":"string","format":"uuid"},"ownerId":{"type":"string"},"type":{"type":"string","enum":["executor","bank","insurance","password_manager"]},"provider":{"type":"string","description":"Display name, e.g. \"HDFC AA\""},"status":{"type":"string","enum":["pending","active","revoked","error"]},"scope":{"type":"array","items":{"type":"string"}},"externalRef":{"type":"string","nullable":true,"description":"Opaque provider ref (not a token)"},"lastSyncAt":{"type":"string","format":"date-time","nullable":true},"nextSyncAt":{"type":"string","format":"date-time","nullable":true},"itemsCount":{"type":"integer"},"lastError":{"type":"string","nullable":true},"revokedAt":{"type":"string","format":"date-time","nullable":true},"tokenIssuedAt":{"type":"string","format":"date-time","nullable":true},"tokenExpiresAt":{"type":"string","format":"date-time","nullable":true},"bank":{"type":"object","nullable":true,"description":"AA consent + masked accounts (type=bank)"},"insurance":{"type":"object","nullable":true,"description":"Policy metadata (type=insurance)"},"passwordImport":{"type":"object","nullable":true,"description":"Import job tracking (type=password_manager)"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"NonSecretWill":{"type":"object","description":"Will lifecycle/execution record (non-secret). The will body lives encrypted in the vault.","properties":{"willId":{"type":"string","format":"uuid"},"ownerId":{"type":"string"},"vaultItemId":{"type":"string","description":"Encrypted will body (VaultItem) reference"},"status":{"type":"string","enum":["draft","finalized","activated","executed"]},"executorNomineeId":{"type":"string","nullable":true},"beneficiaryNomineeIds":{"type":"array","items":{"type":"string"}},"witnesses":{"type":"array","items":{"type":"object","properties":{"name":{"type":"string"},"email":{"type":"string","format":"email"},"verifiedAt":{"type":"string","format":"date-time","nullable":true}}}},"legalDocument":{"type":"object","properties":{"generatedAt":{"type":"string","format":"date-time","nullable":true},"ref":{"type":"string","nullable":true}}},"execution":{"type":"object","properties":{"startedAt":{"type":"string","format":"date-time","nullable":true},"startedByUserId":{"type":"string","nullable":true},"completedAt":{"type":"string","format":"date-time","nullable":true},"steps":{"type":"array","items":{"type":"object"}}}},"finalizedAt":{"type":"string","format":"date-time","nullable":true},"activatedAt":{"type":"string","format":"date-time","nullable":true},"executedAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}},"Dropdown":{"type":"object","description":"Content-managed option lists rendered by the web app forms.","properties":{"_id":{"type":"string"},"assetOption":{"type":"object","additionalProperties":true},"liabilityOption":{"type":"object","additionalProperties":true},"nomineeRelation":{"type":"array","items":{}},"passwordTypes":{"type":"array","items":{}},"diaryOptions":{"type":"array","items":{}},"dailySpendsLabels":{"type":"array","items":{}}}},"LocaleMeta":{"type":"object","description":"Language switcher metadata (no translation payload).","properties":{"code":{"type":"string","example":"en"},"name":{"type":"string","example":"English"},"nativeName":{"type":"string"},"flag":{"type":"string"},"dir":{"type":"string","enum":["ltr","rtl"]},"enabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}}},"LocalePack":{"type":"object","description":"Full language pack — metadata plus the nested { Section: { key: value } } translations.","properties":{"code":{"type":"string"},"name":{"type":"string"},"nativeName":{"type":"string"},"flag":{"type":"string"},"dir":{"type":"string","enum":["ltr","rtl"]},"enabled":{"type":"boolean"},"translations":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"}}},"updatedAt":{"type":"string","format":"date-time"}}}},"responses":{"Unauthorized":{"description":"Missing or invalid bearer token","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"message":"Unauthorized — missing bearer token"}}}},"Forbidden":{"description":"Authenticated but lacking the admin role","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"},"example":{"message":"Forbidden — admin only"}}}},"BadRequest":{"description":"Invalid request body or parameters","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"paths":{"/api/v1/console/me":{"get":{"tags":["Console"],"operationId":"consoleGetMe","summary":"Echo the authenticated admin identity from the verified JWT","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Authenticated admin identity","content":{"application/json":{"schema":{"type":"object","properties":{"uid":{"type":"string","nullable":true},"user":{"type":"string","nullable":true},"roles":{"type":"array","items":{"type":"string"}}}},"example":{"uid":"664f1a2b3c4d5e6f7a8b9c0d","user":"admin@example.com","roles":["admin"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/ping":{"get":{"tags":["Console"],"operationId":"consolePing","summary":"Authenticated liveness probe for the console shell","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Liveness response","content":{"application/json":{"schema":{"type":"object","properties":{"pong":{"type":"boolean"},"at":{"type":"string","format":"date-time"}}},"example":{"pong":true,"at":"2026-06-23T10:15:30.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/admins":{"get":{"tags":["Console"],"operationId":"consoleListAdmins","summary":"List all users holding the admin role","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Array of admin users (email and roles only)","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string","format":"email"},"roles":{"type":"array","items":{"type":"string"}}}}},"example":[{"_id":"664f1a2b3c4d5e6f7a8b9c0d","email":"admin@example.com","roles":["admin"]}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/grant-role":{"post":{"tags":["Console"],"operationId":"consoleGrantRole","summary":"Grant a role to a user by email","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","role"],"properties":{"email":{"type":"string","format":"email","description":"Email of the target user"},"role":{"type":"string","enum":["admin"],"description":"Role to grant (currently only 'admin' is known)"}}},"example":{"email":"user@example.com","role":"admin"}}}},"responses":{"200":{"description":"Updated user email and roles","content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"roles":{"type":"array","items":{"type":"string"}}}},"example":{"email":"user@example.com","roles":["admin"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/revoke-role":{"post":{"tags":["Console"],"operationId":"consoleRevokeRole","summary":"Revoke a role from a user by email","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["email","role"],"properties":{"email":{"type":"string","format":"email","description":"Email of the target user"},"role":{"type":"string","description":"Role to revoke"}}},"example":{"email":"user@example.com","role":"admin"}}}},"responses":{"200":{"description":"Updated user email and roles","content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string","format":"email"},"roles":{"type":"array","items":{"type":"string"}}}},"example":{"email":"user@example.com","roles":[]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/audit":{"get":{"tags":["Console"],"operationId":"consoleListAuditLog","summary":"Query the immutable audit trail (non-sensitive event metadata only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by owner or actor user id"},{"name":"action","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by audit action (must be a known AuditLog.ACTIONS value)"},{"name":"outcome","in":"query","required":false,"schema":{"type":"string","enum":["allowed","denied"]},"description":"Filter by event outcome"},{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Inclusive lower bound on event timestamp; invalid dates are ignored"},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date-time"},"description":"Inclusive upper bound (end of day) on event timestamp; invalid dates are ignored"},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"1-based page number"},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size (clamped between 1 and 200)"}],"responses":{"200":{"description":"Paginated audit entries","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"type":"object","properties":{"action":{"type":"string"},"outcome":{"type":"string","enum":["allowed","denied"]},"actorUserId":{"type":"string","nullable":true},"actorEmail":{"type":"string","nullable":true},"ownerId":{"type":"string","nullable":true},"nomineeId":{"type":"string","nullable":true},"scope":{"type":"string","nullable":true},"reason":{"type":"string","nullable":true},"ip":{"type":"string","nullable":true},"at":{"type":"string","format":"date-time"}}}},"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"}}},"example":{"entries":[{"action":"role.grant","outcome":"allowed","actorUserId":"664f...","actorEmail":"admin@example.com","ownerId":null,"nomineeId":null,"scope":null,"reason":"admin:user@example.com","ip":"203.0.113.5","at":"2026-06-23T09:00:00.000Z"}],"page":1,"limit":50,"total":1,"hasMore":false}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/encryption-health":{"get":{"tags":["Console"],"operationId":"consoleEncryptionHealth","summary":"Compliance and encryption-health summary (derived data only)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Aggregated encryption-health metrics","content":{"application/json":{"schema":{"type":"object","properties":{"vault":{"type":"object","properties":{"total":{"type":"integer"},"encrypted":{"type":"integer"},"unencrypted":{"type":"integer","description":"Integrity flag — expected 0"},"encryptedPct":{"type":"number"}}},"users":{"type":"object","properties":{"total":{"type":"integer"},"zkEnabled":{"type":"integer"},"zkPct":{"type":"number"}}},"audit":{"type":"object","properties":{"total":{"type":"integer"},"oldestAt":{"type":"string","format":"date-time","nullable":true},"newestAt":{"type":"string","format":"date-time","nullable":true},"deniedTotal":{"type":"integer"}}},"logins":{"type":"object","properties":{"failed24h":{"type":"integer"},"failedTotal":{"type":"integer"}}},"keyRotations":{"type":"object","properties":{"total":{"type":"integer"},"last30d":{"type":"integer"}}},"nomineeAccess":{"type":"object","properties":{"keyWrapFetches":{"type":"integer"},"releasedVaultReads":{"type":"integer"}}},"generatedAt":{"type":"string","format":"date-time"}}},"example":{"vault":{"total":1240,"encrypted":1240,"unencrypted":0,"encryptedPct":100},"users":{"total":530,"zkEnabled":528,"zkPct":99.62},"audit":{"total":8421,"oldestAt":"2026-01-01T00:00:00.000Z","newestAt":"2026-06-23T09:00:00.000Z","deniedTotal":12},"logins":{"failed24h":3,"failedTotal":87},"keyRotations":{"total":45,"last30d":6},"nomineeAccess":{"keyWrapFetches":9,"releasedVaultReads":4},"generatedAt":"2026-06-23T10:15:30.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/dropdowns":{"get":{"tags":["Dropdowns"],"operationId":"listDropdowns","summary":"List all dropdown option-list records","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Array of dropdown records","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","example":"665f1a2b3c4d5e6f7a8b9c0d"},"assetOption":{"type":"object","description":"Asset option list (free-form object)"},"liabilityOption":{"type":"object","description":"Liability option list (free-form object)"},"nomineeRelation":{"type":"array","items":{},"description":"Nominee relation options"},"passwordTypes":{"type":"array","items":{},"description":"Password type options"},"diaryOptions":{"type":"array","items":{},"description":"Diary options"},"dailySpendsLabels":{"type":"array","items":{},"description":"Daily spends labels"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/dropdowns/add":{"post":{"tags":["Dropdowns"],"operationId":"addDropdown","summary":"Create a new dropdown option-list record","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"assetOption":{"type":"object","description":"Asset option list (free-form object)"},"liabilityOption":{"type":"object","description":"Liability option list (free-form object)"},"nomineeRelation":{"type":"array","items":{},"description":"Nominee relation options"},"passwordTypes":{"type":"array","items":{},"description":"Password type options"},"diaryOptions":{"type":"array","items":{},"description":"Diary options"},"dailySpendsLabels":{"type":"array","items":{},"description":"Daily spends labels"}}}}}},"responses":{"200":{"description":"The created dropdown record","content":{"application/json":{"schema":{"type":"object","properties":{"_id":{"type":"string","example":"665f1a2b3c4d5e6f7a8b9c0d"},"assetOption":{"type":"object"},"liabilityOption":{"type":"object"},"nomineeRelation":{"type":"array","items":{}},"passwordTypes":{"type":"array","items":{}},"diaryOptions":{"type":"array","items":{}},"dailySpendsLabels":{"type":"array","items":{}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/dropdowns/update":{"post":{"tags":["Dropdowns"],"operationId":"updateDropdown","summary":"Update an existing dropdown option-list record by _id","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["_id"],"properties":{"_id":{"type":"string","description":"MongoDB id of the dropdown record to update","example":"665f1a2b3c4d5e6f7a8b9c0d"},"assetOption":{"type":"object","description":"Asset option list (free-form object)"},"liabilityOption":{"type":"object","description":"Liability option list (free-form object)"},"nomineeRelation":{"type":"array","items":{},"description":"Nominee relation options"},"passwordTypes":{"type":"array","items":{},"description":"Password type options"},"diaryOptions":{"type":"array","items":{},"description":"Diary options"},"dailySpendsLabels":{"type":"array","items":{},"description":"Daily spends labels"}}}}}},"responses":{"200":{"description":"The pre-update dropdown record (returns null if no record matched _id)","content":{"application/json":{"schema":{"type":"object","nullable":true,"properties":{"_id":{"type":"string","example":"665f1a2b3c4d5e6f7a8b9c0d"},"assetOption":{"type":"object"},"liabilityOption":{"type":"object"},"nomineeRelation":{"type":"array","items":{}},"passwordTypes":{"type":"array","items":{}},"diaryOptions":{"type":"array","items":{}},"dailySpendsLabels":{"type":"array","items":{}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/languages":{"get":{"tags":["Languages"],"operationId":"listLanguages","summary":"List language packs (metadata only)","description":"Returns switcher metadata (no translations payload) for enabled languages, or all languages when all=true. Seeds the default catalogue if none exist yet.","security":[{"bearerAuth":[]}],"parameters":[{"name":"all","in":"query","required":false,"schema":{"type":"string","enum":["true"]},"description":"When 'true', include disabled languages; otherwise only enabled ones are returned."}],"responses":{"200":{"description":"Array of language metadata.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"nativeName":{"type":"string"},"flag":{"type":"string"},"dir":{"type":"string","enum":["ltr","rtl"]},"enabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}}}},"example":[{"code":"en","name":"English","nativeName":"English","flag":"us","dir":"ltr","enabled":true,"updatedAt":"2026-06-22T10:00:00.000Z"},{"code":"ar","name":"Arabic","nativeName":"العربية","flag":"sa","dir":"rtl","enabled":true,"updatedAt":"2026-06-22T10:00:00.000Z"}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/languages/seed":{"post":{"tags":["Languages"],"operationId":"seedLanguages","summary":"Seed the default language catalogue","description":"Idempotently inserts any missing DEFAULT_LOCALES (metadata only, empty translations) and returns the full catalogue.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Number of languages added plus the full catalogue.","content":{"application/json":{"schema":{"type":"object","properties":{"added":{"type":"integer","description":"How many default locales were inserted."},"total":{"type":"integer","description":"Total number of language packs after seeding."},"locales":{"type":"array","items":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"nativeName":{"type":"string"},"flag":{"type":"string"},"dir":{"type":"string","enum":["ltr","rtl"]},"enabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"example":{"added":2,"total":9,"locales":[{"code":"en","name":"English","nativeName":"English","flag":"us","dir":"ltr","enabled":true,"updatedAt":"2026-06-22T10:00:00.000Z"}]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/languages/{code}":{"get":{"tags":["Languages"],"operationId":"getLanguage","summary":"Get a full language pack","description":"Returns the full translation pack for the given code. Falls back to English when the requested code is unknown; 404 only if English is also absent.","security":[{"bearerAuth":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Language code (case-insensitive, e.g. 'en', 'hi')."}],"responses":{"200":{"description":"Full language pack including translations.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"nativeName":{"type":"string"},"flag":{"type":"string"},"dir":{"type":"string","enum":["ltr","rtl"]},"enabled":{"type":"boolean"},"translations":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"}},"description":"Nested { Section: { key: value } } translation map."},"updatedAt":{"type":"string","format":"date-time"}}},"example":{"code":"en","name":"English","nativeName":"English","flag":"us","dir":"ltr","enabled":true,"translations":{"Common":{"save":"Save","cancel":"Cancel"}},"updatedAt":"2026-06-22T10:00:00.000Z"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["Languages"],"operationId":"upsertLanguage","summary":"Create or replace a language pack","description":"Creates a new language pack or replaces the provided fields of an existing one. 'name' is required when creating. Returns 201 on create, 200 on update.","security":[{"bearerAuth":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Language code (case-insensitive; trimmed and lowercased)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"name":{"type":"string","description":"Display name. Required when creating a new language."},"nativeName":{"type":"string","description":"Name in the language's own script."},"flag":{"type":"string","description":"Flag identifier (e.g. country code)."},"dir":{"type":"string","enum":["ltr","rtl"],"description":"Text direction."},"enabled":{"type":"boolean","description":"Whether the language is visible in the switcher."},"translations":{"type":"object","additionalProperties":{"type":"object","additionalProperties":{"type":"string"}},"description":"Full { Section: { key: value } } translation map (replaces existing)."}},"example":{"name":"Hindi","nativeName":"हिंदी","flag":"in","dir":"ltr","enabled":true,"translations":{"Common":{"save":"सहेजें"}}}}}}},"responses":{"200":{"description":"Existing language pack updated; returns metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"nativeName":{"type":"string"},"flag":{"type":"string"},"dir":{"type":"string","enum":["ltr","rtl"]},"enabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}}},"example":{"code":"hi","name":"Hindi","nativeName":"हिंदी","flag":"in","dir":"ltr","enabled":true,"updatedAt":"2026-06-22T10:00:00.000Z"}}}},"201":{"description":"New language pack created; returns metadata.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"name":{"type":"string"},"nativeName":{"type":"string"},"flag":{"type":"string"},"dir":{"type":"string","enum":["ltr","rtl"]},"enabled":{"type":"boolean"},"updatedAt":{"type":"string","format":"date-time"}}},"example":{"code":"hi","name":"Hindi","nativeName":"हिंदी","flag":"in","dir":"ltr","enabled":true,"updatedAt":"2026-06-22T10:00:00.000Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"delete":{"tags":["Languages"],"operationId":"deleteLanguage","summary":"Delete a language pack","security":[{"bearerAuth":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Language code (case-insensitive) to delete."}],"responses":{"200":{"description":"Language pack deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"deleted":{"type":"boolean"}}},"example":{"code":"hi","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/languages/{code}/sections/{section}":{"patch":{"tags":["Languages"],"operationId":"patchLanguageSection","summary":"Merge keys into one translation section","description":"Shallow-merges the provided keys into the named section of the language pack's translations, creating the section if absent.","security":[{"bearerAuth":[]}],"parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"Language code (case-insensitive)."},{"name":"section","in":"path","required":true,"schema":{"type":"string"},"description":"Translation section name to merge keys into."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["keys"],"properties":{"keys":{"type":"object","additionalProperties":{"type":"string"},"description":"Map of { key: value } strings to merge into the section."}},"example":{"keys":{"save":"Save","cancel":"Cancel"}}}}}},"responses":{"200":{"description":"Section after the merge.","content":{"application/json":{"schema":{"type":"object","properties":{"code":{"type":"string"},"section":{"type":"string"},"keys":{"type":"object","additionalProperties":{"type":"string"}},"updatedAt":{"type":"string","format":"date-time"}}},"example":{"code":"en","section":"Common","keys":{"save":"Save","cancel":"Cancel"},"updatedAt":"2026-06-22T10:00:00.000Z"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/billing/metrics":{"get":{"tags":["Billing"],"operationId":"getBillingMetrics","summary":"Get derived billing/revenue analytics","description":"Returns derived revenue analytics: status counts, churn rate, and per-currency MRR/ARPU/LTV plus per-plan counts. Monetary figures are grouped by currency; purged (GDPR) rows are excluded.","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Aggregated billing metrics","content":{"application/json":{"schema":{"type":"object","properties":{"totalSubscriptions":{"type":"integer","example":1240},"activeCount":{"type":"integer","example":870},"newLast30d":{"type":"integer","example":64},"churnRate":{"type":"number","format":"float","example":0.0732},"statusCounts":{"type":"object","additionalProperties":{"type":"integer"},"example":{"active":870,"canceled":60,"refunded":8,"paused":12}},"byCurrency":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string","example":"INR"},"activeCount":{"type":"integer","example":700},"payingUsers":{"type":"integer","example":680},"mrr":{"type":"number","example":245000.5},"activeRevenue":{"type":"number","example":320000},"arpu":{"type":"number","example":360.29},"ltv":{"type":"number","nullable":true,"example":4922.3}}}},"byPlan":{"type":"array","items":{"type":"object","properties":{"planName":{"type":"string","example":"Pro Annual"},"count":{"type":"integer","example":320}}}},"mrrNote":{"type":"string"},"generatedAt":{"type":"string","format":"date-time"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/billing/subscriptions":{"get":{"tags":["Billing"],"operationId":"listBillingSubscriptions","summary":"List subscriptions (paginated, filterable)","description":"Returns a paginated list of subscriptions, optionally filtered by user, status, or plan name. No card data is returned.","security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by subscription status (e.g. active, paused, canceled, refunded)."},{"name":"userId","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by owning user id."},{"name":"plan","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by exact plan name (matches planName)."},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"Page number (1-based)."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size (clamped between 1 and 200)."}],"responses":{"200":{"description":"Paginated subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/SubscriptionView"}},"page":{"type":"integer","example":1},"limit":{"type":"integer","example":50},"total":{"type":"integer","example":1240},"hasMore":{"type":"boolean","example":true}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/billing/subscriptions/{id}/refund":{"post":{"tags":["Billing"],"operationId":"refundSubscription","summary":"Refund a subscription","description":"Issues a refund for a subscription. With Razorpay configured and a captured payment, calls the gateway; otherwise records a manual offline refund. Either path sets status=refunded and writes an audit entry.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Subscription id to refund."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"amount":{"type":"number","description":"Refund amount; defaults to the full subscription amount. Must be > 0 and not exceed the subscription amount."},"reason":{"type":"string","description":"Optional human-readable refund reason (recorded in the audit trail)."}}}}}},"responses":{"200":{"description":"Refunded subscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Subscription already refunded","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Subscription already refunded"}}}}}},"502":{"description":"Gateway refund failed","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Gateway refund failed"}}}}}}}}},"/api/v1/console/billing/subscriptions/{id}/override":{"post":{"tags":["Billing"],"operationId":"overrideSubscription","summary":"Override subscription plan/status","description":"Loyalty/testing override: change plan fields, interval, or set status to active/paused/canceled. At least one override field must be supplied. Audited.","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Subscription id to override."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"At least one of these fields must be provided.","properties":{"status":{"type":"string","enum":["active","paused","canceled"],"description":"New subscription status (admin-settable subset)."},"planId":{"type":"string","description":"New plan id."},"planName":{"type":"string","description":"New plan name."},"amount":{"type":"number","description":"New subscription amount."},"interval":{"type":"string","nullable":true,"enum":["monthly","annual","one_time"],"description":"Billing interval (backfilled for exact MRR); may be null to clear."},"reason":{"type":"string","description":"Optional reason appended to the audit entry."}}}}}},"responses":{"200":{"description":"Updated subscription","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SubscriptionView"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/billing/users/{userId}/purge":{"post":{"tags":["Billing"],"operationId":"purgeUserBilling","summary":"Anonymize a user's billing records (GDPR)","description":"GDPR right-to-be-forgotten: anonymizes the user's non-purged subscriptions by clearing gateway ids and marking them purged so analytics exclude them. Rows are retained (anonymized) for tax/financial law. Audited.","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"User id whose billing records should be anonymized."}],"responses":{"200":{"description":"Purge result","content":{"application/json":{"schema":{"type":"object","properties":{"userId":{"type":"string","example":"64f0c2a1b9e3a2d4f8a1b2c3"},"purged":{"type":"integer","description":"Number of records anonymized","example":3},"purgedAt":{"type":"string","format":"date-time"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/billing/tax-report":{"get":{"tags":["Billing"],"operationId":"getBillingTaxReport","summary":"Get tax report grouped by currency","description":"Returns gross / refunds / net grouped by currency over a period (on activatedAt = revenue recognition). Currency is used as a proxy for tax region. Includes purged rows' amounts.","security":[{"bearerAuth":[]}],"parameters":[{"name":"from","in":"query","required":false,"schema":{"type":"string","format":"date"},"description":"Start of the period (inclusive); parsed as a date. Invalid values are ignored."},{"name":"to","in":"query","required":false,"schema":{"type":"string","format":"date"},"description":"End of the period (inclusive, extended to end-of-day UTC). Invalid values are ignored."},{"name":"currency","in":"query","required":false,"schema":{"type":"string"},"description":"Restrict the report to a single currency code (e.g. INR, USD)."}],"responses":{"200":{"description":"Tax report rows","content":{"application/json":{"schema":{"type":"object","properties":{"from":{"type":"string","nullable":true,"example":"2026-01-01"},"to":{"type":"string","nullable":true,"example":"2026-03-31"},"rows":{"type":"array","items":{"type":"object","properties":{"currency":{"type":"string","example":"INR"},"region":{"type":"string","example":"IN"},"gross":{"type":"number","example":320000},"refunds":{"type":"number","example":4500},"net":{"type":"number","example":315500},"count":{"type":"integer","example":870}}}},"note":{"type":"string"},"generatedAt":{"type":"string","format":"date-time"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/integrations":{"get":{"tags":["Integrations"],"operationId":"listIntegrations","summary":"List integrations (paginated, filterable)","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"query","required":false,"schema":{"type":"string"},"description":"Filter by integration owner id."},{"name":"type","in":"query","required":false,"schema":{"type":"string","enum":["executor","bank","insurance","password_manager"]},"description":"Filter by integration type (ignored if not a known type)."},{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","active","revoked"]},"description":"Filter by status (ignored if not a known status)."},{"name":"page","in":"query","required":false,"schema":{"type":"integer","minimum":1,"default":1},"description":"1-based page number."},{"name":"limit","in":"query","required":false,"schema":{"type":"integer","minimum":1,"maximum":200,"default":50},"description":"Page size, clamped to 1..200."}],"responses":{"200":{"description":"Paginated list of integration views.","content":{"application/json":{"schema":{"type":"object","properties":{"entries":{"type":"array","items":{"$ref":"#/components/schemas/Integration"}},"page":{"type":"integer"},"limit":{"type":"integer"},"total":{"type":"integer"},"hasMore":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Integrations"],"operationId":"createIntegration","summary":"Create (authorize) an integration","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["ownerId","type","provider"],"properties":{"ownerId":{"type":"string","description":"User id that owns the integration."},"type":{"type":"string","enum":["executor","bank","insurance","password_manager"],"description":"Integration type (must be a known type)."},"provider":{"type":"string","description":"Provider/partner name."},"scope":{"type":"array","items":{"type":"string"},"description":"Scope entries; for executor type, 'will:<willId>' entries must reference wills owned by ownerId."},"externalRef":{"type":"string","nullable":true,"description":"Optional external reference id."}}}}}},"responses":{"201":{"description":"Created integration view.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/integrations/{id}":{"get":{"tags":["Integrations"],"operationId":"getIntegration","summary":"Get a single integration by id","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId."}],"responses":{"200":{"description":"Integration view.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/integrations/{id}/will-access":{"get":{"tags":["Integrations"],"operationId":"getIntegrationWillAccess","summary":"Preview the non-secret wills an executor integration can read","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId (must be an executor integration)."}],"responses":{"200":{"description":"Non-secret will documents in the integration's scope owned by the integration owner.","content":{"application/json":{"schema":{"type":"object","properties":{"integrationId":{"type":"string"},"ownerId":{"type":"string"},"provider":{"type":"string"},"wills":{"type":"array","items":{"$ref":"#/components/schemas/NonSecretWill"}},"note":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/integrations/{id}/sync":{"post":{"tags":["Integrations"],"operationId":"syncIntegration","summary":"Trigger a sync (advances bookkeeping timestamps)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Updated integration view after sync.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Integration is revoked and cannot be synced.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/api/v1/console/integrations/{id}/revoke":{"post":{"tags":["Integrations"],"operationId":"revokeIntegration","summary":"Revoke an integration (kills any issued partner token)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{}}}}},"responses":{"200":{"description":"Revoked integration view.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/integrations/{id}/issue-token":{"post":{"tags":["Integrations"],"operationId":"issueIntegrationToken","summary":"Issue (or rotate) a partner bearer token for an executor integration","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId (must be an executor integration)."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"ttlDays":{"type":"integer","minimum":1,"maximum":365,"default":90,"description":"Token lifetime in days, clamped to 1..365 (default 90)."}}}}}},"responses":{"201":{"description":"Newly issued token. The plaintext token is returned exactly once.","content":{"application/json":{"schema":{"type":"object","properties":{"integrationId":{"type":"string"},"token":{"type":"string","description":"Plaintext partner bearer token, shown only once."},"tokenIssuedAt":{"type":"string","format":"date-time"},"tokenExpiresAt":{"type":"string","format":"date-time"},"note":{"type":"string"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"409":{"description":"Integration is revoked and cannot issue a token.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"}}}}}}}}},"/api/v1/console/integrations/{id}/bank":{"patch":{"tags":["Integrations"],"operationId":"updateIntegrationBank","summary":"Update bank/AA consent and masked-account metadata (feature-flagged, metadata only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId (must be a bank integration)."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"aaHandle":{"type":"string","nullable":true,"description":"Account Aggregator handle."},"purposeCode":{"type":"string","nullable":true,"description":"AA consent purpose code."},"consentStatus":{"type":"string","description":"AA consent status (must be a known status)."},"consentExpiry":{"type":"string","format":"date-time","nullable":true,"description":"AA consent expiry date."},"fiTypes":{"type":"array","items":{"type":"string"},"description":"Financial information types."},"accounts":{"type":"array","description":"Linked accounts; only the non-secret whitelist fields are stored, all other fields are dropped.","items":{"type":"object","properties":{"maskedAccountNumber":{"type":"string"},"fipId":{"type":"string"},"fipName":{"type":"string"},"fiType":{"type":"string"},"accountType":{"type":"string"},"currency":{"type":"string"}}}}}}}}},"responses":{"200":{"description":"Updated integration view.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/integrations/{id}/insurance":{"patch":{"tags":["Integrations"],"operationId":"updateIntegrationInsurance","summary":"Update non-secret insurance policy metadata and beneficiary mapping","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId (must be an insurance integration)."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"policyNumberMasked":{"type":"string","nullable":true,"description":"Masked policy number."},"insurer":{"type":"string","nullable":true,"description":"Insurer name."},"policyType":{"type":"string","description":"Policy type (must be a known type)."},"status":{"type":"string","description":"Policy status (must be a known status)."},"premiumFrequency":{"type":"string","nullable":true,"description":"Premium payment frequency."},"premiumDueDate":{"type":"string","format":"date-time","nullable":true,"description":"Next premium due date."},"beneficiaryNomineeIds":{"type":"array","items":{"type":"string"},"description":"Nominee ids; each must be a nominee of the integration owner."}}}}}},"responses":{"200":{"description":"Updated integration view.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/integrations/{id}/password-import":{"patch":{"tags":["Integrations"],"operationId":"updateIntegrationPasswordImport","summary":"Update password-manager import-job metadata (counts/status only)","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"The integrationId (must be a password_manager integration)."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"source":{"type":"string","nullable":true,"description":"Import source/tool name."},"format":{"type":"string","description":"Import file format (must be a known format)."},"status":{"type":"string","description":"Import job status (must be a known status)."},"itemsTotal":{"type":"integer","minimum":0,"description":"Total items in the import batch."},"itemsImported":{"type":"integer","minimum":0,"description":"Number of items successfully imported."},"categories":{"type":"array","items":{"type":"string"},"description":"Category tags for the imported items."},"error":{"type":"string","nullable":true,"description":"Last import error message."}}}}}},"responses":{"200":{"description":"Updated integration view.","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Integration"}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/field-schema/{feature}":{"get":{"tags":["Field Schema"],"operationId":"getFieldSchema","summary":"Get the full field schema document (draft + published) for a feature","security":[{"bearerAuth":[]}],"parameters":[{"name":"feature","in":"path","required":true,"schema":{"type":"string"},"description":"Feature key (must be one of the allowed FieldSchema.FEATURES)."}],"responses":{"200":{"description":"The full schema document for the feature, or null if none exists yet.","content":{"application/json":{"schema":{"nullable":true,"type":"object","properties":{"feature":{"type":"string"},"version":{"type":"integer","example":1},"sections":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"order":{"type":"integer"},"repeatable":{"type":"boolean"}}}},"fields":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"helpText":{"type":"string","nullable":true},"placeholder":{"type":"string","nullable":true},"type":{"type":"string"},"section":{"type":"string","nullable":true},"order":{"type":"integer"},"required":{"type":"boolean"},"min":{"type":"number","nullable":true},"max":{"type":"number","nullable":true},"maxLength":{"type":"number","nullable":true},"regex":{"type":"string","nullable":true},"options":{"type":"array","items":{"type":"object","properties":{"value":{"type":"string"},"label":{"type":"string"},"description":{"type":"string","nullable":true},"emoji":{"type":"string","nullable":true},"color":{"type":"string","nullable":true}}}},"optionsSource":{"type":"string","nullable":true},"format":{"type":"string","nullable":true},"mask":{"type":"string","nullable":true},"listColumn":{"type":"boolean"},"sortable":{"type":"boolean"},"filterable":{"type":"boolean"},"defaultValue":{"nullable":true},"readonly":{"type":"boolean"},"sensitive":{"type":"boolean"},"visibleWhen":{"type":"string","nullable":true}}}},"published":{"type":"object","nullable":true,"properties":{"version":{"type":"integer"},"sections":{"type":"array","items":{"type":"object"}},"fields":{"type":"array","items":{"type":"object"}},"publishedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"put":{"tags":["Field Schema"],"operationId":"saveFieldSchemaDraft","summary":"Replace the draft (sections + fields) for a feature","security":[{"bearerAuth":[]}],"parameters":[{"name":"feature","in":"path","required":true,"schema":{"type":"string"},"description":"Feature key (must be one of the allowed FieldSchema.FEATURES)."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["fields"],"properties":{"sections":{"type":"array","description":"Section definitions. Each must have a key matching /^[a-zA-Z][a-zA-Z0-9_]*$/.","items":{"type":"object","required":["key"],"properties":{"key":{"type":"string","description":"Stable section identifier."},"label":{"type":"string"},"order":{"type":"integer"},"repeatable":{"type":"boolean"}}}},"fields":{"type":"array","description":"Field definitions (metadata only). Keys must be unique and match /^[a-zA-Z][a-zA-Z0-9_]*$/; label required; type must be one of FieldSchema.FIELD_TYPES.","items":{"type":"object","required":["key","label","type"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"helpText":{"type":"string","nullable":true},"placeholder":{"type":"string","nullable":true},"type":{"type":"string"},"section":{"type":"string","nullable":true},"order":{"type":"integer"},"required":{"type":"boolean"},"min":{"type":"number","nullable":true},"max":{"type":"number","nullable":true},"maxLength":{"type":"number","nullable":true},"regex":{"type":"string","nullable":true},"options":{"type":"array","items":{"type":"object","properties":{"value":{},"label":{"type":"string"},"description":{"type":"string","nullable":true},"emoji":{"type":"string","nullable":true},"color":{"type":"string","nullable":true}}}},"optionsSource":{"type":"string","nullable":true},"format":{"type":"string","nullable":true},"mask":{"type":"string","nullable":true},"listColumn":{"type":"boolean"},"sortable":{"type":"boolean"},"filterable":{"type":"boolean"},"defaultValue":{"nullable":true},"readonly":{"type":"boolean"},"sensitive":{"type":"boolean"},"visibleWhen":{"type":"string","nullable":true}}}}}}}}},"responses":{"200":{"description":"The updated (upserted) schema document with the saved draft.","content":{"application/json":{"schema":{"type":"object","properties":{"feature":{"type":"string"},"version":{"type":"integer","example":1},"sections":{"type":"array","items":{"type":"object"}},"fields":{"type":"array","items":{"type":"object"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/field-schema/{feature}/publish":{"post":{"tags":["Field Schema"],"operationId":"publishFieldSchema","summary":"Publish the current draft as a versioned snapshot for a feature","security":[{"bearerAuth":[]}],"parameters":[{"name":"feature","in":"path","required":true,"schema":{"type":"string"},"description":"Feature key whose existing draft will be published."}],"requestBody":{"required":false,"description":"No request body fields are read by the controller; the draft already stored is snapshotted.","content":{"application/json":{"schema":{"type":"object"}}}},"responses":{"200":{"description":"The schema document after publishing, with the new published snapshot and bumped draft version.","content":{"application/json":{"schema":{"type":"object","properties":{"feature":{"type":"string"},"version":{"type":"integer","description":"Next draft version (bumped after publish).","example":2},"sections":{"type":"array","items":{"type":"object"}},"fields":{"type":"array","items":{"type":"object"}},"published":{"type":"object","properties":{"version":{"type":"integer","example":1},"sections":{"type":"array","items":{"type":"object"}},"fields":{"type":"array","items":{"type":"object"}},"publishedAt":{"type":"string","format":"date-time"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/postman-templates":{"get":{"tags":["Postman Templates"],"operationId":"listPostmanTemplates","summary":"List all Postman message templates","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"All templates, sorted by order then name.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"templateId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"subject":{"type":"string","nullable":true},"body":{"type":"string"},"variables":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"default":{"type":"string","nullable":true},"sample":{"type":"string","nullable":true}}}},"status":{"type":"string","enum":["active","disabled"]},"order":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}},"example":[{"templateId":"b3f1c0a2-7e4d-4c2b-9f1a-1a2b3c4d5e6f","name":"Letter to my children","description":"A heartfelt farewell letter","category":"Personal","subject":"A message for you","body":"Dear {firstName}, on {date} ...","variables":[{"key":"firstName","label":"First name","default":null,"sample":"Alex"},{"key":"date","label":"Date","default":null,"sample":"2026-06-23"}],"status":"active","order":0,"createdAt":"2026-06-01T10:00:00.000Z","updatedAt":"2026-06-10T12:30:00.000Z"}]}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Postman Templates"],"operationId":"createPostmanTemplate","summary":"Create a Postman message template","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string","description":"Template display name (required)."},"description":{"type":"string","description":"Optional description."},"category":{"type":"string","description":"Optional grouping category."},"subject":{"type":"string","description":"Optional message subject line."},"body":{"type":"string","description":"Template text with {variable} placeholders."},"variables":{"type":"array","description":"Merge variables. Each key must match ^[a-zA-Z][a-zA-Z0-9_]*$; invalid entries are dropped.","items":{"type":"object","required":["key"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"default":{"type":"string","nullable":true},"sample":{"type":"string","nullable":true}}}},"status":{"type":"string","enum":["active","disabled"],"description":"Defaults to active."},"order":{"type":"integer","description":"Sort order; coerced to a number (defaults to 0)."}}},"example":{"name":"Letter to my children","description":"A heartfelt farewell letter","category":"Personal","subject":"A message for you","body":"Dear {firstName}, on {date} ...","variables":[{"key":"firstName","label":"First name","sample":"Alex"}],"status":"active","order":0}}}},"responses":{"201":{"description":"Template created.","content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"subject":{"type":"string","nullable":true},"body":{"type":"string"},"variables":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"default":{"type":"string","nullable":true},"sample":{"type":"string","nullable":true}}}},"status":{"type":"string","enum":["active","disabled"]},"order":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/postman-templates/{id}":{"patch":{"tags":["Postman Templates"],"operationId":"updatePostmanTemplate","summary":"Update a Postman message template","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The templateId of the template to update."}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","description":"Any subset of fields; only provided fields are updated.","properties":{"name":{"type":"string"},"description":{"type":"string"},"category":{"type":"string"},"subject":{"type":"string"},"body":{"type":"string"},"variables":{"type":"array","items":{"type":"object","required":["key"],"properties":{"key":{"type":"string"},"label":{"type":"string"},"default":{"type":"string","nullable":true},"sample":{"type":"string","nullable":true}}}},"status":{"type":"string","enum":["active","disabled"]},"order":{"type":"integer"}}},"example":{"status":"disabled","order":5}}}},"responses":{"200":{"description":"Updated template.","content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"type":"string","format":"uuid"},"name":{"type":"string"},"description":{"type":"string","nullable":true},"category":{"type":"string","nullable":true},"subject":{"type":"string","nullable":true},"body":{"type":"string"},"variables":{"type":"array","items":{"type":"object","properties":{"key":{"type":"string"},"label":{"type":"string"},"default":{"type":"string","nullable":true},"sample":{"type":"string","nullable":true}}}},"status":{"type":"string","enum":["active","disabled"]},"order":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Postman Templates"],"operationId":"deletePostmanTemplate","summary":"Delete a Postman message template","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string","format":"uuid"},"description":"The templateId of the template to delete."}],"responses":{"200":{"description":"Template deleted.","content":{"application/json":{"schema":{"type":"object","properties":{"templateId":{"type":"string","format":"uuid"},"deleted":{"type":"boolean"}}},"example":{"templateId":"b3f1c0a2-7e4d-4c2b-9f1a-1a2b3c4d5e6f","deleted":true}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/death-cert":{"get":{"tags":["Death Certificate"],"operationId":"listDeathCertRequests","summary":"List death-certificate release requests (optionally filtered by status)","security":[{"bearerAuth":[]}],"parameters":[{"name":"status","in":"query","required":false,"schema":{"type":"string","enum":["pending","verified","rejected"]},"description":"Filter requests by status. Omit to return all requests."}],"responses":{"200":{"description":"Array of death-certificate requests, newest first.","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string","example":"665f1a2b3c4d5e6f7a8b9c0d"},"ownerId":{"type":"string","example":"665f0000000000000000aaaa"},"ownerEmail":{"type":"string","format":"email","example":"owner@example.com"},"requestedByUserId":{"type":"string","example":"665f0000000000000000bbbb"},"requestedByEmail":{"type":"string","format":"email","example":"executor@example.com"},"documentRef":{"type":"string","example":"665f0000000000000000aaaa/9b1deb4d-3b7d-4bad-9bdd-2b0d7b3dcb6d.pdf"},"blobContainer":{"type":"string","example":"deathcerts"},"contentType":{"type":"string","example":"application/pdf"},"sizeBytes":{"type":"integer","example":482311},"note":{"type":"string","example":"Certified copy attached."},"status":{"type":"string","enum":["pending","verified","rejected"],"example":"pending"},"rejectionReason":{"type":"string","example":""},"verifiedAt":{"type":"string","format":"date-time"},"verifiedByUserId":{"type":"string","example":"665f0000000000000000cccc"},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/death-cert/{id}/document":{"get":{"tags":["Death Certificate"],"operationId":"getDeathCertDocumentSas","summary":"Get a short-lived read SAS URL for a request's death-certificate document","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Death-certificate request id."}],"responses":{"200":{"description":"A read URL for the document. For internally stored blobs a time-limited SAS URL is returned with an expiry; for externally referenced documents the stored URL is returned with external=true.","content":{"application/json":{"schema":{"type":"object","properties":{"url":{"type":"string","example":"https://acct.blob.core.windows.net/deathcerts/665f.../doc.pdf?sv=...&sig=..."},"expiresInMinutes":{"type":"integer","example":15},"external":{"type":"boolean","example":false}},"required":["url"]}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"},"503":{"description":"Blob storage is not configured on the server.","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"Blob storage not configured"}}}}}}}}},"/api/v1/console/death-cert/{id}/verify":{"post":{"tags":["Death Certificate"],"operationId":"verifyDeathCert","summary":"Verify a death-certificate request and set the owner's death-cert verified timestamp","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Death-certificate request id."}],"requestBody":{"required":false,"description":"No body fields are read by the handler; the request is identified by the path id.","content":{"application/json":{"schema":{"type":"object","additionalProperties":false}}}},"responses":{"200":{"description":"Request verified (or already verified). On first verification the owner's zk.release.deathCertVerifiedAt is set.","content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","example":"665f1a2b3c4d5e6f7a8b9c0d"},"status":{"type":"string","example":"verified"},"alreadyVerified":{"type":"boolean","example":false},"deathCertVerifiedAt":{"type":"string","format":"date-time"},"note":{"type":"string","example":"Nominees with triggerType=executor_death_cert release after the 14-day hold."}},"required":["requestId","status"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/death-cert/{id}/reject":{"post":{"tags":["Death Certificate"],"operationId":"rejectDeathCert","summary":"Reject a death-certificate request with an optional reason","security":[{"bearerAuth":[]}],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Death-certificate request id."}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rejectionReason":{"type":"string","description":"Optional reason stored on the request and audit log.","example":"Document illegible / could not be validated."}}}}}},"responses":{"200":{"description":"Request marked as rejected.","content":{"application/json":{"schema":{"type":"object","properties":{"requestId":{"type":"string","example":"665f1a2b3c4d5e6f7a8b9c0d"},"status":{"type":"string","example":"rejected"}},"required":["requestId","status"]}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/console/users":{"get":{"tags":["Users"],"operationId":"fetchAllUsers","summary":"List all users (password field excluded)","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Array of users with the password field excluded","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"username":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"createdAt":{"type":"string","format":"date-time"},"updatedAt":{"type":"string","format":"date-time"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}},"post":{"tags":["Users"],"operationId":"createUsers","summary":"Bulk-create users from an array","security":[{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["users"],"properties":{"users":{"type":"array","description":"Array of user objects to create. Each is persisted via User.create.","items":{"type":"object","properties":{"email":{"type":"string"},"username":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"profileBasicInfo":{"type":"object","properties":{"salutation":{"type":"string"},"gender":{"type":"string"},"dateOfBirth":{"type":"string","format":"date"},"firstName":{"type":"string"},"middleName":{"type":"string"},"lastName":{"type":"string"}}}}}}}}}}},"responses":{"201":{"description":"Created user documents","content":{"application/json":{"schema":{"type":"array","items":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"username":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/users/count":{"get":{"tags":["Users"],"operationId":"usercount","summary":"Get the total user count","security":[{"bearerAuth":[]}],"responses":{"200":{"description":"Total number of user documents","content":{"application/json":{"schema":{"type":"object","properties":{"count":{"type":"integer","example":1287}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"}}}},"/api/v1/console/users/{userId}":{"get":{"tags":["Users"],"operationId":"fetchUserByUserId","summary":"Fetch a single user by id (password field excluded)","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"MongoDB _id of the user"}],"responses":{"200":{"description":"The user document with the password field excluded","content":{"application/json":{"schema":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"username":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"put":{"tags":["Users"],"operationId":"updateUserByUserId","summary":"Replace/update a user by id (full update)","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"MongoDB _id of the user"}],"requestBody":{"required":true,"description":"Arbitrary user fields to update (entire req.body passed to findByIdAndUpdate). Must not contain plaintext secrets (enforced by zkGuard).","content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"profileBasicInfo":{"type":"object","properties":{"firstName":{"type":"string"},"middleName":{"type":"string"},"lastName":{"type":"string"},"salutation":{"type":"string"},"gender":{"type":"string"},"dateOfBirth":{"type":"string","format":"date"}}},"profileContacts":{"type":"object","properties":{"primaryContactNumber":{"type":"string"},"secondaryContactNumber":{"type":"string"},"secondaryEmail":{"type":"string"}}}}}}}},"responses":{"200":{"description":"The updated user document with the password field excluded","content":{"application/json":{"schema":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"patch":{"tags":["Users"],"operationId":"patchUserByUserId","summary":"Partially update a user by id ($set)","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"MongoDB _id of the user"}],"requestBody":{"required":true,"description":"Partial user fields to set (entire req.body applied via $set to findByIdAndUpdate). Must not contain plaintext secrets (enforced by zkGuard).","content":{"application/json":{"schema":{"type":"object","properties":{"email":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}},"profileBasicInfo":{"type":"object","properties":{"firstName":{"type":"string"},"lastName":{"type":"string"}}}}}}}},"responses":{"200":{"description":"The patched user document with the password field excluded","content":{"application/json":{"schema":{"type":"object","properties":{"_id":{"type":"string"},"email":{"type":"string"},"status":{"type":"string"},"roles":{"type":"array","items":{"type":"string"}}}}}}},"400":{"$ref":"#/components/responses/BadRequest"},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}},"delete":{"tags":["Users"],"operationId":"deleteUserByUserId","summary":"Delete a single user by id (no cascade)","security":[{"bearerAuth":[]}],"parameters":[{"name":"userId","in":"path","required":true,"schema":{"type":"string"},"description":"MongoDB _id of the user"}],"responses":{"200":{"description":"User deleted","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string","example":"User deleted successfully"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/Forbidden"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/health":{"get":{"tags":["System"],"operationId":"health","summary":"Liveness + service/version (public)","responses":{"200":{"description":"Service is up","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"service":{"type":"string","example":"laConsoleAPI"},"version":{"type":"string"},"uptime":{"type":"number","description":"Process uptime in seconds"}}}}}}}}},"/api/v1/content/dropdowns":{"get":{"tags":["Content"],"operationId":"contentDropdowns","summary":"Public dropdowns reference data (option lists for the web app)","responses":{"200":{"description":"Array of dropdown documents (usually one)","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/Dropdown"}}}}}}}},"/api/v1/content/languages":{"get":{"tags":["Content"],"operationId":"contentLanguages","summary":"Enabled language list for the switcher (metadata only)","parameters":[{"name":"all","in":"query","required":false,"schema":{"type":"string","enum":["true"]},"description":"Include disabled locales as well"}],"responses":{"200":{"description":"Array of locale metadata","content":{"application/json":{"schema":{"type":"array","items":{"$ref":"#/components/schemas/LocaleMeta"}}}}}}}},"/api/v1/content/languages/{code}":{"get":{"tags":["Content"],"operationId":"contentLanguagePack","summary":"Full language pack for a code (falls back to English when unknown)","parameters":[{"name":"code","in":"path","required":true,"schema":{"type":"string"},"description":"ISO 639-1 code, e.g. en, hi, fr"}],"responses":{"200":{"description":"Language pack with translations","content":{"application/json":{"schema":{"$ref":"#/components/schemas/LocalePack"}}}},"404":{"$ref":"#/components/responses/NotFound"}}}}}}