2026-04-19 23:25:13 +02:00
{
"openapi" : "3.1.0" ,
"info" : {
"title" : "Home Automation Backend (Python)" ,
2026-04-20 20:40:04 +02:00
"description" : "Home automation backend with auth, runtime config, Home Assistant integrations, TickTick integration, and SQLite-backed recorders." ,
2026-04-19 23:25:13 +02:00
"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"
}
}
}
}
}
}
} ,
2026-04-20 15:16:47 +02:00
"/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"
}
}
}
}
}
}
} ,
2026-04-20 15:56:10 +02:00
"/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"
}
}
}
}
}
}
} ,
2026-04-20 15:16:47 +02:00
"/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"
}
}
}
}
}
}
} ,
2026-04-19 23:25:13 +02:00
"/" : {
"get" : {
"tags" : [
"pages"
] ,
"summary" : "Home" ,
"operationId" : "home__get" ,
"responses" : {
"200" : {
"description" : "Successful Response" ,
"content" : {
"text/html" : {
"schema" : {
"type" : "string"
}
}
}
}
}
}
} ,
2026-04-20 15:16:47 +02:00
"/admin" : {
"get" : {
"tags" : [
"pages"
] ,
2026-04-20 15:56:10 +02:00
"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" ,
2026-04-20 15:16:47 +02:00
"responses" : {
"200" : {
"description" : "Successful Response" ,
"content" : {
"text/html" : {
"schema" : {
"type" : "string"
}
}
}
}
}
}
} ,
2026-06-12 17:13:28 +02:00
"/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"
}
}
}
}
}
}
} ,
2026-06-12 23:08:14 +02:00
"/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"
}
}
}
}
}
}
} ,
2026-06-12 23:24:17 +02:00
"/api/locations" : {
"get" : {
"tags" : [
"api-data"
] ,
"summary" : "Get Locations" ,
"description" : "Return location records with optional time-window filtering and pagination.\n\n- ``start`` / ``end`` are ISO8601 strings; filtering is **inclusive** on both bounds.\n- Results are ordered by ``datetime`` ascending.\n- ``limit`` is capped at 5000 to prevent full-table exports." ,
"operationId" : "get_locations_api_locations_get" ,
"parameters" : [
{
"name" : "limit" ,
"in" : "query" ,
"required" : false ,
"schema" : {
"type" : "integer" ,
"maximum" : 5000 ,
"minimum" : 1 ,
"default" : 1000 ,
"title" : "Limit"
}
} ,
{
"name" : "offset" ,
"in" : "query" ,
"required" : false ,
"schema" : {
"type" : "integer" ,
"minimum" : 0 ,
"default" : 0 ,
"title" : "Offset"
}
} ,
{
"name" : "start" ,
"in" : "query" ,
"required" : false ,
"schema" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "Start"
}
} ,
{
"name" : "end" ,
"in" : "query" ,
"required" : false ,
"schema" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "End"
}
}
] ,
"responses" : {
"200" : {
"description" : "Successful Response" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/LocationsResponse"
}
}
}
} ,
"422" : {
"description" : "Validation Error" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
} ,
"/api/poo" : {
"get" : {
"tags" : [
"api-data"
] ,
"summary" : "Get Poo" ,
"description" : "Return poo records ordered by timestamp descending (most recent first).\n\n``limit`` is capped at 1000 to prevent full-table exports." ,
"operationId" : "get_poo_api_poo_get" ,
"parameters" : [
{
"name" : "limit" ,
"in" : "query" ,
"required" : false ,
"schema" : {
"type" : "integer" ,
"maximum" : 1000 ,
"minimum" : 1 ,
"default" : 100 ,
"title" : "Limit"
}
} ,
{
"name" : "offset" ,
"in" : "query" ,
"required" : false ,
"schema" : {
"type" : "integer" ,
"minimum" : 0 ,
"default" : 0 ,
"title" : "Offset"
}
}
] ,
"responses" : {
"200" : {
"description" : "Successful Response" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/PooResponse"
}
}
}
} ,
"422" : {
"description" : "Validation Error" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
} ,
"/api/public-ip" : {
"get" : {
"tags" : [
"api-data"
] ,
"summary" : "Get Public Ip" ,
"description" : "Return the current public IP state and recent history.\n\n- ``state`` is ``null`` if no IP check has been performed yet.\n- ``history`` is ordered by ``observed_at`` descending (most recent first).\n- ``limit`` applies to the history list and is capped at 1000." ,
"operationId" : "get_public_ip_api_public_ip_get" ,
"parameters" : [
{
"name" : "limit" ,
"in" : "query" ,
"required" : false ,
"schema" : {
"type" : "integer" ,
"maximum" : 1000 ,
"minimum" : 1 ,
"default" : 100 ,
"title" : "Limit"
}
}
] ,
"responses" : {
"200" : {
"description" : "Successful Response" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/PublicIPResponse"
}
}
}
} ,
"422" : {
"description" : "Validation Error" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
} ,
2026-06-12 23:33:08 +02:00
"/api/locations/{person}/{datetime}" : {
"patch" : {
"tags" : [
"api-data"
] ,
"summary" : "Patch Location" ,
"description" : "Update the non-PK fields of a single location record.\n\n- ``person`` and ``datetime`` identify the row (composite PK) and are immutable.\n- Only ``latitude``, ``longitude``, and ``altitude`` may be updated.\n- Omitted body fields are left unchanged.\n- Returns **404** if the PK does not exist." ,
"operationId" : "patch_location_api_locations__person___datetime__patch" ,
"parameters" : [
{
"name" : "person" ,
"in" : "path" ,
"required" : true ,
"schema" : {
"type" : "string" ,
"title" : "Person"
}
} ,
{
"name" : "datetime" ,
"in" : "path" ,
"required" : true ,
"schema" : {
"type" : "string" ,
"title" : "Datetime"
}
} ,
{
"name" : "X-CSRF-Token" ,
"in" : "header" ,
"required" : false ,
"schema" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "X-Csrf-Token"
}
}
] ,
"requestBody" : {
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/LocationUpdateRequest" ,
"default" : { }
}
}
}
} ,
"responses" : {
"200" : {
"description" : "Successful Response" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/LocationRecord"
}
}
}
} ,
"422" : {
"description" : "Validation Error" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/HTTPValidationError"
}
}
}
}
}
} ,
"delete" : {
"tags" : [
"api-data"
] ,
"summary" : "Delete Location Record" ,
"description" : "Delete the single location record identified by its composite PK.\n\n- Exactly one row is deleted; **404** if the PK does not exist.\n- No batch delete / truncate path is available." ,
"operationId" : "delete_location_record_api_locations__person___datetime__delete" ,
"parameters" : [
{
"name" : "person" ,
"in" : "path" ,
"required" : true ,
"schema" : {
"type" : "string" ,
"title" : "Person"
}
} ,
{
"name" : "datetime" ,
"in" : "path" ,
"required" : true ,
"schema" : {
"type" : "string" ,
"title" : "Datetime"
}
} ,
{
"name" : "X-CSRF-Token" ,
"in" : "header" ,
"required" : false ,
"schema" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "X-Csrf-Token"
}
}
] ,
"responses" : {
"204" : {
"description" : "Successful Response"
} ,
"422" : {
"description" : "Validation Error" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
} ,
"/api/poo/{timestamp}" : {
"patch" : {
"tags" : [
"api-data"
] ,
"summary" : "Patch Poo" ,
"description" : "Update the non-PK fields of a single poo record.\n\n- ``timestamp`` is the PK and is immutable.\n- Only ``status``, ``latitude``, and ``longitude`` may be updated.\n- Omitted body fields are left unchanged.\n- Returns **404** if the PK does not exist." ,
"operationId" : "patch_poo_api_poo__timestamp__patch" ,
"parameters" : [
{
"name" : "timestamp" ,
"in" : "path" ,
"required" : true ,
"schema" : {
"type" : "string" ,
"title" : "Timestamp"
}
} ,
{
"name" : "X-CSRF-Token" ,
"in" : "header" ,
"required" : false ,
"schema" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "X-Csrf-Token"
}
}
] ,
"requestBody" : {
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/PooUpdateRequest" ,
"default" : { }
}
}
}
} ,
"responses" : {
"200" : {
"description" : "Successful Response" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/PooRecord"
}
}
}
} ,
"422" : {
"description" : "Validation Error" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/HTTPValidationError"
}
}
}
}
}
} ,
"delete" : {
"tags" : [
"api-data"
] ,
"summary" : "Delete Poo" ,
"description" : "Delete the single poo record identified by its PK.\n\n- Exactly one row is deleted; **404** if the PK does not exist.\n- No batch delete / truncate path is available." ,
"operationId" : "delete_poo_api_poo__timestamp__delete" ,
"parameters" : [
{
"name" : "timestamp" ,
"in" : "path" ,
"required" : true ,
"schema" : {
"type" : "string" ,
"title" : "Timestamp"
}
} ,
{
"name" : "X-CSRF-Token" ,
"in" : "header" ,
"required" : false ,
"schema" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "X-Csrf-Token"
}
}
] ,
"responses" : {
"204" : {
"description" : "Successful Response"
} ,
"422" : {
"description" : "Validation Error" ,
"content" : {
"application/json" : {
"schema" : {
"$ref" : "#/components/schemas/HTTPValidationError"
}
}
}
}
}
}
} ,
2026-06-12 23:15:56 +02:00
"/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"
}
}
}
}
}
}
} ,
2026-04-20 10:42:35 +02:00
"/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" : { }
}
}
}
}
}
} ,
2026-04-19 23:25:13 +02:00
"/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" : { }
}
}
}
}
}
2026-04-20 11:48:48 +02:00
} ,
"/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" : { }
}
}
}
2026-04-20 20:40:04 +02:00
}
}
} ,
2026-06-12 17:13:28 +02:00
"/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"
}
}
}
}
}
}
} ,
2026-04-20 20:40:04 +02:00
"/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" : { }
}
}
}
2026-04-20 11:48:48 +02:00
}
}
2026-04-19 23:25:13 +02:00
}
} ,
"components" : {
"schemas" : {
2026-04-20 15:56:10 +02:00
"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"
} ,
2026-04-20 15:16:47 +02:00
"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"
} ,
2026-06-12 23:08:14 +02:00
"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"
} ,
2026-04-20 15:16:47 +02:00
"HTTPValidationError" : {
"properties" : {
"detail" : {
"items" : {
"$ref" : "#/components/schemas/ValidationError"
} ,
"type" : "array" ,
"title" : "Detail"
}
} ,
"type" : "object" ,
"title" : "HTTPValidationError"
} ,
2026-06-12 23:24:17 +02:00
"LocationRecord" : {
"properties" : {
"person" : {
"type" : "string" ,
"title" : "Person"
} ,
"datetime" : {
"type" : "string" ,
"title" : "Datetime"
} ,
"latitude" : {
"type" : "number" ,
"title" : "Latitude"
} ,
"longitude" : {
"type" : "number" ,
"title" : "Longitude"
} ,
"altitude" : {
"anyOf" : [
{
"type" : "number"
} ,
{
"type" : "null"
}
] ,
"title" : "Altitude"
}
} ,
"type" : "object" ,
"required" : [
"person" ,
"datetime" ,
"latitude" ,
"longitude" ,
"altitude"
] ,
"title" : "LocationRecord"
} ,
2026-06-12 23:33:08 +02:00
"LocationUpdateRequest" : {
"properties" : {
"latitude" : {
"anyOf" : [
{
"type" : "number"
} ,
{
"type" : "null"
}
] ,
"title" : "Latitude"
} ,
"longitude" : {
"anyOf" : [
{
"type" : "number"
} ,
{
"type" : "null"
}
] ,
"title" : "Longitude"
} ,
"altitude" : {
"anyOf" : [
{
"type" : "number"
} ,
{
"type" : "null"
}
] ,
"title" : "Altitude"
}
} ,
"type" : "object" ,
"title" : "LocationUpdateRequest" ,
"description" : "PATCH body for a location record — all fields optional; PK fields excluded."
} ,
2026-06-12 23:24:17 +02:00
"LocationsResponse" : {
"properties" : {
"items" : {
"items" : {
"$ref" : "#/components/schemas/LocationRecord"
} ,
"type" : "array" ,
"title" : "Items"
} ,
"limit" : {
"type" : "integer" ,
"title" : "Limit"
} ,
"offset" : {
"type" : "integer" ,
"title" : "Offset"
}
} ,
"type" : "object" ,
"required" : [
"items" ,
"limit" ,
"offset"
] ,
"title" : "LocationsResponse"
} ,
2026-06-12 23:15:56 +02:00
"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"
} ,
2026-06-12 23:24:17 +02:00
"PooRecord" : {
"properties" : {
"timestamp" : {
"type" : "string" ,
"title" : "Timestamp"
} ,
"status" : {
"type" : "string" ,
"title" : "Status"
} ,
"latitude" : {
"type" : "number" ,
"title" : "Latitude"
} ,
"longitude" : {
"type" : "number" ,
"title" : "Longitude"
}
} ,
"type" : "object" ,
"required" : [
"timestamp" ,
"status" ,
"latitude" ,
"longitude"
] ,
"title" : "PooRecord"
} ,
"PooResponse" : {
"properties" : {
"items" : {
"items" : {
"$ref" : "#/components/schemas/PooRecord"
} ,
"type" : "array" ,
"title" : "Items"
} ,
"limit" : {
"type" : "integer" ,
"title" : "Limit"
} ,
"offset" : {
"type" : "integer" ,
"title" : "Offset"
}
} ,
"type" : "object" ,
"required" : [
"items" ,
"limit" ,
"offset"
] ,
"title" : "PooResponse"
} ,
2026-06-12 23:33:08 +02:00
"PooUpdateRequest" : {
"properties" : {
"status" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "Status"
} ,
"latitude" : {
"anyOf" : [
{
"type" : "number"
} ,
{
"type" : "null"
}
] ,
"title" : "Latitude"
} ,
"longitude" : {
"anyOf" : [
{
"type" : "number"
} ,
{
"type" : "null"
}
] ,
"title" : "Longitude"
}
} ,
"type" : "object" ,
"title" : "PooUpdateRequest" ,
"description" : "PATCH body for a poo record — all fields optional; PK field excluded."
} ,
2026-06-12 17:13:28 +02:00
"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"
} ,
2026-06-12 23:24:17 +02:00
"PublicIPHistorySchema" : {
"properties" : {
"id" : {
"type" : "integer" ,
"title" : "Id"
} ,
"ipv4" : {
"type" : "string" ,
"title" : "Ipv4"
} ,
"observed_at" : {
"type" : "string" ,
"format" : "date-time" ,
"title" : "Observed At"
} ,
"change_type" : {
"type" : "string" ,
"title" : "Change Type"
} ,
"provider" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "Provider"
}
} ,
"type" : "object" ,
"required" : [
"id" ,
"ipv4" ,
"observed_at" ,
"change_type" ,
"provider"
] ,
"title" : "PublicIPHistorySchema"
} ,
"PublicIPResponse" : {
"properties" : {
"state" : {
"anyOf" : [
{
"$ref" : "#/components/schemas/PublicIPStateSchema"
} ,
{
"type" : "null"
}
]
} ,
"history" : {
"items" : {
"$ref" : "#/components/schemas/PublicIPHistorySchema"
} ,
"type" : "array" ,
"title" : "History"
}
} ,
"type" : "object" ,
"required" : [
"state" ,
"history"
] ,
"title" : "PublicIPResponse"
} ,
"PublicIPStateSchema" : {
"properties" : {
"id" : {
"type" : "integer" ,
"title" : "Id"
} ,
"current_ipv4" : {
"type" : "string" ,
"title" : "Current Ipv4"
} ,
"previous_ipv4" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "Previous Ipv4"
} ,
"first_seen_at" : {
"type" : "string" ,
"format" : "date-time" ,
"title" : "First Seen At"
} ,
"last_checked_at" : {
"type" : "string" ,
"format" : "date-time" ,
"title" : "Last Checked At"
} ,
"last_changed_at" : {
"anyOf" : [
{
"type" : "string" ,
"format" : "date-time"
} ,
{
"type" : "null"
}
] ,
"title" : "Last Changed At"
} ,
"last_check_status" : {
"type" : "string" ,
"title" : "Last Check Status"
} ,
"last_check_error" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "Last Check Error"
} ,
"last_provider" : {
"anyOf" : [
{
"type" : "string"
} ,
{
"type" : "null"
}
] ,
"title" : "Last Provider"
}
} ,
"type" : "object" ,
"required" : [
"id" ,
"current_ipv4" ,
"previous_ipv4" ,
"first_seen_at" ,
"last_checked_at" ,
"last_changed_at" ,
"last_check_status" ,
"last_check_error" ,
"last_provider"
] ,
"title" : "PublicIPStateSchema"
} ,
2026-06-12 23:15:56 +02:00
"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"
} ,
2026-04-19 23:25:13 +02:00
"StatusResponse" : {
"properties" : {
"status" : {
"type" : "string" ,
"title" : "Status"
}
} ,
"type" : "object" ,
"required" : [
"status"
] ,
"title" : "StatusResponse"
2026-04-20 15:16:47 +02:00
} ,
"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"
2026-04-19 23:25:13 +02:00
}
}
}
}