{
  "openapi": "3.1.0",
  "info": {
    "title": "Hungry Machines API",
    "version": "3.0.0",
    "description": "Hungry Machines builds optimized operating schedules for a home's HVAC, EV charger, water heater and battery. Conventions used throughout this API: a schedule is 48 half-hour slots starting at local midnight; temperatures are Fahrenheit; prices are cents per kWh; timestamps are ISO 8601. Errors are returned as `{\"detail\": \"...\"}`. A schedule's per-slot commands are opaque -- apply them as given rather than inferring the state they imply.",
    "contact": {
      "name": "Hungry Machines",
      "url": "https://hungrymachines.io",
      "email": "info@hungrymachines.io"
    }
  },
  "servers": [
    {
      "url": "https://api.hungrymachines.io"
    }
  ],
  "externalDocs": {
    "description": "Hungry Machines developer docs",
    "url": "https://docs.hungrymachines.io/api-reference/openapi/"
  },
  "tags": [
    {
      "name": "Appliance Management",
      "description": "Appliance Management"
    },
    {
      "name": "Authentication",
      "description": "Authentication"
    },
    {
      "name": "Billing",
      "description": "Billing"
    },
    {
      "name": "Calibration (Automatic Warm-Up)",
      "description": "Calibration (Automatic Warm-Up)"
    },
    {
      "name": "Customer Metrics",
      "description": "Customer Metrics"
    },
    {
      "name": "Health Check",
      "description": "Health Check"
    },
    {
      "name": "Per-Appliance Preferences",
      "description": "Per-Appliance Preferences"
    },
    {
      "name": "Rates",
      "description": "Rates"
    },
    {
      "name": "Schedules (Primary Integration Point)",
      "description": "Schedules (Primary Integration Point)"
    },
    {
      "name": "Sensor Readings",
      "description": "Sensor Readings"
    },
    {
      "name": "User Preferences",
      "description": "User Preferences"
    },
    {
      "name": "Weather",
      "description": "Weather"
    }
  ],
  "paths": {
    "/api/v1/appliances": {
      "get": {
        "operationId": "getAppliances",
        "summary": "List all registered appliances.",
        "description": "List all registered appliances.",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "array"
                },
                "examples": {
                  "default": {
                    "value": [
                      {
                        "appliance_type": "ev_charger",
                        "config": {
                          "battery_capacity_kwh": 75,
                          "efficiency": 0.9,
                          "entity_id": "switch.tesla_charger",
                          "max_charge_rate_kw": 7.2,
                          "soc_entity_id": "sensor.tesla_battery_level"
                        },
                        "created_at": "2025-11-15T10:30:00+00:00",
                        "id": "a1b2c3d4-...",
                        "is_active": true,
                        "name": "Tesla Model 3",
                        "optimization_enabled": true,
                        "user_id": "550e8400-..."
                      }
                    ]
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "createAppliance",
        "summary": "Register a new appliance.",
        "description": "Register a new appliance.",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplianceCreate"
              },
              "examples": {
                "default": {
                  "value": {
                    "appliance_type": "ev_charger",
                    "config": {
                      "battery_capacity_kwh": 75,
                      "efficiency": 0.9,
                      "entity_id": "switch.tesla_charger",
                      "max_charge_rate_kw": 7.2,
                      "soc_entity_id": "sensor.tesla_battery_level"
                    },
                    "name": "Tesla Model 3"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliance_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses); Free accounts may register one HVAC appliance only; a second appliance or a non-HVAC type requires Premium. This check runs before the `config` check.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Upgrade required"
                    },
                    "summary": "Free accounts may register one HVAC appliance only; a second appliance or a non-HVAC type requires Premium. This check runs before the `config` check."
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appliances/{appliance_id}": {
      "delete": {
        "operationId": "deleteAppliance",
        "summary": "Permanently delete an appliance the account owns, along with its readings, schedules, and constraints.",
        "description": "Permanently delete an appliance the account owns, along with its readings, schedules, and constraints.",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "responses": {
          "204": {
            "description": "Successful Response"
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateAppliance",
        "summary": "Update an appliance's name, config, or pause flag.",
        "description": "Update an appliance's name, config, or pause flag. Send only what changes.",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/ApplianceUpdate"
              },
              "examples": {
                "default": {
                  "value": {
                    "config": {
                      "battery_capacity_kwh": 75,
                      "efficiency": 0.9,
                      "entity_id": "switch.tesla_charger",
                      "max_charge_rate_kw": 11.5,
                      "soc_entity_id": "sensor.tesla_battery_level"
                    },
                    "name": "Tesla Model 3 (Garage)"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appliances/{appliance_id}/constraints": {
      "get": {
        "operationId": "getApplianceConstraints",
        "summary": "Read the stored constraints for a non-HVAC appliance so the client can re-display what was last saved.",
        "description": "Read the stored constraints for a non-HVAC appliance so the client can re-display what was last saved.",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "example1": {
                    "value": {}
                  },
                  "example2": {
                    "value": {
                      "constraints": {
                        "deadline_time": "07:00",
                        "min_charge_pct": 30,
                        "target_charge_pct": 80
                      },
                      "status": "ok"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "post": {
        "operationId": "setApplianceConstraints",
        "summary": "Set the constraints a non-HVAC appliance is scheduled within.",
        "description": "Set the constraints a non-HVAC appliance is scheduled within. (HVAC comfort settings go through [Per-Appliance Preferences](#per-appliance-preferences) instead.)",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "additionalProperties": true,
                "title": "Constraints"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- a field in the table above for this appliance's type failed validation",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "<field>: <message>"
                    },
                    "summary": "a field in the table above for this appliance's type failed validation"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appliances/{appliance_id}/preferences": {
      "get": {
        "operationId": "getAppliancePreferences",
        "summary": "GET /api/v1/appliances/{appliance_id}/preferences",
        "description": "GET /api/v1/appliances/{appliance_id}/preferences",
        "tags": [
          "Per-Appliance Preferences"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppliancePreferencesResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "base_temperature": 72.0,
                      "hourly_high_temps_f": null,
                      "hourly_low_temps_f": null,
                      "optimization_enabled": true,
                      "optimization_mode": "cool",
                      "optimize_hvac_fan": false,
                      "optimize_hvac_mode": false,
                      "savings_level": 1,
                      "time_away": "08:00",
                      "time_home": "17:00"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found -- (missing, not owned, or not an HVAC unit)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    },
                    "summary": "(missing, not owned, or not an HVAC unit)"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateAppliancePreferences",
        "summary": "Update per-HVAC preferences.",
        "description": "Update per-HVAC preferences. All fields optional; fields you do not send keep their saved values. The account-level preferences are left untouched.",
        "tags": [
          "Per-Appliance Preferences"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/AppliancePreferencesUpdate"
              },
              "examples": {
                "default": {
                  "value": {
                    "base_temperature": 70.0,
                    "optimization_enabled": false,
                    "optimization_mode": "auto",
                    "savings_level": 3
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/AppliancePreferencesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- hourly-band validation messages (see `PUT /api/v1/preferences`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appliances/{appliance_id}/preferences/default-bands": {
      "get": {
        "operationId": "getApplianceDefaultPreferenceBands",
        "summary": "Same preview as `GET /api/v1/preferences/default-bands`, scoped to one HVAC appliance.",
        "description": "Same preview as `GET /api/v1/preferences/default-bands`, scoped to one HVAC appliance. An omitted query param falls back to this appliance's own preferences once they have been saved, otherwise to the account-level preferences.",
        "tags": [
          "Per-Appliance Preferences"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          },
          {
            "name": "base_temperature",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Base Temperature"
            }
          },
          {
            "name": "savings_level",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Savings Level"
            }
          },
          {
            "name": "time_away",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Time Away"
            }
          },
          {
            "name": "time_home",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Time Home"
            }
          },
          {
            "name": "optimization_mode",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Optimization Mode"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DefaultBandsResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- same validation messages as the account-level endpoint",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appliances/{appliance_id}/readings": {
      "post": {
        "operationId": "pushApplianceReadings",
        "summary": "Push state readings for a non-HVAC appliance in batches (EV charger, home battery, robot, water heater, solar).",
        "description": "Push state readings for a non-HVAC appliance in batches (EV charger, home battery, robot, water heater, solar). HVAC and dehumidifier readings go through `POST /api/v1/readings` instead.",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/app__routes__appliances__ReadingsBatch"
              },
              "examples": {
                "default": {
                  "value": {
                    "readings": [
                      {
                        "metadata": {
                          "current": 30,
                          "voltage": 240
                        },
                        "power_watts": 7200.0,
                        "state": "CHARGING",
                        "timestamp": "2025-11-18T14:30:00+00:00",
                        "value": 45.2
                      }
                    ]
                  }
                }
              }
            }
          }
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "accepted": 1
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- (also `... for home_battery`, `... for robot`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "example1": {
                    "value": {
                      "detail": "Value must be 0-100 (percent) for ev_charger"
                    },
                    "summary": "(also `... for home_battery`, `... for robot`)"
                  },
                  "example2": {
                    "value": {
                      "detail": "Value must be 60-180 (degrees F) for water_heater"
                    }
                  },
                  "example3": {
                    "value": {
                      "detail": "Value must be 0-100000 (watts) for solar"
                    }
                  },
                  "example4": {
                    "value": {
                      "detail": "power_watts must be 0-100000 (watts) for solar"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Rate limit exceeded: max <cap> readings per user per day (scaled to <N> active appliance(s))"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/appliances/{appliance_id}/schedule": {
      "get": {
        "operationId": "getApplianceSchedule",
        "summary": "Get today's schedule for one appliance.",
        "description": "Get today's schedule for one appliance. Same per-type `schedule` blob as one entry of `GET /api/v1/schedules`, plus the date it applies to. When no schedule exists yet, `source` is `\"defaults\"`, `savings_pct` is `0.0`, and `schedule` is `{}`.",
        "tags": [
          "Appliance Management"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Appliance Id"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliance_id": "a1b2c3d4-...",
                      "appliance_type": "ev_charger",
                      "date": "2025-11-18",
                      "entities": {
                        "entity_id": "switch.tesla_charger",
                        "soc_entity_id": "sensor.tesla_battery_level"
                      },
                      "name": "Tesla Model 3",
                      "optimization_enabled": true,
                      "savings_pct": 32.1,
                      "schedule": {
                        "intervals": [
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          false,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          true,
                          false
                        ],
                        "unit": "percent",
                        "value_trajectory": [
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          35.0,
                          57.5,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0,
                          80.0
                        ]
                      },
                      "source": "optimization"
                    },
                    "summary": "EV charger example"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    }
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/calibration/skip": {
      "post": {
        "operationId": "skipCalibration",
        "summary": "Opt an HVAC unit out of its first warm-up day.",
        "description": "Opt an HVAC unit out of its first warm-up day. It stays skipped until a later `/calibration/start`. A later, second warm-up day is not affected.",
        "tags": [
          "Calibration (Automatic Warm-Up)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/_ApplianceIdBody"
              },
              "examples": {
                "default": {
                  "value": {
                    "appliance_id": "a1b2c3d4-..."
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliance_id": "a1b2c3d4-...",
                      "skipped": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- (id resolution, or a non-HVAC appliance id)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "409": {
            "description": "Conflict -- (the unit already has a `completed` or `skipped` run)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Warm-up is already complete for this appliance"
                    },
                    "summary": "(the unit already has a `completed` or `skipped` run)"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config) -- .",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/calibration/start": {
      "post": {
        "operationId": "startCalibration",
        "summary": "Request a fresh warm-up run for an HVAC unit (e.g.",
        "description": "Request a fresh warm-up run for an HVAC unit (e.g. after equipment service, or to override a skipped status). The run begins at the next nightly cycle (\u2264 24 h).",
        "tags": [
          "Calibration (Automatic Warm-Up)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/_ApplianceIdBody"
              },
              "examples": {
                "default": {
                  "value": {
                    "appliance_id": "a1b2c3d4-..."
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliance_id": "a1b2c3d4-...",
                      "run": {
                        "id": 43,
                        "kind": "fan_excitation",
                        "phases": [
                          "..."
                        ],
                        "schedule_date": "2026-06-05",
                        "started_at": "2026-06-05T18:42:11+00:00",
                        "status": "in_progress"
                      },
                      "run_id": 43,
                      "started": true
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- (id resolution, same bodies as `GET /calibration/status`)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config) -- (database unavailable, including when the run could not be recorded).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/calibration/status": {
      "get": {
        "operationId": "getCalibrationStatus",
        "summary": "Get warm-up state for one HVAC unit.",
        "description": "Get warm-up state for one HVAC unit.",
        "tags": [
          "Calibration (Automatic Warm-Up)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Appliance Id"
            },
            "description": "UUID of the HVAC appliance. Optional when the user has exactly one HVAC; required otherwise (400 if missing)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliance_id": "a1b2c3d4-...",
                      "can_skip": false,
                      "history": [
                        "..."
                      ],
                      "is_complete": true,
                      "is_in_progress": false,
                      "latest_run": {
                        "aborted_reason": null,
                        "completed_at": "2026-06-06T01:30:00+00:00",
                        "derived_rates": {
                          "...": "opaque diagnostic object \u2014 see note"
                        },
                        "id": 42,
                        "kind": "fan_excitation",
                        "partial": false,
                        "phases": [
                          "..."
                        ],
                        "schedule_date": "2026-06-05",
                        "started_at": "2026-06-05T01:30:00+00:00",
                        "status": "completed"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- (the id belongs to a non-HVAC appliance)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Device tokens cannot access user endpoints"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Resource not found -- (also when the appliance belongs to another account)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Appliance not found"
                    },
                    "summary": "(also when the appliance belongs to another account)"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/integration/health": {
      "get": {
        "operationId": "getIntegrationHealth",
        "summary": "Standalone link-health check.",
        "description": "Standalone link-health check. Returns the same `integration_health` block that `GET /api/v1/schedules` inlines. Poll this on a faster cadence (e.g. every 30 s) without pulling the full schedule payload.",
        "tags": [
          "Schedules (Primary Integration Point)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliances": [
                        {
                          "appliance_id": "1111...",
                          "lookback_hours": 6,
                          "message": "Integration is healthy.",
                          "name": "Living Room AC",
                          "status": "healthy"
                        },
                        {
                          "appliance_id": "2222...",
                          "lookback_hours": 6,
                          "message": "...",
                          "name": "Bedroom AC",
                          "status": "frozen_sensor"
                        }
                      ],
                      "last_reading_age_seconds": 312,
                      "last_reading_at": "2026-05-29T02:00:00+00:00",
                      "lookback_hours": 6,
                      "message": "Readings are arriving on time but indoor temperature has been stuck at 70.0\u00b0F for 6 hours. Your thermostat is likely disconnected, or your client's sensor mapping has changed.",
                      "sample_count": 71,
                      "status": "frozen_sensor"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Device tokens cannot access user endpoints"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me/metrics/daily": {
      "get": {
        "operationId": "getDailyMetrics",
        "summary": "The same savings / peaks / flexibility / comfort metrics as `/summary`, but **per day and un-aggregated**, so a dashboard can chart a trend rather than a single number.",
        "description": "The same savings / peaks / flexibility / comfort metrics as `/summary`, but **per day and un-aggregated**, so a dashboard can chart a trend rather than a single number.",
        "tags": [
          "Customer Metrics"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "start",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Start"
            },
            "description": "ISO date (YYYY-MM-DD). Default: end - 30 days."
          },
          {
            "name": "end",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "End"
            },
            "description": "ISO date (YYYY-MM-DD). Default: today (user-local)."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "days": [
                        {
                          "comfort": {
                            "in_band_home_pct": 96.0
                          },
                          "date": "2026-08-01",
                          "flexibility": {
                            "degree_hours": 336.0,
                            "percent_hours": null
                          },
                          "peaks": {
                            "off_peak_kwh_share_pct": 50.0,
                            "peak_hours_idle": 2.0,
                            "top_peak_hours_idle": 1.5
                          },
                          "savings": {
                            "degenerate": false,
                            "modeled_usd": 1.0,
                            "realized_usd": 0.5,
                            "savings_pct": 10.0
                          }
                        }
                      ],
                      "end": "2026-08-03",
                      "start": "2026-07-04"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- `start` more than 90 days before `end`, or reversed range; `start`/`end` is not a valid ISO date",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token -- No `Authorization` header / malformed token / expired token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- The token is not a user access token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me/metrics/day/{date}": {
      "get": {
        "operationId": "getMetricsForDay",
        "summary": "One local calendar day's **plan versus actual** for the caller's HVAC: the plan the system intended (the 48-slot setpoints, the comfort band, the price curve), the measured indoor temperature, and where plan and reality diverged \u2014 split into two **separate** lists so an override (the customer's own decision) is never conflated with a conformance defect (a plan the service failed to deliver).",
        "description": "One local calendar day's **plan versus actual** for the caller's HVAC: the plan the system intended (the 48-slot setpoints, the comfort band, the price curve), the measured indoor temperature, and where plan and reality diverged \u2014 split into two **separate** lists so an override (the customer's own decision) is never conflated with a conformance defect (a plan the service failed to deliver).",
        "tags": [
          "Customer Metrics"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "date",
            "in": "path",
            "required": true,
            "schema": {
              "type": "string",
              "title": "Date"
            },
            "description": "Local calendar day (ISO YYYY-MM-DD)."
          },
          {
            "name": "appliance_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Appliance Id"
            },
            "description": "Target HVAC. Defaults to the caller's first active HVAC."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliance_id": "9191a36c-9b61-444a-ac3a-666b7912514e",
                      "comfort_band": {
                        "high": [
                          74.0,
                          "\u2026 48 \u2026"
                        ],
                        "low": [
                          70.0,
                          "\u2026 48 \u2026"
                        ]
                      },
                      "conformance_defects": [
                        {
                          "end": "2026-06-08T12:15:00+00:00",
                          "readings": 2,
                          "start": "2026-06-08T12:10:00+00:00",
                          "start_hour": 12
                        }
                      ],
                      "date": "2026-06-08",
                      "indoor_temps": [
                        71.0,
                        null,
                        "\u2026 48 \u2026"
                      ],
                      "overrides": [
                        {
                          "end": "2026-06-08T10:20:00+00:00",
                          "readings": 3,
                          "start": "2026-06-08T10:10:00+00:00",
                          "start_hour": 10
                        }
                      ],
                      "price_curve": [
                        12.4,
                        12.1,
                        "\u2026 48 \u2026"
                      ],
                      "setpoints": [
                        72.0,
                        72.0,
                        "\u2026 48 \u2026"
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- Malformed `date` path value",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token -- No `Authorization` header / malformed token / expired token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- The token is not a user access token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me/metrics/summary": {
      "get": {
        "operationId": "getMetricsSummary",
        "summary": "Trailing-window aggregate of the caller's savings, peaks avoided, flexibility, comfort, plan adherence and connected machines \u2014 one call for a headline row.",
        "description": "Trailing-window aggregate of the caller's savings, peaks avoided, flexibility, comfort, plan adherence and connected machines \u2014 one call for a headline row.",
        "tags": [
          "Customer Metrics"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 30,
              "title": "Window"
            },
            "description": "Trailing days to aggregate. Max 90; wider requests 400."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "adherence": {
                        "conformance_pct": 95.0,
                        "override_by_hour": [
                          0,
                          0,
                          0,
                          0,
                          0,
                          0,
                          0,
                          3,
                          0,
                          0,
                          0,
                          0,
                          0,
                          0,
                          0,
                          0,
                          0,
                          0,
                          3,
                          0,
                          0,
                          0,
                          0,
                          0
                        ],
                        "override_events": 3
                      },
                      "comfort": {
                        "in_band_home_pct": 96.0
                      },
                      "days_counted": 2,
                      "flexibility": {
                        "degree_hours": 336.0,
                        "percent_hours": null
                      },
                      "latest_date": "2026-08-02",
                      "machines": {
                        "active": 2,
                        "by_type": {
                          "ev_charger": 1,
                          "hvac": 1
                        }
                      },
                      "peaks": {
                        "off_peak_kwh_share_pct": 55.0,
                        "peak_hours_idle": 6.0,
                        "top_peak_hours_idle": 3.0
                      },
                      "savings": {
                        "degenerate": false,
                        "modeled_days": 2,
                        "modeled_usd": 4.0,
                        "realized_days": 1,
                        "realized_usd": 2.0,
                        "savings_pct": 20.0
                      },
                      "window": 30
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- `window` greater than 90",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token -- No `Authorization` header / malformed token / expired token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- The token is not a user access token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/me/rankings": {
      "get": {
        "operationId": "getRankings",
        "summary": "How the caller stacks up against comparable homes \u2014 **without revealing anything about those homes**.",
        "description": "How the caller stacks up against comparable homes \u2014 **without revealing anything about those homes**. For each of four higher-is-better metrics, the route compares the caller's own value over the window with comparable homes, and returns **only the caller's rank, percentile and own value** \u2014 never the cohort's size, and never another home's value.",
        "tags": [
          "Customer Metrics"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "window",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "default": 30,
              "title": "Window"
            },
            "description": "Trailing days the ranking window spans. Max 90; wider 400."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "latest_date": "2026-08-03",
                      "rankings": [
                        {
                          "cohort_kind": "zip5",
                          "cohort_label": "your ZIP code",
                          "metric": "savings_pct",
                          "percentile": 100.0,
                          "rank": 1,
                          "your_value": 22.5
                        },
                        {
                          "cohort_kind": "rate_peers",
                          "cohort_label": "your rate plan",
                          "metric": "off_peak_kwh_share_pct",
                          "percentile": 62.5,
                          "rank": 3,
                          "your_value": 55.0
                        },
                        {
                          "cohort_kind": "fleet",
                          "cohort_label": "all Hungry Machines homes",
                          "metric": "flexibility_degree_hours",
                          "percentile": null,
                          "rank": null,
                          "your_value": null
                        },
                        {
                          "cohort_kind": "zip5",
                          "cohort_label": "your ZIP code",
                          "metric": "active_appliances",
                          "percentile": 100.0,
                          "rank": 1,
                          "your_value": 2.0
                        }
                      ],
                      "window": 30
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- `window` greater than 90",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token -- No `Authorization` header / malformed token / expired token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- The token is not a user access token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/preferences": {
      "get": {
        "operationId": "getPreferences",
        "summary": "GET /api/v1/preferences",
        "description": "GET /api/v1/preferences",
        "tags": [
          "User Preferences"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreferencesResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "base_load_reserve_kw": 0.0,
                      "base_temperature": 72.0,
                      "demand_charge_usd_per_kw": null,
                      "demand_window_end": null,
                      "demand_window_start": null,
                      "hourly_high_temps_f": null,
                      "hourly_low_temps_f": null,
                      "max_concurrent_appliances": null,
                      "newsletter_opt_in": true,
                      "optimization_enabled": true,
                      "optimization_mode": "cool",
                      "optimize_hvac_fan": false,
                      "optimize_hvac_mode": false,
                      "power_cap_kw": null,
                      "savings_level": 1,
                      "spike_guard_enabled": true,
                      "time_away": "08:00",
                      "time_home": "17:00"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updatePreferences",
        "summary": "Update preferences.",
        "description": "Update preferences. All fields optional \u2014 send only what changes. Any change other than `newsletter_opt_in` alone triggers a debounced recompute of today's schedule.",
        "tags": [
          "User Preferences"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/PreferencesUpdate"
              },
              "examples": {
                "default": {
                  "value": {
                    "base_temperature": 73.0,
                    "hourly_high_temps_f": [
                      76,
                      76,
                      76,
                      76,
                      76,
                      76,
                      74,
                      74,
                      78,
                      78,
                      78,
                      78,
                      78,
                      78,
                      78,
                      78,
                      78,
                      76,
                      74,
                      74,
                      74,
                      74,
                      74,
                      74
                    ],
                    "hourly_low_temps_f": [
                      68,
                      68,
                      68,
                      68,
                      68,
                      68,
                      70,
                      70,
                      66,
                      66,
                      66,
                      66,
                      66,
                      66,
                      66,
                      66,
                      66,
                      70,
                      70,
                      70,
                      70,
                      70,
                      70,
                      70
                    ],
                    "optimization_mode": "auto",
                    "savings_level": 2
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PreferencesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "example1": {
                    "value": {
                      "detail": "hourly_high_temps_f and hourly_low_temps_f must be set together or both cleared"
                    }
                  },
                  "example2": {
                    "value": {
                      "detail": "hourly_high_temps_f and hourly_low_temps_f must each have exactly 24 values"
                    }
                  },
                  "example3": {
                    "value": {
                      "detail": "hourly bands at hour <i> must be between 50 and 90 F"
                    }
                  },
                  "example4": {
                    "value": {
                      "detail": "hourly bands at hour <i> must be finite numbers between 50 and 90 F"
                    }
                  },
                  "example5": {
                    "value": {
                      "detail": "hourly low must be less than high at hour <i>"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/preferences/default-bands": {
      "get": {
        "operationId": "getDefaultPreferenceBands",
        "summary": "Preview the default hourly comfort band \u2014 the band that applies when no hourly arrays are saved \u2014 without writing anything.",
        "description": "Preview the default hourly comfort band \u2014 the band that applies when no hourly arrays are saved \u2014 without writing anything. Use it to build a \"Reset to defaults\" control that shows what will actually apply.",
        "tags": [
          "User Preferences"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "base_temperature",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "number"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Base Temperature"
            }
          },
          {
            "name": "savings_level",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "integer"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Savings Level"
            }
          },
          {
            "name": "time_away",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Time Away"
            }
          },
          {
            "name": "time_home",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Time Home"
            }
          },
          {
            "name": "optimization_mode",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Optimization Mode"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/DefaultBandsResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "hourly_high_temps_f": [
                        73.0,
                        73.0,
                        "...(24 values)"
                      ],
                      "hourly_low_temps_f": [
                        70.0,
                        70.0,
                        "...(24 values)"
                      ],
                      "peak_hours": [
                        13,
                        21
                      ],
                      "precool_hours": [
                        9,
                        13
                      ]
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "example1": {
                    "value": {
                      "detail": "base_temperature must be between 60 and 85F"
                    }
                  },
                  "example2": {
                    "value": {
                      "detail": "savings_level must be 1, 2, or 3"
                    }
                  },
                  "example3": {
                    "value": {
                      "detail": "Time must be in HH:MM format"
                    }
                  },
                  "example4": {
                    "value": {
                      "detail": "optimization_mode must be cool, heat, or auto"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rates": {
      "get": {
        "operationId": "getRates",
        "summary": "Return the 48-interval time-of-use electricity rate curve for the account, plus the metadata to render and edit the pricing-source selection.",
        "description": "Return the 48-interval time-of-use electricity rate curve for the account, plus the metadata to render and edit the pricing-source selection. Use this to color the schedule timeline by peak / off-peak pricing.",
        "tags": [
          "Rates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RatesResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "adder_grid_ruleset_id": null,
                      "available_delivery_tariffs": [
                        {
                          "external_id": "comed-dtod-sf",
                          "id": 12,
                          "period_rates": {
                            "evening": 3.747,
                            "midday_peak": 10.712,
                            "morning": 4.009,
                            "overnight": 2.984
                          },
                          "plan_name": "Delivery Time-of-Day \u2014 Single-Family",
                          "region": "Northern Illinois",
                          "utility": "ComEd"
                        },
                        "... more entries ..."
                      ],
                      "available_dynamic_zones": [
                        {
                          "label": "ComEd \u2014 Hourly Pricing (Northern Illinois)",
                          "slug": "comed"
                        },
                        {
                          "label": "Ameren Illinois (Power Smart Pricing)",
                          "slug": "ameren"
                        },
                        "... more entries (UK, EU/Nordic, Spain, Australia and California plans) ..."
                      ],
                      "available_pricing_zones": [
                        {
                          "id": 1,
                          "label": "SDG&E TOU-DR1 \u2014 San Diego",
                          "notes": "peak 4-9pm",
                          "plan": "TOU-DR1",
                          "region": "San Diego, CA",
                          "slug": "sdge-tou-dr1",
                          "utility": "SDG&E"
                        },
                        "... more entries ..."
                      ],
                      "currency": "USD",
                      "delivery_tod_cents": null,
                      "dynamic_zone": null,
                      "export_rates_cents_per_kwh": null,
                      "hourly_rates_cents_per_kwh": null,
                      "intervals": [
                        0,
                        1,
                        2,
                        3,
                        4,
                        5,
                        6,
                        7,
                        8,
                        9,
                        10,
                        11,
                        12,
                        13,
                        14,
                        15,
                        16,
                        17,
                        18,
                        19,
                        20,
                        21,
                        22,
                        23,
                        24,
                        25,
                        26,
                        27,
                        28,
                        29,
                        30,
                        31,
                        32,
                        33,
                        34,
                        35,
                        36,
                        37,
                        38,
                        39,
                        40,
                        41,
                        42,
                        43,
                        44,
                        45,
                        46,
                        47
                      ],
                      "pricing_adder_cents_per_kwh": null,
                      "pricing_location": 1,
                      "pricing_source": "zone",
                      "rates_cents_per_kwh": [
                        24.7,
                        24.7,
                        "... 48 values ..."
                      ],
                      "season": "summer",
                      "source": "zone",
                      "tariff_ruleset_id": null,
                      "unit": "cents/kWh"
                    },
                    "summary": "zone"
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses).",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "put": {
        "operationId": "updateRates",
        "summary": "Set or clear any subset of the account's pricing configuration.",
        "description": "Set or clear any subset of the account's pricing configuration. Only fields explicitly sent are updated. A request with none of the fields below changes nothing and returns the current state.",
        "tags": [
          "Rates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RatesUpdate"
              },
              "examples": {
                "default": {
                  "value": {
                    "hourly_rates_cents_per_kwh": [
                      22.0,
                      22.0,
                      22.0,
                      22.0,
                      22.0,
                      22.0,
                      28.0,
                      28.0,
                      28.0,
                      28.0,
                      28.0,
                      28.0,
                      28.0,
                      28.0,
                      28.0,
                      28.0,
                      45.0,
                      45.0,
                      45.0,
                      45.0,
                      45.0,
                      28.0,
                      28.0,
                      22.0
                    ],
                    "pricing_source": "custom"
                  },
                  "summary": "custom hourly rates \u2014 send the source and the array together"
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RatesResponse"
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- when `custom` is selected with no override sent (or explicitly nulled) and none already stored",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "example1": {
                    "value": {
                      "detail": "hourly_rates_cents_per_kwh must have exactly 24 values"
                    }
                  },
                  "example2": {
                    "value": {
                      "detail": "rate at hour <i> must be between 0 and 200 cents/kWh"
                    }
                  },
                  "example3": {
                    "value": {
                      "detail": "pricing_source must be one of ['zone', 'custom', 'dynamic', 'tariff']"
                    }
                  },
                  "example4": {
                    "value": {
                      "detail": "pricing_source custom requires hourly_rates_cents_per_kwh"
                    },
                    "summary": "when `custom` is selected with no override sent (or explicitly nulled) and none already stored"
                  },
                  "example5": {
                    "value": {
                      "detail": "pricing_source='dynamic' requires dynamic_zone (one of: [...])"
                    }
                  },
                  "example6": {
                    "value": {
                      "detail": "dynamic_zone must be one of: [...]"
                    }
                  },
                  "example7": {
                    "value": {
                      "detail": "pricing_adder_cents_per_kwh must be a number between 0 and 50 cents/kWh"
                    }
                  },
                  "example8": {
                    "value": {
                      "detail": "pricing_location must be one of the catalog ids: [...]"
                    }
                  },
                  "example9": {
                    "value": {
                      "detail": "tariff_ruleset_id must be a positive integer id"
                    }
                  },
                  "example10": {
                    "value": {
                      "detail": "tariff_ruleset_id <id> does not exist (browse GET /api/v1/rates/tariffs)"
                    }
                  },
                  "example11": {
                    "value": {
                      "detail": "tariff_ruleset_id <id> is not currently in force"
                    }
                  },
                  "example12": {
                    "value": {
                      "detail": "pricing_source='tariff' requires tariff_ruleset_id (browse GET /api/v1/rates/tariffs)"
                    }
                  },
                  "example13": {
                    "value": {
                      "detail": "adder_grid_ruleset_id <id> does not reference an available delivery tariff (see available_delivery_tariffs on GET /api/v1/rates)"
                    }
                  },
                  "example14": {
                    "value": {
                      "detail": "delivery_tod_cents must be an object with exactly the keys [...]"
                    }
                  },
                  "example15": {
                    "value": {
                      "detail": "delivery_tod_cents must have exactly the keys [...] (missing [...]; unexpected [...])"
                    }
                  },
                  "example16": {
                    "value": {
                      "detail": "delivery_tod_cents.<key> must be a number between 0 and 50 cents/kWh"
                    }
                  },
                  "example17": {
                    "value": {
                      "detail": "export_rates_cents_per_kwh must have exactly 48 values"
                    }
                  },
                  "example18": {
                    "value": {
                      "detail": "export rate at slot <i> must be between 0 and 200 cents/kWh"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/rates/tariffs": {
      "get": {
        "operationId": "getRateTariffs",
        "summary": "Browse the tariff library to find a `tariff_ruleset_id` to select on `PUT /api/v1/rates`.",
        "description": "Browse the tariff library to find a `tariff_ruleset_id` to select on `PUT /api/v1/rates`. Returns plan metadata only \u2014 the rate values appear in `GET /api/v1/rates` once a tariff is linked.",
        "tags": [
          "Rates"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "country",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Country"
            },
            "description": "Exact country code, case-insensitive (US, CA)."
          },
          {
            "name": "region",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Region"
            },
            "description": "Case-insensitive substring match on region."
          },
          {
            "name": "utility",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Utility"
            },
            "description": "Exact utility name, case-insensitive (SCE, SMUD)."
          },
          {
            "name": "q",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Q"
            },
            "description": "Free-text search \u2014 case-insensitive substring over utility, plan_name, and region."
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "maximum": 500,
              "minimum": 1,
              "default": 50,
              "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": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "country": null,
                      "limit": 50,
                      "offset": 0,
                      "q": null,
                      "region": null,
                      "tariffs": [
                        {
                          "country": "CA",
                          "currency": "CAD",
                          "effective_from": "2026-05-01",
                          "id": 3,
                          "plan_name": "TOU",
                          "region": "Ontario",
                          "utility": "OEB",
                          "verified": true
                        },
                        {
                          "country": "US",
                          "currency": "USD",
                          "disclaimer": "Community-sourced rate \u2014 verify against your utility bill",
                          "effective_from": "2026-01-01",
                          "id": 7,
                          "plan_name": "TOU-D-4-9PM",
                          "region": "Southern California",
                          "utility": "SCE",
                          "verified": false
                        }
                      ],
                      "total": 2,
                      "utility": null
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/readings": {
      "post": {
        "operationId": "pushReadings",
        "summary": "Push HVAC sensor readings in batches.",
        "description": "Push HVAC sensor readings in batches. A thermostat integration should call this every 5 minutes with the latest reading, or batch up to 100 readings.",
        "tags": [
          "Sensor Readings"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/app__routes__readings__ReadingsBatch"
              },
              "examples": {
                "default": {
                  "value": {
                    "client": {
                      "ha_version": "2026.8.1",
                      "kind": "hacs",
                      "node_bundle": null,
                      "version": "3.7.0"
                    },
                    "readings": [
                      {
                        "appliance_id": "11111111-1111-1111-1111-111111111111",
                        "commanded_fan_mode": "low",
                        "commanded_hvac_mode": "COOL",
                        "commanded_setpoint": 71.0,
                        "fan_mode": "auto",
                        "hvac_action": "cooling",
                        "hvac_state": "COOL",
                        "indoor_humidity": 45.0,
                        "indoor_source": "sensor",
                        "indoor_temp": 72.5,
                        "outdoor_temp": 85.0,
                        "override_active": false,
                        "power_watts": 298.0,
                        "room_target": 73.0,
                        "target_temp": 72.0,
                        "timestamp": "2025-11-18T14:30:00+00:00"
                      }
                    ]
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ReadingsResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "accepted": 5
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "appliance_id <uuid> is not a hvac or dehumidifier appliance owned by this user"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token -- (the token is not valid). An expired user token gets `\"Invalid credentials\"` on this route, so refresh it and retry.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded -- where `<cap>` is 600 \u00d7 `<N>`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Rate limit exceeded: max <cap> readings per user per day (scaled to <N> active reading-producing appliance(s))"
                    },
                    "summary": "where `<cap>` is 600 \u00d7 `<N>`."
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/schedule": {
      "get": {
        "operationId": "getSchedule",
        "summary": "Get today's HVAC schedule for one unit, in a small fixed shape.",
        "description": "Get today's HVAC schedule for one unit, in a small fixed shape. It suits a client that drives a single thermostat by setpoint. The per-slot mode and fan schedules and `room_target_temps` are returned only by [`GET /api/v1/schedules`](#get-apiv1schedules).",
        "tags": [
          "Schedules (Primary Integration Point)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Appliance Id"
            },
            "description": "UUID of the HVAC appliance whose schedule to return. Optional when the user has exactly one HVAC (the legacy single-HVAC client path); required as a 400 when the user has 2+ HVACs."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ScheduleResponse"
                },
                "examples": {
                  "example1": {
                    "value": {
                      "date": "2025-11-18",
                      "estimated_savings_pct": 18.5,
                      "generated_at": "2025-11-18T04:15:00+00:00",
                      "mode": "cool",
                      "model_confidence": null,
                      "schedule": {
                        "high_temps": [
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0,
                          74.0
                        ],
                        "intervals": [
                          0,
                          1,
                          2,
                          3,
                          4,
                          5,
                          6,
                          7,
                          8,
                          9,
                          10,
                          11,
                          12,
                          13,
                          14,
                          15,
                          16,
                          17,
                          18,
                          19,
                          20,
                          21,
                          22,
                          23,
                          24,
                          25,
                          26,
                          27,
                          28,
                          29,
                          30,
                          31,
                          32,
                          33,
                          34,
                          35,
                          36,
                          37,
                          38,
                          39,
                          40,
                          41,
                          42,
                          43,
                          44,
                          45,
                          46,
                          47
                        ],
                        "low_temps": [
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0,
                          70.0
                        ],
                        "setpoint_temps": [
                          72.0,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5,
                          71.5
                        ],
                        "temp_trajectory": [
                          72.1,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6,
                          71.6
                        ]
                      },
                      "source": "optimization",
                      "stale": false
                    },
                    "summary": "with a stored plan for today"
                  },
                  "example2": {
                    "value": {
                      "date": "2025-11-18",
                      "estimated_savings_pct": 0.0,
                      "generated_at": "2025-11-18T12:00:00+00:00",
                      "mode": "cool",
                      "model_confidence": null,
                      "schedule": {
                        "high_temps": [
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5,
                          73.5
                        ],
                        "intervals": [
                          0,
                          1,
                          2,
                          3,
                          4,
                          5,
                          6,
                          7,
                          8,
                          9,
                          10,
                          11,
                          12,
                          13,
                          14,
                          15,
                          16,
                          17,
                          18,
                          19,
                          20,
                          21,
                          22,
                          23,
                          24,
                          25,
                          26,
                          27,
                          28,
                          29,
                          30,
                          31,
                          32,
                          33,
                          34,
                          35,
                          36,
                          37,
                          38,
                          39,
                          40,
                          41,
                          42,
                          43,
                          44,
                          45,
                          46,
                          47
                        ],
                        "low_temps": [
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5,
                          70.5
                        ],
                        "setpoint_temps": null,
                        "temp_trajectory": null
                      },
                      "source": "defaults",
                      "stale": false
                    },
                    "summary": "no stored plan yet (`source"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "User has multiple HVAC appliances; pass appliance_id to disambiguate."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Device tokens cannot access user endpoints"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/schedule/recompute": {
      "post": {
        "operationId": "recomputeSchedule",
        "summary": "Recompute schedules for the account now, wait for the result, and return it.",
        "description": "Recompute schedules for the account now, wait for the result, and return it. Use this right after the user saves a constraint or comfort change so the UI updates without polling. No request body.",
        "tags": [
          "Schedules (Primary Integration Point)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliances": [
                        "<same entries as GET /api/v1/schedules>"
                      ],
                      "date": "2026-07-02",
                      "results": [
                        {
                          "appliance_id": "uuid-1",
                          "appliance_type": "hvac",
                          "name": "Office AC",
                          "status": "ok"
                        },
                        {
                          "appliance_id": "uuid-2",
                          "appliance_type": "hvac",
                          "detail": "internal error",
                          "name": "Front AC",
                          "status": "failed"
                        }
                      ]
                    },
                    "summary": "exactly three keys: `date`, `appliances` and `results`."
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Device tokens cannot access user endpoints"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/schedules": {
      "get": {
        "operationId": "getSchedules",
        "summary": "Get today's schedules for **all** registered appliances.",
        "description": "Get today's schedules for **all** registered appliances. The unified endpoint for an integration that manages multiple devices, and the only one that returns the per-slot mode and fan schedules.",
        "tags": [
          "Schedules (Primary Integration Point)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "example1": {
                    "value": {
                      "appliances": [
                        {
                          "appliance_id": "a1b2c3d4-...",
                          "appliance_type": "hvac",
                          "entities": {
                            "entity_id": "climate.living_room",
                            "indoor_temp_entity_id": "sensor.back_bedroom_temperature"
                          },
                          "integration_health": {
                            "last_reading_age_seconds": 88,
                            "last_reading_at": "2025-11-18T14:23:10+00:00",
                            "lookback_hours": 6,
                            "message": "Integration is healthy.",
                            "sample_count": 71,
                            "status": "healthy"
                          },
                          "name": "Living Room AC",
                          "optimization_enabled": true,
                          "savings_pct": 18.5,
                          "schedule": {
                            "generated_at": "2025-11-18T04:15:00+00:00",
                            "high_temps": [
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0,
                              74.0
                            ],
                            "intervals": [
                              0,
                              1,
                              2,
                              3,
                              4,
                              5,
                              6,
                              7,
                              8,
                              9,
                              10,
                              11,
                              12,
                              13,
                              14,
                              15,
                              16,
                              17,
                              18,
                              19,
                              20,
                              21,
                              22,
                              23,
                              24,
                              25,
                              26,
                              27,
                              28,
                              29,
                              30,
                              31,
                              32,
                              33,
                              34,
                              35,
                              36,
                              37,
                              38,
                              39,
                              40,
                              41,
                              42,
                              43,
                              44,
                              45,
                              46,
                              47
                            ],
                            "low_temps": [
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0,
                              70.0
                            ],
                            "mode": "cool",
                            "room_target_temps": [
                              72.0,
                              71.5,
                              "..."
                            ],
                            "setpoint_temps": [
                              72.0,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5,
                              71.5
                            ],
                            "temp_trajectory": [
                              72.1,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6,
                              71.6
                            ]
                          },
                          "source": "optimization"
                        },
                        {
                          "appliance_id": "e5f6a7b8-...",
                          "appliance_type": "ev_charger",
                          "entities": {
                            "entity_id": "switch.tesla_charger",
                            "soc_entity_id": "sensor.tesla_battery_level"
                          },
                          "name": "Tesla Model 3",
                          "optimization_enabled": true,
                          "savings_pct": 32.1,
                          "schedule": {
                            "intervals": [
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              true,
                              false,
                              false
                            ],
                            "unit": "percent",
                            "value_trajectory": [
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              30.0,
                              45.2,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              60.4,
                              80.0,
                              80.0
                            ]
                          },
                          "source": "optimization"
                        },
                        {
                          "appliance_id": "c9d0e1f2-...",
                          "appliance_type": "water_heater",
                          "entities": {
                            "entity_id": "switch.water_heater",
                            "temp_entity_id": "sensor.tank_temperature"
                          },
                          "name": "Basement Water Heater",
                          "optimization_enabled": true,
                          "savings_pct": 22.0,
                          "schedule": {
                            "intervals": [
                              true,
                              true,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              true,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false,
                              false
                            ],
                            "temp_trajectory": [
                              120.0,
                              128.5,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              135.2,
                              118.3,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7,
                              126.7
                            ],
                            "unit": "fahrenheit"
                          },
                          "source": "optimization"
                        }
                      ],
                      "date": "2025-11-18",
                      "divergence_summary": {
                        "human_readable": "All three signals agree \u2014 recent readings are clean.",
                        "sample_count": 288,
                        "verdict": "healthy"
                      },
                      "integration_health": {
                        "appliances": [
                          {
                            "appliance_id": "1111...",
                            "lookback_hours": 6,
                            "message": "Integration is healthy.",
                            "name": "Living Room AC",
                            "status": "healthy"
                          },
                          {
                            "appliance_id": "2222...",
                            "lookback_hours": 6,
                            "message": "Readings are arriving on time but indoor temperature has been stuck at 70.0\u00b0F for 6 hours. Your thermostat is likely disconnected, or your client's sensor mapping has changed.",
                            "name": "Bedroom AC",
                            "status": "frozen_sensor"
                          }
                        ],
                        "last_reading_age_seconds": 88,
                        "last_reading_at": "2025-11-18T14:23:10+00:00",
                        "lookback_hours": 6,
                        "message": "Integration is healthy.",
                        "sample_count": 71,
                        "status": "healthy"
                      },
                      "optimization_enabled": true
                    }
                  },
                  "example2": {
                    "value": {
                      "appliance_id": "a1b2c3d4-...",
                      "appliance_type": "hvac",
                      "entities": {
                        "entity_id": "climate.living_room"
                      },
                      "integration_health": {
                        "last_reading_age_seconds": null,
                        "last_reading_at": null,
                        "lookback_hours": 6,
                        "message": "No readings received from this HVAC in the last 6 hours. Check your thermostat and indoor-temp sensor bindings on this appliance.",
                        "sample_count": 0,
                        "status": "no_data"
                      },
                      "name": "Living Room AC",
                      "optimization_enabled": true,
                      "savings_pct": 0.0,
                      "schedule": {},
                      "source": "defaults"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Not authenticated"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/schedules/history": {
      "get": {
        "operationId": "getScheduleHistory",
        "summary": "Return the history of schedule rows for the account's appliances within a date range.",
        "description": "Return the history of schedule rows for the account's appliances within a date range. `GET /schedule` and `/schedules` always return the **latest** schedule per `(appliance, date)`; this endpoint returns every stored one, so a UI can show how the plan for a day changed.",
        "tags": [
          "Schedules (Primary Integration Point)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "appliance_id",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Appliance Id"
            },
            "description": "If omitted, returns history for every appliance the user owns."
          },
          {
            "name": "start",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "Start"
            },
            "description": "ISO date (YYYY-MM-DD). Default: end - 14 days."
          },
          {
            "name": "end",
            "in": "query",
            "required": false,
            "schema": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "null"
                }
              ],
              "title": "End"
            },
            "description": "ISO date (YYYY-MM-DD). Default: today."
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "appliances": [
                        {
                          "appliance_id": "0a0feccb-...",
                          "appliance_type": "hvac",
                          "history": [
                            {
                              "appliance_id": "0a0feccb-...",
                              "baseline_cost": 0.42,
                              "constraints_used": {
                                "base_temperature": 72.0,
                                "optimization_mode": "cool"
                              },
                              "created_at": "2026-05-14T21:35:04Z",
                              "date": "2026-05-14",
                              "id": 79,
                              "optimized_cost": 0.31,
                              "savings_pct": 26.1,
                              "schedule": {
                                "setpoint_temps": [
                                  "..."
                                ],
                                "temp_trajectory": [
                                  "..."
                                ]
                              }
                            }
                          ],
                          "name": "Bedroom AC"
                        }
                      ],
                      "end": "2026-05-29",
                      "start": "2026-05-15"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Device tokens cannot access user endpoints"
                    }
                  }
                }
              }
            }
          },
          "404": {
            "description": "Resource not found -- (only when `appliance_id` is set)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "appliance not found for this user"
                    },
                    "summary": "(only when `appliance_id` is set)"
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/schedules/updated-at": {
      "get": {
        "operationId": "getSchedulesUpdatedAt",
        "summary": "Lightweight freshness check: returns the latest timestamp a schedule was written for the account, for today, without downloading the schedules themselves.",
        "description": "Lightweight freshness check: returns the latest timestamp a schedule was written for the account, for today, without downloading the schedules themselves. **This is how a client notices a daytime re-plan.** Poll it every few minutes, keep the last value you saw, and fetch `GET /api/v1/schedules` again when it changes.",
        "tags": [
          "Schedules (Primary Integration Point)"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "updated_at": "2026-09-05T14:32:07.123456+00:00"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Device tokens cannot access user endpoints"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/weather": {
      "post": {
        "operationId": "pushWeather",
        "summary": "Push the user's hourly weather forecast (for example from a Home Assistant `weather.*` entity).",
        "description": "Push the user's hourly weather forecast (for example from a Home Assistant `weather.*` entity). A push from the last 24 hours is preferred over the server-side fallback forecast.",
        "tags": [
          "Weather"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/WeatherPush"
              },
              "examples": {
                "default": {
                  "value": {
                    "forecast": {
                      "forecast_date": "2025-11-18",
                      "hourly_humidity": [
                        62,
                        64,
                        "..."
                      ],
                      "hourly_temps_f": [
                        54.2,
                        53.8,
                        "...(24-72 values)"
                      ],
                      "hourly_wind_mph": [
                        3.1,
                        2.8,
                        "..."
                      ]
                    }
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "201": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/WeatherPushResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "accepted_hours": 48,
                      "pushed_at": "2025-11-18T03:30:00+00:00"
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- (any optional array)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "example1": {
                    "value": {
                      "detail": "<name> must contain between 24 and 72 hourly values"
                    }
                  },
                  "example2": {
                    "value": {
                      "detail": "<name>[<i>]=<v> is outside the allowed range [<min>, <max>]"
                    }
                  },
                  "example3": {
                    "value": {
                      "detail": "<name>[<i>] is not a finite number"
                    }
                  },
                  "example4": {
                    "value": {
                      "detail": "<name> length must match hourly_temps_f"
                    },
                    "summary": "(any optional array)"
                  },
                  "example5": {
                    "value": {
                      "detail": "forecast.forecast_date must be an ISO date (YYYY-MM-DD)"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/auth/login": {
      "post": {
        "operationId": "logIn",
        "summary": "Exchange email + password for an access + refresh token pair.",
        "description": "Exchange email + password for an access + refresh token pair.",
        "tags": [
          "Authentication"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/LoginRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "email": "user@example.com",
                    "password": "securepassword"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "access_token": "eyJhbGciOi...",
                      "expires_at": 1762450800,
                      "expires_in": 3600,
                      "refresh_token": "JKLrM3...",
                      "token_type": "bearer",
                      "user": {
                        "email": "user@example.com",
                        "id": "550e8400-e29b-41d4-a716-446655440000"
                      }
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Invalid login credentials"
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream auth service unreachable -- or the identity provider's own message when it fails",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Auth service unreachable"
                    },
                    "summary": "or the identity provider's own message when it fails"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Auth not configured"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/me": {
      "get": {
        "operationId": "getMe",
        "summary": "Get the current user's profile and subscription tier.",
        "description": "Get the current user's profile and subscription tier. Call it once right after signup or login, before any other request: the first call sets up the account's profile and applies the optional fields sent at signup.",
        "tags": [
          "Authentication"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "email": "user@example.com",
                      "home_size_sqft": 2000,
                      "location_zip": "92101",
                      "pricing_location": 1,
                      "subscription_tier": "free",
                      "timezone": "America/New_York",
                      "user_id": "550e8400-e29b-41d4-a716-446655440000",
                      "weather_entity_id": "weather.home"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- (the token is not a user access token)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Device tokens cannot access user endpoints"
                    },
                    "summary": "(the token is not a user access token)"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      },
      "patch": {
        "operationId": "updateMe",
        "summary": "Update the profile.",
        "description": "Update the profile. Send only the fields you want to change.",
        "tags": [
          "Authentication"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/UpdateProfileRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "home_size_sqft": 1800,
                    "location_zip": "94110",
                    "pricing_location": 3,
                    "timezone": "America/Los_Angeles",
                    "weather_entity_id": "weather.home"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/MeResponse"
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- as on `GET /auth/me`",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/auth/refresh": {
      "post": {
        "operationId": "refreshToken",
        "summary": "Exchange a refresh token for a new access + refresh token pair.",
        "description": "Exchange a refresh token for a new access + refresh token pair. Refresh tokens are **single-use** \u2014 a successful call rotates both tokens, so clients must persist the new `refresh_token` from the response.",
        "tags": [
          "Authentication"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RefreshRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "refresh_token": "JKLrM3..."
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {}
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- (reused, revoked, or expired). Any `4xx` here means the refresh token is no longer usable: ask the user to sign in again.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Invalid Refresh Token"
                    },
                    "summary": "(reused, revoked, or expired). Any `4xx` here means the refresh token is no longer usable: ask the user to sign in again."
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream auth service unreachable",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config) -- as above",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          }
        }
      }
    },
    "/auth/signup": {
      "post": {
        "operationId": "signUp",
        "summary": "Create a new account.",
        "description": "Create a new account. Optional profile fields are stored on the account and applied the first time the client calls `GET /auth/me`, so call `GET /auth/me` once after signup or login, before any other request.",
        "tags": [
          "Authentication"
        ],
        "security": [],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/SignupRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "email": "user@example.com",
                    "home_size_sqft": 2000,
                    "location_zip": "92101",
                    "password": "securepassword",
                    "pricing_location": 1
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "access_token": "eyJhbGciOi...",
                      "expires_at": 1762450800,
                      "expires_in": 3600,
                      "refresh_token": "JKLrM3...",
                      "token_type": "bearer",
                      "user": {
                        "email": "user@example.com",
                        "id": "550e8400-e29b-41d4-a716-446655440000"
                      }
                    },
                    "summary": "An authenticated session, unless the account requires email confirmation"
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure -- (or another signup failure message)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "User already registered"
                    },
                    "summary": "(or another signup failure message)"
                  }
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "502": {
            "description": "Upstream auth service unreachable -- or the identity provider's own message when it fails",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Auth service unreachable"
                    },
                    "summary": "or the identity provider's own message when it fails"
                  }
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Auth not configured"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/billing/create-checkout": {
      "post": {
        "operationId": "createCheckoutSession",
        "summary": "Start a hosted checkout session for a subscription upgrade.",
        "description": "Start a hosted checkout session for a subscription upgrade.",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "requestBody": {
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CreateCheckoutRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "cancel_url": "https://hungrymachines.io/dashboard?checkout=canceled",
                    "success_url": "https://hungrymachines.io/dashboard?checkout=success",
                    "tier": "premium"
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CheckoutResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "url": "https://checkout.stripe.com/c/pay_..."
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "Bad request / validation failure",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Unknown tier. Must be one of: premium"
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "422": {
            "description": "Validation Error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HTTPValidationError"
                }
              }
            }
          },
          "500": {
            "description": "Server / upstream service error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/billing/portal": {
      "get": {
        "operationId": "getBillingPortal",
        "summary": "Open the hosted customer portal for subscription management (cancel, update payment method, view invoices).",
        "description": "Open the hosted customer portal for subscription management (cancel, update payment method, view invoices).",
        "tags": [
          "Billing"
        ],
        "security": [
          {
            "bearerAuth": []
          }
        ],
        "parameters": [
          {
            "name": "return_url",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "default": "https://hungrymachines.io/dashboard",
              "title": "Return Url"
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/PortalResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "url": "https://billing.stripe.com/p/session/..."
                    }
                  }
                }
              }
            }
          },
          "401": {
            "description": "Not authenticated / invalid token",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "403": {
            "description": "Forbidden (e.g. upgrade required) -- see [Common Error Responses](#common-error-responses)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "404": {
            "description": "Resource not found -- (the account has never started a checkout)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "No billing account found"
                    },
                    "summary": "(the account has never started a checkout)"
                  }
                }
              }
            }
          },
          "500": {
            "description": "Server / upstream service error",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "503": {
            "description": "Dependency unavailable (DB / config)",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                },
                "examples": {
                  "default": {
                    "value": {
                      "detail": "Database unavailable"
                    }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/health": {
      "get": {
        "operationId": "getHealth",
        "summary": "System status.",
        "description": "System status. No auth required. The response has exactly these three keys.",
        "tags": [
          "Health Check"
        ],
        "security": [],
        "responses": {
          "200": {
            "description": "Successful Response",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                },
                "examples": {
                  "default": {
                    "value": {
                      "api_build": "1119842",
                      "status": "ok",
                      "version": "3.0.0"
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "A user access token from `/auth/login` or `/auth/signup` (refreshed via `/auth/refresh`), or a satellite device token minted by `/api/v1/devices/claim`. Send it as `Authorization: Bearer <token>` on every protected route; the two kinds of token are not interchangeable."
      }
    },
    "schemas": {
      "ApplianceCreate": {
        "properties": {
          "appliance_type": {
            "type": "string",
            "title": "Appliance Type",
            "description": "One of `\"hvac\"`, `\"ev_charger\"`, `\"home_battery\"`, `\"water_heater\"`, `\"solar\"`, `\"dehumidifier\"`, `\"robot\"`. Cannot be changed later."
          },
          "name": {
            "type": "string",
            "title": "Name",
            "description": "Display name."
          },
          "config": {
            "additionalProperties": true,
            "type": "object",
            "title": "Config",
            "default": {},
            "description": "Per-type keys, listed below. Every type has at least one required key."
          }
        },
        "type": "object",
        "required": [
          "appliance_type",
          "name"
        ],
        "title": "ApplianceCreate"
      },
      "AppliancePreferencesResponse": {
        "properties": {
          "base_temperature": {
            "type": "number",
            "title": "Base Temperature"
          },
          "savings_level": {
            "type": "integer",
            "title": "Savings Level"
          },
          "time_away": {
            "type": "string",
            "title": "Time Away"
          },
          "time_home": {
            "type": "string",
            "title": "Time Home"
          },
          "optimization_mode": {
            "type": "string",
            "title": "Optimization Mode"
          },
          "hourly_high_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly High Temps F"
          },
          "hourly_low_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Low Temps F"
          },
          "optimize_hvac_fan": {
            "type": "boolean",
            "title": "Optimize Hvac Fan",
            "default": false
          },
          "optimize_hvac_mode": {
            "type": "boolean",
            "title": "Optimize Hvac Mode",
            "default": false
          },
          "optimization_enabled": {
            "type": "boolean",
            "title": "Optimization Enabled",
            "default": true
          }
        },
        "type": "object",
        "required": [
          "base_temperature",
          "savings_level",
          "time_away",
          "time_home",
          "optimization_mode"
        ],
        "title": "AppliancePreferencesResponse"
      },
      "AppliancePreferencesUpdate": {
        "properties": {
          "base_temperature": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Base Temperature"
          },
          "savings_level": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Savings Level"
          },
          "time_away": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Time Away"
          },
          "time_home": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Time Home"
          },
          "optimization_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimization Mode"
          },
          "hourly_high_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly High Temps F"
          },
          "hourly_low_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Low Temps F"
          },
          "optimize_hvac_fan": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimize Hvac Fan"
          },
          "optimize_hvac_mode": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimize Hvac Mode"
          },
          "optimization_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimization Enabled"
          }
        },
        "type": "object",
        "title": "AppliancePreferencesUpdate"
      },
      "ApplianceReading": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp"
          },
          "state": {
            "type": "string",
            "title": "State",
            "description": "e.g. `\"CHARGING\"`, `\"IDLE\"`, `\"ON\"`, `\"OFF\"`, `\"DISCHARGING\"`"
          },
          "value": {
            "type": "number",
            "title": "Value",
            "description": "Charge percent, 0 \u2013 100, for `ev_charger`, `home_battery` and `robot`. Tank temperature, 60 \u2013 180 \u00b0F, for `water_heater`. Production in watts, 0 \u2013 100000, for `solar`."
          },
          "power_watts": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Power Watts",
            "description": "Current power draw. For `solar`, 0 \u2013 100000."
          },
          "metadata": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Metadata",
            "description": "Any additional data."
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "state",
          "value"
        ],
        "title": "ApplianceReading"
      },
      "ApplianceUpdate": {
        "properties": {
          "name": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name",
            "description": "New display name."
          },
          "config": {
            "anyOf": [
              {
                "additionalProperties": true,
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Config",
            "description": "**Replaces** the stored config. Send the complete config for the appliance's type, including every required key (see `POST /api/v1/appliances`), not only the keys that changed."
          },
          "optimization_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimization Enabled",
            "description": "Pause (`false`) or resume (`true`) a non-HVAC appliance. HVAC units are paused through [Per-Appliance Preferences](#per-appliance-preferences)."
          }
        },
        "type": "object",
        "title": "ApplianceUpdate"
      },
      "CheckoutResponse": {
        "properties": {
          "url": {
            "type": "string",
            "title": "Url"
          }
        },
        "type": "object",
        "required": [
          "url"
        ],
        "title": "CheckoutResponse"
      },
      "ClientInfo": {
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "hacs",
              "node",
              "custom"
            ],
            "title": "Kind"
          },
          "version": {
            "type": "string",
            "maxLength": 40,
            "minLength": 1,
            "title": "Version"
          },
          "node_bundle": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Node Bundle"
          },
          "ha_version": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Ha Version"
          },
          "name": {
            "anyOf": [
              {
                "type": "string",
                "maxLength": 40,
                "minLength": 1,
                "pattern": "^[A-Za-z0-9 ._-]+$"
              },
              {
                "type": "null"
              }
            ],
            "title": "Name"
          }
        },
        "type": "object",
        "required": [
          "kind",
          "version"
        ],
        "title": "ClientInfo"
      },
      "CreateCheckoutRequest": {
        "properties": {
          "tier": {
            "type": "string",
            "title": "Tier",
            "description": "Must be `\"premium\"`"
          },
          "success_url": {
            "type": "string",
            "title": "Success Url",
            "description": "Absolute URL in your own app to return to after successful payment"
          },
          "cancel_url": {
            "type": "string",
            "title": "Cancel Url",
            "description": "Absolute URL in your own app to return to if the user cancels"
          }
        },
        "type": "object",
        "required": [
          "tier",
          "success_url",
          "cancel_url"
        ],
        "title": "CreateCheckoutRequest"
      },
      "DefaultBandsResponse": {
        "properties": {
          "hourly_high_temps_f": {
            "items": {
              "type": "number"
            },
            "type": "array",
            "title": "Hourly High Temps F"
          },
          "hourly_low_temps_f": {
            "items": {
              "type": "number"
            },
            "type": "array",
            "title": "Hourly Low Temps F"
          },
          "peak_hours": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Peak Hours"
          },
          "precool_hours": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Precool Hours"
          }
        },
        "type": "object",
        "required": [
          "hourly_high_temps_f",
          "hourly_low_temps_f",
          "peak_hours",
          "precool_hours"
        ],
        "title": "DefaultBandsResponse"
      },
      "DeliveryTariffOption": {
        "properties": {
          "id": {
            "type": "integer",
            "title": "Id"
          },
          "external_id": {
            "type": "string",
            "title": "External Id"
          },
          "plan_name": {
            "type": "string",
            "title": "Plan Name"
          },
          "utility": {
            "type": "string",
            "title": "Utility"
          },
          "region": {
            "type": "string",
            "title": "Region"
          },
          "period_rates": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "number"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Period Rates"
          }
        },
        "type": "object",
        "required": [
          "id",
          "external_id",
          "plan_name",
          "utility",
          "region"
        ],
        "title": "DeliveryTariffOption"
      },
      "DynamicZoneOption": {
        "properties": {
          "slug": {
            "type": "string",
            "title": "Slug"
          },
          "label": {
            "type": "string",
            "title": "Label"
          }
        },
        "type": "object",
        "required": [
          "slug",
          "label"
        ],
        "title": "DynamicZoneOption"
      },
      "Error": {
        "type": "object",
        "properties": {
          "detail": {
            "type": "string"
          }
        },
        "required": [
          "detail"
        ]
      },
      "HTTPValidationError": {
        "properties": {
          "detail": {
            "items": {
              "$ref": "#/components/schemas/ValidationError"
            },
            "type": "array",
            "title": "Detail"
          }
        },
        "type": "object",
        "title": "HTTPValidationError"
      },
      "HvacScheduleBody": {
        "properties": {
          "intervals": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Intervals",
            "description": "Always `[0, 1, \u2026, 47]` (48 \u00d7 30-minute intervals)"
          },
          "high_temps": {
            "items": {
              "type": "number"
            },
            "type": "array",
            "title": "High Temps",
            "description": "Per-interval upper comfort bound (\u00b0F). **Display-only.** On the defaults path it is built from the account's comfort preferences."
          },
          "low_temps": {
            "items": {
              "type": "number"
            },
            "type": "array",
            "title": "Low Temps",
            "description": "Per-interval lower comfort bound (\u00b0F). **Display-only.**"
          },
          "temp_trajectory": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Temp Trajectory",
            "description": "Predicted indoor-temperature line, **display-only** (the \"optimized temperature\" chart line). `null` when `source` is `\"defaults\"`, and on a warm-up day (see [Calibration](#calibration-automatic-warm-up))."
          },
          "setpoint_temps": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Setpoint Temps",
            "description": "**The thermostat command to apply.** Apply directly via `climate.set_temperature` at each boundary. `null` when `source` is `\"defaults\"` (and on plans stored before the field existed) \u2014 fall back to `(high_temps[i] + low_temps[i]) / 2`."
          }
        },
        "type": "object",
        "required": [
          "intervals",
          "high_temps",
          "low_temps"
        ],
        "title": "HvacScheduleBody"
      },
      "LoginRequest": {
        "properties": {
          "email": {
            "type": "string",
            "title": "Email"
          },
          "password": {
            "type": "string",
            "title": "Password"
          }
        },
        "type": "object",
        "required": [
          "email",
          "password"
        ],
        "title": "LoginRequest"
      },
      "MeResponse": {
        "properties": {
          "user_id": {
            "type": "string",
            "title": "User Id",
            "description": "Account id (matches the JWT subject)"
          },
          "email": {
            "type": "string",
            "title": "Email"
          },
          "location_zip": {
            "type": "string",
            "title": "Location Zip",
            "description": "May be empty"
          },
          "home_size_sqft": {
            "type": "integer",
            "title": "Home Size Sqft",
            "description": "May be 0"
          },
          "pricing_location": {
            "type": "integer",
            "title": "Pricing Location",
            "description": "Rate-catalog id (see `available_pricing_zones`)"
          },
          "timezone": {
            "type": "string",
            "title": "Timezone",
            "description": "IANA timezone"
          },
          "subscription_tier": {
            "type": "string",
            "title": "Subscription Tier",
            "description": "`\"free\"` or `\"premium\"`. Defaults to `\"free\"`."
          },
          "weather_entity_id": {
            "type": "string",
            "title": "Weather Entity Id",
            "default": "",
            "description": "Home Assistant `weather.*` entity the user picked for forecasts. Empty when unset."
          }
        },
        "type": "object",
        "required": [
          "user_id",
          "email",
          "location_zip",
          "home_size_sqft",
          "pricing_location",
          "timezone",
          "subscription_tier"
        ],
        "title": "MeResponse"
      },
      "PortalResponse": {
        "properties": {
          "url": {
            "type": "string",
            "title": "Url"
          }
        },
        "type": "object",
        "required": [
          "url"
        ],
        "title": "PortalResponse"
      },
      "PreferencesResponse": {
        "properties": {
          "base_temperature": {
            "type": "number",
            "title": "Base Temperature",
            "description": "Desired temperature (\u00b0F)"
          },
          "savings_level": {
            "type": "integer",
            "title": "Savings Level",
            "description": "1 = tight comfort, 2 = moderate, 3 = aggressive. Stored and returned. It does not change the default comfort band (see `GET /api/v1/preferences/default-bands`); to widen or narrow comfort, set the two hourly arrays."
          },
          "time_away": {
            "type": "string",
            "title": "Time Away",
            "description": "HH:MM (24-hour) when the user leaves home. Stored and returned; it does not change the default comfort band."
          },
          "time_home": {
            "type": "string",
            "title": "Time Home",
            "description": "HH:MM (24-hour) when the user returns. Stored and returned; it does not change the default comfort band."
          },
          "optimization_mode": {
            "type": "string",
            "title": "Optimization Mode",
            "description": "`\"cool\"`, `\"heat\"`, `\"auto\"`, or `\"off\"`"
          },
          "hourly_high_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly High Temps F",
            "description": "Optional 24-element per-hour upper comfort bound. When set, the two hourly arrays are the comfort band. When `null`, the default band applies."
          },
          "hourly_low_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Low Temps F",
            "description": "Optional 24-element per-hour lower comfort bound. Must be set together with `hourly_high_temps_f`."
          },
          "optimize_hvac_fan": {
            "type": "boolean",
            "title": "Optimize Hvac Fan",
            "default": false,
            "description": "Opt-in: also emit a per-slot fan-speed schedule."
          },
          "optimize_hvac_mode": {
            "type": "boolean",
            "title": "Optimize Hvac Mode",
            "default": false,
            "description": "Opt-in: also emit a per-slot HVAC-mode schedule."
          },
          "optimization_enabled": {
            "type": "boolean",
            "title": "Optimization Enabled",
            "default": true,
            "description": "Master pause switch. When `false`, clients must stop applying schedules entirely until re-enabled. Schedules are still computed, so re-enabling takes effect at the next half-hour boundary."
          },
          "newsletter_opt_in": {
            "type": "boolean",
            "title": "Newsletter Opt In",
            "default": true,
            "description": "Newsletter membership."
          },
          "spike_guard_enabled": {
            "type": "boolean",
            "title": "Spike Guard Enabled",
            "default": true,
            "description": "Automatically avoid real-time price spikes on plans that support it. Your comfort range always applies. Turn off any time."
          },
          "max_concurrent_appliances": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Max Concurrent Appliances",
            "description": "Limit how many appliances (EV charger, home battery, water heater, etc.) may run at the same time. `null` = no limit."
          },
          "power_cap_kw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Power Cap Kw",
            "description": "A whole-home power ceiling (kW) the planner respects. `null` = no cap."
          },
          "base_load_reserve_kw": {
            "type": "number",
            "title": "Base Load Reserve Kw",
            "default": 0.0,
            "description": "Power (kW) always reserved for everyday always-on draw before the planner spends the rest of `power_cap_kw`."
          },
          "demand_charge_usd_per_kw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Demand Charge Usd Per Kw",
            "description": "Your utility's demand charge rate ($/kW), if any, so the planner avoids a new monthly peak. `null` = no demand charge."
          },
          "demand_window_start": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Demand Window Start",
            "description": "HH:MM start of the hours your demand charge applies. `null` with `demand_window_end` also `null` = all day."
          },
          "demand_window_end": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Demand Window End",
            "description": "HH:MM end of the hours your demand charge applies."
          }
        },
        "type": "object",
        "required": [
          "base_temperature",
          "savings_level",
          "time_away",
          "time_home",
          "optimization_mode"
        ],
        "title": "PreferencesResponse"
      },
      "PreferencesUpdate": {
        "properties": {
          "base_temperature": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Base Temperature",
            "description": "60.0 \u2013 85.0 \u00b0F"
          },
          "savings_level": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Savings Level",
            "description": "1, 2, or 3"
          },
          "time_away": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Time Away",
            "description": "HH:MM, 24-hour, `00:00` \u2013 `23:59`"
          },
          "time_home": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Time Home",
            "description": "HH:MM, 24-hour, `00:00` \u2013 `23:59`"
          },
          "optimization_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimization Mode",
            "description": "`\"cool\"`, `\"heat\"`, `\"auto\"`, `\"off\"`"
          },
          "hourly_high_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly High Temps F",
            "description": "Exactly 24 finite numbers in [50, 90]. Set together with `hourly_low_temps_f` (or both `null` to clear). For each hour `i`, low < high."
          },
          "hourly_low_temps_f": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Low Temps F",
            "description": "Exactly 24 finite numbers in [50, 90]. Set together with `hourly_high_temps_f`."
          },
          "optimize_hvac_fan": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimize Hvac Fan",
            "description": "true/false"
          },
          "optimize_hvac_mode": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimize Hvac Mode",
            "description": "true/false"
          },
          "optimization_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Optimization Enabled",
            "description": "true/false"
          },
          "newsletter_opt_in": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Newsletter Opt In",
            "description": "true/false"
          },
          "spike_guard_enabled": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Spike Guard Enabled",
            "description": "true/false"
          },
          "max_concurrent_appliances": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Max Concurrent Appliances",
            "description": ">= 1, or `null` to clear"
          },
          "power_cap_kw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Power Cap Kw",
            "description": "> 0, or `null` to clear"
          },
          "base_load_reserve_kw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Base Load Reserve Kw",
            "description": ">= 0"
          },
          "demand_charge_usd_per_kw": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Demand Charge Usd Per Kw",
            "description": ">= 0, or `null` to clear"
          },
          "demand_window_start": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Demand Window Start",
            "description": "HH:MM, 24-hour, `00:00` \u2013 `23:59`, or `null`"
          },
          "demand_window_end": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Demand Window End",
            "description": "HH:MM, 24-hour, `00:00` \u2013 `23:59`, or `null`"
          }
        },
        "type": "object",
        "title": "PreferencesUpdate"
      },
      "PricingZoneOption": {
        "properties": {
          "id": {
            "type": "integer",
            "title": "Id"
          },
          "slug": {
            "type": "string",
            "title": "Slug"
          },
          "utility": {
            "type": "string",
            "title": "Utility"
          },
          "plan": {
            "type": "string",
            "title": "Plan"
          },
          "region": {
            "type": "string",
            "title": "Region"
          },
          "label": {
            "type": "string",
            "title": "Label"
          },
          "notes": {
            "type": "string",
            "title": "Notes"
          }
        },
        "type": "object",
        "required": [
          "id",
          "slug",
          "utility",
          "plan",
          "region",
          "label",
          "notes"
        ],
        "title": "PricingZoneOption"
      },
      "RatesResponse": {
        "properties": {
          "pricing_location": {
            "type": "integer",
            "title": "Pricing Location",
            "description": "Catalog id from `available_pricing_zones`; defaults to 1 when unset."
          },
          "intervals": {
            "items": {
              "type": "integer"
            },
            "type": "array",
            "title": "Intervals",
            "description": "Indices 0-47 (30-minute slots of the local day)."
          },
          "rates_cents_per_kwh": {
            "items": {
              "type": "number"
            },
            "type": "array",
            "title": "Rates Cents Per Kwh",
            "description": "Exactly 48 values for the source reported in `source` (cents/kWh, or the plan currency's minor units for a tariff or a non-US dynamic zone). Display only."
          },
          "source": {
            "type": "string",
            "title": "Source",
            "description": "Which pricing source this response's curve came from: `\"zone\"`, `\"custom\"`, `\"dynamic\"`, or `\"tariff\"`. Differs from `pricing_source` when dynamic or tariff pricing was unavailable and the zone curve was returned instead."
          },
          "season": {
            "type": "string",
            "title": "Season",
            "description": "`\"summer\"` or `\"winter\"`, computed from the account's local date. Informational for non-seasonal plans."
          },
          "hourly_rates_cents_per_kwh": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Rates Cents Per Kwh",
            "description": "The account's raw 24-element override, whenever one is stored \u2014 regardless of the active `source`. `null` when none is stored."
          },
          "pricing_source": {
            "type": "string",
            "title": "Pricing Source",
            "description": "The account's stored preference: `\"zone\"`, `\"custom\"`, `\"dynamic\"`, or `\"tariff\"`. The UI toggle should reflect this."
          },
          "dynamic_zone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dynamic Zone",
            "description": "The account's chosen dynamic-pricing slug. `null` when none selected."
          },
          "pricing_adder_cents_per_kwh": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pricing Adder Cents Per Kwh",
            "description": "Per-account flat adder applied to dynamic pricing. `null` = the server default for the zone."
          },
          "tariff_ruleset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tariff Ruleset Id",
            "description": "The account's linked tariff-library id (browse via `GET /api/v1/rates/tariffs`). `null` when no tariff linked."
          },
          "rate_rin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rate Rin"
          },
          "rin_status": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rin Status"
          },
          "available_dynamic_zones": {
            "items": {
              "$ref": "#/components/schemas/DynamicZoneOption"
            },
            "type": "array",
            "title": "Available Dynamic Zones",
            "description": "Catalog for the dynamic source. Use `slug` when sending `dynamic_zone`; render `label` \u2014 it names the plan or market (e.g. `\"SCE TOU-D-4-9PM (California)\"`, `\"Netherlands day-ahead\"`)."
          },
          "available_pricing_zones": {
            "items": {
              "$ref": "#/components/schemas/PricingZoneOption"
            },
            "type": "array",
            "title": "Available Pricing Zones",
            "description": "Catalog of static tariff plans. Use `id` when sending `pricing_location`; render `label`."
          },
          "adder_grid_ruleset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Adder Grid Ruleset Id",
            "description": "The account's selected delivery/distribution plan (browse via `available_delivery_tariffs`). Only meaningful alongside `pricing_source=\"dynamic\"`. `null` = no delivery plan selected. When `delivery_tod_cents` is set, those prices are used and this field records which plan they started from."
          },
          "available_delivery_tariffs": {
            "items": {
              "$ref": "#/components/schemas/DeliveryTariffOption"
            },
            "type": "array",
            "title": "Available Delivery Tariffs",
            "default": [],
            "description": "Delivery/distribution plans available for `adder_grid_ruleset_id`. `period_rates` is that plan's published `{morning, midday_peak, evening, overnight}` rates \u2014 use it to prefill `delivery_tod_cents` when the account selects this plan; `null` if it can't be derived. Empty when none apply to your utility."
          },
          "delivery_tod_cents": {
            "anyOf": [
              {
                "additionalProperties": {
                  "type": "number"
                },
                "type": "object"
              },
              {
                "type": "null"
              }
            ],
            "title": "Delivery Tod Cents",
            "description": "The account's own four period prices \u2014 `{morning, midday_peak, evening, overnight}`, cents/kWh. `null` when unset. When set, these prices are used in place of the selected plan's published rates."
          },
          "unit": {
            "type": "string",
            "title": "Unit",
            "default": "cents/kWh",
            "description": "Always `\"cents/kWh\"`. For a tariff or a non-US dynamic zone, read it as that plan's currency minor units per kWh \u2014 see `currency` below for which one."
          },
          "currency": {
            "type": "string",
            "title": "Currency",
            "default": "USD",
            "description": "ISO 4217 code of the curve actually served: `\"USD\"` for `zone`/`custom` sources and a USD dynamic zone, the plan's own code for a tariff, the zone's own code for a non-US dynamic zone (e.g. `\"GBP\"`, `\"EUR\"`, `\"AUD\"`)."
          },
          "export_rates_cents_per_kwh": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Export Rates Cents Per Kwh",
            "description": "What the utility pays for exported solar \u2014 48 half-hour slots (slot 0 = local midnight), same units as `rates_cents_per_kwh`. `null` = no export credit configured. Settable via `PUT`."
          }
        },
        "type": "object",
        "required": [
          "pricing_location",
          "intervals",
          "rates_cents_per_kwh",
          "source",
          "season",
          "pricing_source",
          "available_dynamic_zones",
          "available_pricing_zones"
        ],
        "title": "RatesResponse"
      },
      "RatesUpdate": {
        "properties": {
          "hourly_rates_cents_per_kwh": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Rates Cents Per Kwh",
            "description": "Exactly 24 numbers (00:00 \u2192 23:00), each in `[0, 200]`. Send it with `pricing_source: \"custom\"`. `null` clears the stored array."
          },
          "pricing_source": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pricing Source",
            "description": "`\"zone\"`, `\"custom\"`, `\"dynamic\"`, or `\"tariff\"` (case-insensitive). `null` clears the explicit selection. Required (here or already stored) when `\"custom\"`: send `hourly_rates_cents_per_kwh` too unless one is already stored."
          },
          "dynamic_zone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Dynamic Zone",
            "description": "Slug from `available_dynamic_zones` (case-insensitive). `null` or a blank string clears it. Required (here or already stored) when `pricing_source=\"dynamic\"`."
          },
          "pricing_adder_cents_per_kwh": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pricing Adder Cents Per Kwh",
            "description": "Flat per-kWh adder in `[0, 50]`. `null` clears the per-account override."
          },
          "pricing_location": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pricing Location",
            "description": "Catalog id from `available_pricing_zones`. Has no cleared state: `null` is rejected."
          },
          "tariff_ruleset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Tariff Ruleset Id",
            "description": "Id from `GET /api/v1/rates/tariffs`, 1 or greater. Must reference a tariff that exists and is currently in force. `null` clears the link. Required (here or already stored) when `pricing_source=\"tariff\"`."
          },
          "rate_rin": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Rate Rin"
          },
          "adder_grid_ruleset_id": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Adder Grid Ruleset Id",
            "description": "Id from `available_delivery_tariffs`. Must reference an available delivery/distribution plan. `null` clears the selection."
          },
          "delivery_tod_cents": {
            "title": "Delivery Tod Cents",
            "description": "Exactly the four keys `morning`/`midday_peak`/`evening`/`overnight`, each a number in `[0, 50]` cents/kWh. `null` clears it. Settable in the same request as `adder_grid_ruleset_id`."
          },
          "export_rates_cents_per_kwh": {
            "title": "Export Rates Cents Per Kwh",
            "description": "Exactly 48 numbers (slot 0 = local midnight), each in `[0, 200]`. `null` clears it (no export credit)."
          }
        },
        "type": "object",
        "title": "RatesUpdate"
      },
      "ReadingsResponse": {
        "properties": {
          "accepted": {
            "type": "integer",
            "title": "Accepted"
          }
        },
        "type": "object",
        "required": [
          "accepted"
        ],
        "title": "ReadingsResponse"
      },
      "RefreshRequest": {
        "properties": {
          "refresh_token": {
            "type": "string",
            "title": "Refresh Token"
          }
        },
        "type": "object",
        "required": [
          "refresh_token"
        ],
        "title": "RefreshRequest"
      },
      "ScheduleResponse": {
        "properties": {
          "date": {
            "type": "string",
            "title": "Date",
            "description": "YYYY-MM-DD. The date of the plan returned; today's date on the defaults path."
          },
          "schedule": {
            "$ref": "#/components/schemas/HvacScheduleBody"
          },
          "mode": {
            "type": "string",
            "title": "Mode",
            "description": "`\"cool\"` or `\"heat\"` on a stored plan. On the defaults path it echoes the account's `optimization_mode` preference, so it can also be `\"auto\"` or `\"off\"`."
          },
          "estimated_savings_pct": {
            "type": "number",
            "title": "Estimated Savings Pct",
            "description": "**Display-only** estimated % savings vs a thermostat held at the middle of the comfort band. `0.0` on the defaults path."
          },
          "model_confidence": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Model Confidence",
            "description": "**Display-only**, reserved. Currently always `null`; do not build on it."
          },
          "generated_at": {
            "type": "string",
            "title": "Generated At",
            "description": "UTC timestamp of when the plan was produced (on the defaults path, the time of the request)"
          },
          "stale": {
            "type": "boolean",
            "title": "Stale",
            "default": false,
            "description": "`false` when the plan returned is for today, and always `false` on the defaults path. `true` when there is no plan for today and the most recent stored plan is returned instead; `date` tells you which day it was made for."
          },
          "source": {
            "type": "string",
            "title": "Source",
            "default": "optimization",
            "description": "`\"optimization\"` (a stored plan) or `\"defaults\"` (no stored plan yet)"
          }
        },
        "type": "object",
        "required": [
          "date",
          "schedule",
          "mode",
          "estimated_savings_pct",
          "generated_at"
        ],
        "title": "ScheduleResponse"
      },
      "SensorReading": {
        "properties": {
          "timestamp": {
            "type": "string",
            "format": "date-time",
            "title": "Timestamp"
          },
          "indoor_temp": {
            "type": "number",
            "title": "Indoor Temp"
          },
          "hvac_state": {
            "type": "string",
            "title": "Hvac State"
          },
          "indoor_humidity": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Indoor Humidity"
          },
          "outdoor_temp": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Outdoor Temp"
          },
          "target_temp": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Target Temp"
          },
          "fan_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Fan Mode"
          },
          "power_watts": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Power Watts"
          },
          "appliance_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Appliance Id"
          },
          "commanded_hvac_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Commanded Hvac Mode"
          },
          "commanded_fan_mode": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Commanded Fan Mode"
          },
          "commanded_setpoint": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Commanded Setpoint"
          },
          "hvac_action": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hvac Action"
          },
          "indoor_source": {
            "anyOf": [
              {
                "type": "string",
                "enum": [
                  "sensor",
                  "entity"
                ]
              },
              {
                "type": "null"
              }
            ],
            "title": "Indoor Source"
          },
          "override_active": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Override Active"
          },
          "room_target": {
            "anyOf": [
              {
                "type": "number"
              },
              {
                "type": "null"
              }
            ],
            "title": "Room Target"
          }
        },
        "type": "object",
        "required": [
          "timestamp",
          "indoor_temp",
          "hvac_state"
        ],
        "title": "SensorReading"
      },
      "SignupRequest": {
        "properties": {
          "email": {
            "type": "string",
            "title": "Email",
            "description": "Must be unique"
          },
          "password": {
            "type": "string",
            "title": "Password",
            "description": "Subject to the account password policy"
          },
          "location_zip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Location Zip",
            "description": "US zip code, used for weather forecasts"
          },
          "home_size_sqft": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Size Sqft",
            "description": "Used to estimate appliance power draw"
          },
          "pricing_location": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pricing Location",
            "description": "Rate-catalog id (see `available_pricing_zones` from `GET /api/v1/rates`; default 1)"
          },
          "timezone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Timezone",
            "description": "IANA timezone name, for example `America/Los_Angeles`. `422` if it isn't a real zone."
          },
          "newsletter_opt_in": {
            "anyOf": [
              {
                "type": "boolean"
              },
              {
                "type": "null"
              }
            ],
            "title": "Newsletter Opt In",
            "description": "Newsletter checkbox state. Omitted means opted in."
          }
        },
        "type": "object",
        "required": [
          "email",
          "password"
        ],
        "title": "SignupRequest"
      },
      "UpdateProfileRequest": {
        "properties": {
          "location_zip": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Location Zip",
            "description": "US zip code. Send `\"\"` to clear. Not checked as a real zip."
          },
          "home_size_sqft": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Home Size Sqft"
          },
          "pricing_location": {
            "anyOf": [
              {
                "type": "integer"
              },
              {
                "type": "null"
              }
            ],
            "title": "Pricing Location",
            "description": "A rate-catalog id from `available_pricing_zones` (`GET /api/v1/rates`). `422` if it isn't one."
          },
          "timezone": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Timezone",
            "description": "IANA timezone name, for example `America/Los_Angeles`. Schedules are keyed to it. `422` if it isn't a real zone."
          },
          "weather_entity_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Weather Entity Id",
            "description": "Home Assistant `weather.*` entity id. Send `\"\"` to clear."
          }
        },
        "type": "object",
        "title": "UpdateProfileRequest"
      },
      "ValidationError": {
        "properties": {
          "loc": {
            "items": {
              "anyOf": [
                {
                  "type": "string"
                },
                {
                  "type": "integer"
                }
              ]
            },
            "type": "array",
            "title": "Location"
          },
          "msg": {
            "type": "string",
            "title": "Message"
          },
          "type": {
            "type": "string",
            "title": "Error Type"
          },
          "input": {
            "title": "Input"
          },
          "ctx": {
            "type": "object",
            "title": "Context"
          }
        },
        "type": "object",
        "required": [
          "loc",
          "msg",
          "type"
        ],
        "title": "ValidationError"
      },
      "WeatherForecast": {
        "properties": {
          "hourly_temps_f": {
            "items": {
              "type": "number"
            },
            "type": "array",
            "title": "Hourly Temps F",
            "description": "24\u201372 hourly values, each in `[-50, 150]` \u00b0F. Element 0 is local midnight (hour 0) of `forecast_date` in the account's timezone; the array walks forward one hour per element."
          },
          "hourly_humidity": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Humidity",
            "description": "Same length as `hourly_temps_f`. Each in `[0, 100]` percent."
          },
          "hourly_wind_mph": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Wind Mph",
            "description": "Same length as `hourly_temps_f`. Each in `[0, 200]` mph."
          },
          "forecast_date": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Forecast Date",
            "description": "`YYYY-MM-DD`: the local calendar date that element 0 covers. Defaults to today in the account's timezone. Validated as an ISO date; a malformed value is a `400`."
          },
          "hourly_cloud_coverage_pct": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Cloud Coverage Pct",
            "description": "Same length as `hourly_temps_f`. Each in `[0, 100]` percent."
          },
          "hourly_precipitation_mm": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Precipitation Mm",
            "description": "Same length as `hourly_temps_f`. Each in `[0, 300]` mm."
          },
          "hourly_solar_irradiance_w": {
            "anyOf": [
              {
                "items": {
                  "type": "number"
                },
                "type": "array"
              },
              {
                "type": "null"
              }
            ],
            "title": "Hourly Solar Irradiance W",
            "description": "Same length as `hourly_temps_f`. Each in `[0, 1500]` W/m\u00b2."
          }
        },
        "type": "object",
        "required": [
          "hourly_temps_f"
        ],
        "title": "WeatherForecast"
      },
      "WeatherPush": {
        "properties": {
          "forecast": {
            "$ref": "#/components/schemas/WeatherForecast"
          }
        },
        "type": "object",
        "required": [
          "forecast"
        ],
        "title": "WeatherPush"
      },
      "WeatherPushResponse": {
        "properties": {
          "accepted_hours": {
            "type": "integer",
            "title": "Accepted Hours"
          },
          "pushed_at": {
            "type": "string",
            "title": "Pushed At"
          }
        },
        "type": "object",
        "required": [
          "accepted_hours",
          "pushed_at"
        ],
        "title": "WeatherPushResponse"
      },
      "_ApplianceIdBody": {
        "properties": {
          "appliance_id": {
            "anyOf": [
              {
                "type": "string"
              },
              {
                "type": "null"
              }
            ],
            "title": "Appliance Id"
          }
        },
        "type": "object",
        "title": "_ApplianceIdBody"
      },
      "app__routes__appliances__ReadingsBatch": {
        "properties": {
          "readings": {
            "items": {
              "$ref": "#/components/schemas/ApplianceReading"
            },
            "type": "array",
            "title": "Readings",
            "description": "1 to 100 readings per request."
          }
        },
        "type": "object",
        "required": [
          "readings"
        ],
        "title": "ReadingsBatch"
      },
      "app__routes__readings__ReadingsBatch": {
        "properties": {
          "readings": {
            "items": {
              "$ref": "#/components/schemas/SensorReading"
            },
            "type": "array",
            "title": "Readings",
            "description": "1\u2013100 reading objects (below)"
          },
          "client": {
            "anyOf": [
              {
                "$ref": "#/components/schemas/ClientInfo"
              },
              {
                "type": "null"
              }
            ],
            "description": "Identifies the client software. A third-party client should send `kind: \"custom\"`, optionally with `name`. See **Client identity** below."
          }
        },
        "type": "object",
        "required": [
          "readings"
        ],
        "title": "ReadingsBatch"
      }
    }
  }
}
