{ "openapi": "3.1.0", "info": { "title": "Home Automation Backend (Python)", "description": "Home automation backend with auth, runtime config, Home Assistant integrations, TickTick integration, and SQLite-backed recorders.", "version": "0.1.0" }, "paths": { "/status": { "get": { "tags": [ "system" ], "summary": "Get Status", "operationId": "get_status_status_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/StatusResponse" } } } } } } }, "/login": { "get": { "tags": [ "auth" ], "summary": "Login Page", "operationId": "login_page_login_get", "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } } } }, "post": { "tags": [ "auth" ], "summary": "Login Submit", "operationId": "login_submit_login_post", "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/Body_login_submit_login_post" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/config/change-password": { "post": { "tags": [ "auth" ], "summary": "Change Password Submit", "operationId": "change_password_submit_config_change_password_post", "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/Body_change_password_submit_config_change_password_post" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/logout": { "post": { "tags": [ "auth" ], "summary": "Logout", "operationId": "logout_logout_post", "requestBody": { "content": { "application/x-www-form-urlencoded": { "schema": { "$ref": "#/components/schemas/Body_logout_logout_post" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/": { "get": { "tags": [ "pages" ], "summary": "Home", "operationId": "home__get", "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } } } } }, "/admin": { "get": { "tags": [ "pages" ], "summary": "Admin Redirect", "operationId": "admin_redirect_admin_get", "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } } } } }, "/config": { "get": { "tags": [ "pages" ], "summary": "Config Page", "operationId": "config_page_config_get", "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } } } }, "post": { "tags": [ "pages" ], "summary": "Config Submit", "operationId": "config_submit_config_post", "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } } } } }, "/config/smtp/test": { "post": { "tags": [ "pages" ], "summary": "Smtp Test Submit", "operationId": "smtp_test_submit_config_smtp_test_post", "responses": { "200": { "description": "Successful Response", "content": { "text/html": { "schema": { "type": "string" } } } } } } }, "/api/config": { "get": { "tags": [ "api-config" ], "summary": "Get Config", "description": "Return all configuration sections. Secret field values are masked (empty string).", "operationId": "get_config_api_config_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigResponse" } } } } } }, "put": { "tags": [ "api-config" ], "summary": "Put Config", "description": "Save configuration updates.\n\n- Blank secret value keeps the existing stored value (no change).\n- Invalid values return 422 and nothing is written to the database.", "operationId": "put_config_api_config_put", "parameters": [ { "name": "X-CSRF-Token", "in": "header", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "X-Csrf-Token" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigUpdateRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/ConfigUpdateResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/session": { "get": { "tags": [ "api-session" ], "summary": "Get Session", "description": "Return the current session user and CSRF token. Returns 401 if not authenticated.", "operationId": "get_session_api_session_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResponse" } } } } } } }, "/api/auth/login": { "post": { "tags": [ "api-session" ], "summary": "Post Login", "description": "Authenticate with username and password.\n\nOn success, sets an HttpOnly session cookie and returns the session user + CSRF token.\nOn failure, returns 401 with no cookie set.\nNo X-CSRF-Token required (unauthenticated endpoint).", "operationId": "post_login_api_auth_login_post", "requestBody": { "content": { "application/json": { "schema": { "$ref": "#/components/schemas/LoginRequest" } } }, "required": true }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SessionResponse" } } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/auth/logout": { "post": { "tags": [ "api-session" ], "summary": "Post Logout", "description": "Revoke the current session and clear the session cookie.\nRequires authentication and X-CSRF-Token header.\nReturns 204 No Content.", "operationId": "post_logout_api_auth_logout_post", "parameters": [ { "name": "X-CSRF-Token", "in": "header", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "X-Csrf-Token" } } ], "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/api/auth/password": { "post": { "tags": [ "api-session" ], "summary": "Post Change Password", "description": "Change the current user's password.\nRequires authentication and X-CSRF-Token header.\nOn AuthPasswordChangeError returns 400 with a generic message.\nOn success, force_password_change becomes False (handled by the service).\nReturns 204 No Content.", "operationId": "post_change_password_api_auth_password_post", "parameters": [ { "name": "X-CSRF-Token", "in": "header", "required": false, "schema": { "anyOf": [ { "type": "string" }, { "type": "null" } ], "title": "X-Csrf-Token" } } ], "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PasswordChangeRequest" } } } }, "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } }, "422": { "description": "Validation Error", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/HTTPValidationError" } } } } } } }, "/homeassistant/publish": { "post": { "tags": [ "homeassistant" ], "summary": "Publish From Homeassistant", "operationId": "publish_from_homeassistant_homeassistant_publish_post", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/location/record": { "post": { "tags": [ "location" ], "summary": "Create Location Record", "operationId": "create_location_record_location_record_post", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/poo/record": { "post": { "tags": [ "poo" ], "summary": "Create Poo Record", "operationId": "create_poo_record_poo_record_post", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/poo/latest": { "get": { "tags": [ "poo" ], "summary": "Notify Latest Poo", "operationId": "notify_latest_poo_poo_latest_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/public-ip/check": { "get": { "tags": [ "public-ip" ], "summary": "Run Public Ip Check", "operationId": "run_public_ip_check_public_ip_check_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/PublicIPCheckResponse" } } } } } } }, "/ticktick/auth/start": { "get": { "tags": [ "ticktick" ], "summary": "Start Ticktick Auth", "operationId": "start_ticktick_auth_ticktick_auth_start_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } }, "/ticktick/auth/code": { "get": { "tags": [ "ticktick" ], "summary": "Handle Ticktick Auth Code", "operationId": "handle_ticktick_auth_code_ticktick_auth_code_get", "responses": { "200": { "description": "Successful Response", "content": { "application/json": { "schema": {} } } } } } } }, "components": { "schemas": { "Body_change_password_submit_config_change_password_post": { "properties": { "current_password": { "type": "string", "title": "Current Password" }, "new_password": { "type": "string", "title": "New Password" }, "confirm_password": { "type": "string", "title": "Confirm Password" }, "csrf_token": { "type": "string", "title": "Csrf Token" } }, "type": "object", "required": [ "current_password", "new_password", "confirm_password", "csrf_token" ], "title": "Body_change_password_submit_config_change_password_post" }, "Body_login_submit_login_post": { "properties": { "username": { "type": "string", "title": "Username" }, "password": { "type": "string", "title": "Password" }, "csrf_token": { "type": "string", "title": "Csrf Token" } }, "type": "object", "required": [ "username", "password", "csrf_token" ], "title": "Body_login_submit_login_post" }, "Body_logout_logout_post": { "properties": { "csrf_token": { "type": "string", "title": "Csrf Token" } }, "type": "object", "required": [ "csrf_token" ], "title": "Body_logout_logout_post" }, "ConfigField": { "properties": { "env_name": { "type": "string", "title": "Env Name" }, "label": { "type": "string", "title": "Label" }, "value": { "type": "string", "title": "Value" }, "secret": { "type": "boolean", "title": "Secret" }, "input_type": { "type": "string", "title": "Input Type" }, "configured": { "type": "boolean", "title": "Configured" } }, "type": "object", "required": [ "env_name", "label", "value", "secret", "input_type", "configured" ], "title": "ConfigField" }, "ConfigResponse": { "properties": { "sections": { "items": { "$ref": "#/components/schemas/ConfigSection" }, "type": "array", "title": "Sections" } }, "type": "object", "required": [ "sections" ], "title": "ConfigResponse" }, "ConfigSection": { "properties": { "name": { "type": "string", "title": "Name" }, "fields": { "items": { "$ref": "#/components/schemas/ConfigField" }, "type": "array", "title": "Fields" } }, "type": "object", "required": [ "name", "fields" ], "title": "ConfigSection" }, "ConfigUpdateRequest": { "properties": { "updates": { "additionalProperties": { "type": "string" }, "type": "object", "title": "Updates" } }, "type": "object", "required": [ "updates" ], "title": "ConfigUpdateRequest", "description": "Flat mapping of env_name → value, mirroring the existing form semantics." }, "ConfigUpdateResponse": { "properties": { "sections": { "items": { "$ref": "#/components/schemas/ConfigSection" }, "type": "array", "title": "Sections" } }, "type": "object", "required": [ "sections" ], "title": "ConfigUpdateResponse" }, "HTTPValidationError": { "properties": { "detail": { "items": { "$ref": "#/components/schemas/ValidationError" }, "type": "array", "title": "Detail" } }, "type": "object", "title": "HTTPValidationError" }, "LoginRequest": { "properties": { "username": { "type": "string", "title": "Username" }, "password": { "type": "string", "title": "Password" } }, "type": "object", "required": [ "username", "password" ], "title": "LoginRequest" }, "PasswordChangeRequest": { "properties": { "current_password": { "type": "string", "title": "Current Password" }, "new_password": { "type": "string", "title": "New Password" }, "confirm_password": { "type": "string", "title": "Confirm Password" } }, "type": "object", "required": [ "current_password", "new_password", "confirm_password" ], "title": "PasswordChangeRequest" }, "PublicIPCheckResponse": { "properties": { "status": { "type": "string", "enum": [ "first_seen", "unchanged", "changed", "error" ], "title": "Status" }, "checked_at": { "type": "string", "format": "date-time", "title": "Checked At" }, "changed": { "type": "boolean", "title": "Changed" } }, "type": "object", "required": [ "status", "checked_at", "changed" ], "title": "PublicIPCheckResponse" }, "SessionResponse": { "properties": { "user": { "$ref": "#/components/schemas/SessionUser" }, "csrf_token": { "type": "string", "title": "Csrf Token" } }, "type": "object", "required": [ "user", "csrf_token" ], "title": "SessionResponse" }, "SessionUser": { "properties": { "username": { "type": "string", "title": "Username" }, "force_password_change": { "type": "boolean", "title": "Force Password Change" } }, "type": "object", "required": [ "username", "force_password_change" ], "title": "SessionUser" }, "StatusResponse": { "properties": { "status": { "type": "string", "title": "Status" } }, "type": "object", "required": [ "status" ], "title": "StatusResponse" }, "ValidationError": { "properties": { "loc": { "items": { "anyOf": [ { "type": "string" }, { "type": "integer" } ] }, "type": "array", "title": "Location" }, "msg": { "type": "string", "title": "Message" }, "type": { "type": "string", "title": "Error Type" } }, "type": "object", "required": [ "loc", "msg", "type" ], "title": "ValidationError" } } } }