{"openapi":"3.0.3","info":{"title":"Hometry API Platform","description":"REST API for the Hometry real estate IoT platform. Three access tiers:\n\n**Basic** (100 req/min, 10K/month): sensor data, building data, incidents, JSON reports.\n\n**Premium** (500 req/min, 100K/month): everything in Basic, plus AI predictions, virtual sensors, PDF reports, safety certificates, and energy recommendations.\n\n**Enterprise** (2000 req/min, unlimited): everything in Premium, plus Algorithm-as-a-Service (POST /analyze) and webhook subscription management.\n\nAuthentication: pass your API key in the `x-api-key` header (keys start with `hom_`), or use a Bearer token from a session.","version":"1.0.0","contact":{"name":"Hometry Support","email":"support@hometry.fr"}},"servers":[{"url":"https://hometry.fr","description":"Production"},{"url":"http://localhost:3000","description":"Development"}],"security":[{"ApiKeyHeader":[]},{"BearerAuth":[]}],"tags":[{"name":"Health","description":"Platform status"},{"name":"Sensors","description":"IoT sensor data (Basic+)"},{"name":"Buildings","description":"Building inventory (Basic+)"},{"name":"Incidents","description":"Incident management (Basic+)"},{"name":"Reports","description":"Data reports (Basic+)"},{"name":"Predictions","description":"AI predictive alerts (Premium+)"},{"name":"Virtual Sensors","description":"Computed / virtual sensors (Premium+)"},{"name":"Energy","description":"Energy recommendations (Premium+)"},{"name":"Certificates","description":"Safety certificates (Premium+)"},{"name":"Analyze","description":"Algorithm-as-a-Service (Enterprise)"},{"name":"Webhooks","description":"Webhook subscriptions (Enterprise)"},{"name":"API Keys","description":"API key management"},{"name":"Legacy","description":"Deprecated v0 endpoints — kept for backwards compatibility"}],"paths":{"/api/v1/health":{"get":{"summary":"Health check","description":"Returns platform status. No authentication required.","tags":["Health"],"security":[],"responses":{"200":{"description":"Platform is healthy","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"ok"},"version":{"type":"string","example":"1.0.0"},"timestamp":{"type":"string","format":"date-time"}}}}}}}}},"/api/v1/sensors":{"get":{"summary":"List sensors","description":"Return IoT sensors for the organisation, with optional filtering.","tags":["Sensors"],"parameters":[{"name":"buildingId","in":"query","schema":{"type":"string"},"description":"Filter by building"},{"name":"type","in":"query","schema":{"type":"string","enum":["temperature","humidity","co2","leak","motion","energy"]},"description":"Sensor type"},{"name":"status","in":"query","schema":{"type":"string","enum":["active","inactive","offline"]},"description":"Sensor status"},{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":1000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Sensor list","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"sensors":{"type":"array","items":{"$ref":"#/components/schemas/SensorInfo"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/sensors/{id}/readings":{"get":{"summary":"Get sensor readings","description":"Historical readings for a single sensor.","tags":["Sensors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Sensor ID"},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":1000,"maximum":10000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Sensor readings","content":{"application/json":{"schema":{"type":"object","properties":{"sensor":{"$ref":"#/components/schemas/SensorInfo"},"pagination":{"$ref":"#/components/schemas/Pagination"},"readings":{"type":"array","items":{"$ref":"#/components/schemas/SensorReading"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/buildings":{"get":{"summary":"List buildings","description":"Return all buildings for the organisation.","tags":["Buildings"],"parameters":[{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":500}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Building list","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"buildings":{"type":"array","items":{"$ref":"#/components/schemas/Building"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/buildings/{id}":{"get":{"summary":"Get building","description":"Return a single building with sensor counts and recent incident summary.","tags":["Buildings"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Building ID"}],"responses":{"200":{"description":"Building detail","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Building"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/incidents":{"get":{"summary":"List incidents","description":"Return incidents with filtering and pagination.","tags":["Incidents"],"parameters":[{"name":"status","in":"query","schema":{"type":"string","enum":["open","in_progress","resolved","closed"]}},{"name":"priority","in":"query","schema":{"type":"string","enum":["low","medium","high","critical"]}},{"name":"type","in":"query","schema":{"type":"string"},"description":"Incident type (e.g. leak, temperature)"},{"name":"buildingId","in":"query","schema":{"type":"string"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":1000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Incident list","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"incidents":{"type":"array","items":{"$ref":"#/components/schemas/Incident"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/reports/temperature":{"get":{"summary":"Temperature report","description":"Aggregated temperature statistics for a building over a date range.","tags":["Reports"],"parameters":[{"name":"buildingId","in":"query","required":true,"schema":{"type":"string"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"}}],"responses":{"200":{"description":"Temperature report (JSON or CSV)","content":{"application/json":{"schema":{"type":"object"}},"text/csv":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/reports/energy":{"get":{"summary":"Energy report","description":"Aggregated energy consumption statistics for a building.","tags":["Reports"],"parameters":[{"name":"buildingId","in":"query","required":true,"schema":{"type":"string"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv","pdf"],"default":"json"}}],"responses":{"200":{"description":"Energy report","content":{"application/json":{"schema":{"type":"object"}},"text/csv":{"schema":{"type":"string"}},"application/pdf":{"schema":{"type":"string","format":"binary"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/reports/incidents":{"get":{"summary":"Incidents report","description":"Summary report of incidents, optionally filtered by building and date range.","tags":["Reports"],"parameters":[{"name":"buildingId","in":"query","schema":{"type":"string"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"status","in":"query","schema":{"type":"string","enum":["open","in_progress","resolved","closed"]}}],"responses":{"200":{"description":"Incidents report","content":{"application/json":{"schema":{"type":"object"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/predictions":{"get":{"summary":"List predictive alerts","description":"Return AI-generated predictive maintenance alerts. **Requires Premium tier.**","tags":["Predictions"],"parameters":[{"name":"buildingId","in":"query","schema":{"type":"string"}},{"name":"severity","in":"query","schema":{"type":"string","enum":["low","medium","high","critical"]}},{"name":"type","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":500}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Predictive alerts","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"predictions":{"type":"array","items":{"$ref":"#/components/schemas/PredictiveAlert"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/predictions/generate":{"post":{"summary":"Generate predictions","description":"Generate prediction context for the organisation. Returns sensor trends and building data. Full AI prediction generation requires configured AI provider in organisation settings. **Requires Premium tier.**","tags":["Predictions"],"responses":{"200":{"description":"Prediction context generated","content":{"application/json":{"schema":{"type":"object","properties":{"status":{"type":"string","example":"context_generated"},"context":{"type":"object","properties":{"buildings":{"type":"array","items":{"$ref":"#/components/schemas/Building"}},"sensorTrends":{"type":"array","items":{"type":"object"}},"recentIncidents":{"type":"array","items":{"type":"object"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/virtual-sensors":{"get":{"summary":"List virtual sensors","description":"Return computed/virtual sensors (e.g. averaged room temperature). **Requires Premium tier.**","tags":["Virtual Sensors"],"parameters":[{"name":"buildingId","in":"query","schema":{"type":"string"}},{"name":"sensorType","in":"query","schema":{"type":"string"}},{"name":"isActive","in":"query","schema":{"type":"boolean"}},{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":500}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Virtual sensor list","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"virtualSensors":{"type":"array","items":{"$ref":"#/components/schemas/VirtualSensor"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/virtual-sensors/{id}/readings":{"get":{"summary":"Get virtual sensor readings","description":"Historical computed readings for a virtual sensor. **Requires Premium tier.**","tags":["Virtual Sensors"],"parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":1000,"maximum":10000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Virtual sensor readings","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"readings":{"type":"array","items":{"$ref":"#/components/schemas/VirtualSensorReading"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"404":{"$ref":"#/components/responses/NotFound"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/energy/recommendations":{"get":{"summary":"Energy recommendations","description":"AI-generated energy saving recommendations for a building. **Requires Premium tier.**","tags":["Energy"],"parameters":[{"name":"buildingId","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Recommendations","content":{"application/json":{"schema":{"type":"object","properties":{"buildingId":{"type":"string"},"recommendations":{"type":"array","items":{"type":"object","properties":{"title":{"type":"string"},"description":{"type":"string"},"estimatedSaving":{"type":"string"}}}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/certificates":{"get":{"summary":"List certificates","description":"Return safety certificates for the organisation. **Requires Premium tier.**","tags":["Certificates"],"parameters":[{"name":"buildingId","in":"query","schema":{"type":"string"}},{"name":"status","in":"query","schema":{"type":"string","enum":["pending","valid","expired","revoked"]}},{"name":"limit","in":"query","schema":{"type":"integer","default":50,"maximum":200}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Certificate list","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"certificates":{"type":"array","items":{"$ref":"#/components/schemas/SafetyCertificate"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"429":{"$ref":"#/components/responses/RateLimited"}}},"post":{"summary":"Create certificate","description":"Request generation of a new safety certificate for a building. **Requires Premium tier.**","tags":["Certificates"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["buildingId","type"],"properties":{"buildingId":{"type":"string"},"type":{"type":"string","description":"Certificate type (e.g. energy_performance, fire_safety)"}}}}}},"responses":{"201":{"description":"Certificate created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/SafetyCertificate"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"429":{"$ref":"#/components/responses/RateLimited"}}}},"/api/v1/certificates/verify/{hash}":{"get":{"summary":"Verify certificate","description":"Public endpoint to verify the authenticity of a certificate by its hash. No authentication required.","tags":["Certificates"],"security":[],"parameters":[{"name":"hash","in":"path","required":true,"schema":{"type":"string"},"description":"Certificate hash"}],"responses":{"200":{"description":"Certificate verification result","content":{"application/json":{"schema":{"type":"object","properties":{"valid":{"type":"boolean"},"certificate":{"$ref":"#/components/schemas/SafetyCertificate"}}}}}},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/v1/analyze":{"post":{"summary":"Algorithm-as-a-Service","description":"Run a named algorithm against arbitrary data. **Requires Enterprise tier.**","tags":["Analyze"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyzeRequest"}}}},"responses":{"200":{"description":"Algorithm result","content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalyzeResponse"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"429":{"$ref":"#/components/responses/RateLimited"},"500":{"$ref":"#/components/responses/InternalError"}}}},"/api/v1/webhooks":{"get":{"summary":"List webhook subscriptions","description":"Return all webhook subscriptions for the organisation. **Requires Enterprise tier.**","tags":["Webhooks"],"responses":{"200":{"description":"Webhook subscriptions","content":{"application/json":{"schema":{"type":"object","properties":{"webhooks":{"type":"array","items":{"$ref":"#/components/schemas/WebhookSubscription"}}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"}}},"post":{"summary":"Create webhook subscription","description":"Subscribe to one or more event types. **Requires Enterprise tier.**","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["url","events"],"properties":{"url":{"type":"string","format":"uri","description":"HTTPS endpoint to receive events"},"events":{"type":"array","items":{"type":"string"},"description":"Event types to subscribe to (e.g. [\"sensor.reading\", \"incident.created\"])"},"secret":{"type":"string","description":"Optional HMAC signing secret. If omitted, one is generated automatically."}}}}}},"responses":{"201":{"description":"Webhook created","content":{"application/json":{"schema":{"$ref":"#/components/schemas/WebhookSubscription"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"}}},"delete":{"summary":"Delete webhook subscription","description":"Remove a webhook subscription. **Requires Enterprise tier.**","tags":["Webhooks"],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["id"],"properties":{"id":{"type":"string","description":"Webhook subscription ID"}}}}}},"responses":{"200":{"description":"Deleted","content":{"application/json":{"schema":{"type":"object","properties":{"success":{"type":"boolean"}}}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"403":{"$ref":"#/components/responses/UpgradeRequired"},"404":{"$ref":"#/components/responses/NotFound"}}}},"/api/data/sensors/{sensorId}/readings":{"get":{"summary":"Get sensor readings (legacy)","description":"**Deprecated.** Use `GET /api/v1/sensors/{id}/readings` instead. Kept for backwards compatibility.","tags":["Legacy"],"parameters":[{"name":"sensorId","in":"path","required":true,"schema":{"type":"string"}},{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"limit","in":"query","schema":{"type":"integer","default":1000,"maximum":10000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Sensor readings","content":{"application/json":{"schema":{"type":"object","properties":{"sensor":{"$ref":"#/components/schemas/SensorInfo"},"pagination":{"$ref":"#/components/schemas/Pagination"},"readings":{"type":"array","items":{"$ref":"#/components/schemas/SensorReading"}}}}},"text/csv":{"schema":{"type":"string"}}}},"401":{"$ref":"#/components/responses/Unauthorized"},"404":{"$ref":"#/components/responses/NotFound"}},"deprecated":true}},"/api/data/incidents":{"get":{"summary":"List incidents (legacy)","description":"**Deprecated.** Use `GET /api/v1/incidents` instead.","tags":["Legacy"],"parameters":[{"name":"format","in":"query","schema":{"type":"string","enum":["json","csv"],"default":"json"}},{"name":"status","in":"query","schema":{"type":"string","enum":["open","in_progress","resolved","closed"]}},{"name":"startDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"endDate","in":"query","schema":{"type":"string","format":"date-time"}},{"name":"buildingId","in":"query","schema":{"type":"string"}},{"name":"limit","in":"query","schema":{"type":"integer","default":100,"maximum":1000}},{"name":"offset","in":"query","schema":{"type":"integer","default":0}}],"responses":{"200":{"description":"Incidents list","content":{"application/json":{"schema":{"type":"object","properties":{"pagination":{"$ref":"#/components/schemas/Pagination"},"incidents":{"type":"array","items":{"$ref":"#/components/schemas/Incident"}}}}}}}},"deprecated":true}},"/api/keys":{"get":{"summary":"List API keys (legacy)","description":"**Deprecated.** Kept for backwards compatibility.","tags":["Legacy","API Keys"],"responses":{"200":{"description":"API keys list","content":{"application/json":{"schema":{"type":"object","properties":{"keys":{"type":"array","items":{"$ref":"#/components/schemas/ApiKeyInfo"}}}}}}}},"deprecated":true},"post":{"summary":"Create API key (legacy)","description":"**Deprecated.** Kept for backwards compatibility.","tags":["Legacy","API Keys"],"requestBody":{"content":{"application/json":{"schema":{"type":"object","required":["name"],"properties":{"name":{"type":"string"},"expiresInDays":{"type":"integer"}}}}}},"responses":{"200":{"description":"API key created","content":{"application/json":{"schema":{"type":"object","properties":{"message":{"type":"string"},"key":{"type":"string"},"keyPrefix":{"type":"string"},"id":{"type":"string"}}}}}}},"deprecated":true}}},"components":{"securitySchemes":{"ApiKeyHeader":{"type":"apiKey","in":"header","name":"x-api-key","description":"API key with `hom_` prefix"},"BearerAuth":{"type":"http","scheme":"bearer","description":"Bearer token auth"}},"responses":{"Unauthorized":{"description":"Authentication required or API key invalid","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"UpgradeRequired":{"description":"Tier upgrade required to access this endpoint","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Upgrade required"},"requiredTier":{"type":"string","example":"premium"}}}}}},"RateLimited":{"description":"Rate limit exceeded","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Rate limit exceeded"},"retryAfterSeconds":{"type":"number","example":60}}}}}},"NotFound":{"description":"Resource not found","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"InternalError":{"description":"Internal server error","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string","example":"Internal server error"}}}}}}},"schemas":{"SensorInfo":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string","enum":["temperature","humidity","co2","leak","motion","energy"]},"serialNumber":{"type":"string"},"location":{"type":"string"},"status":{"type":"string"},"lastValue":{"type":"number"},"lastReading":{"type":"string","format":"date-time"},"buildingId":{"type":"string"}}},"SensorReading":{"type":"object","properties":{"id":{"type":"string"},"value":{"type":"number"},"unit":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"Incident":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"description":{"type":"string"},"type":{"type":"string"},"severity":{"type":"string","enum":["low","medium","high","critical"]},"status":{"type":"string","enum":["open","in_progress","resolved","closed"]},"createdAt":{"type":"string","format":"date-time"},"resolvedAt":{"type":"string","format":"date-time","nullable":true},"building":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"}}},"unit":{"type":"object","nullable":true,"properties":{"id":{"type":"string"},"unitNumber":{"type":"string"}}},"slaReactionMet":{"type":"boolean","nullable":true},"slaResolutionMet":{"type":"boolean","nullable":true}}},"Pagination":{"type":"object","properties":{"total":{"type":"integer"},"limit":{"type":"integer"},"offset":{"type":"integer"},"hasMore":{"type":"boolean"}}},"ApiKeyInfo":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"keyPrefix":{"type":"string"},"permissions":{"type":"string"},"tier":{"type":"string","enum":["basic","premium","enterprise"]},"isActive":{"type":"boolean"},"lastUsedAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"Building":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"address":{"type":"string"},"city":{"type":"string"},"postalCode":{"type":"string"},"totalUnits":{"type":"integer"},"sensorCount":{"type":"integer"},"activeIncidentCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}}},"VirtualSensor":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sensorType":{"type":"string"},"formula":{"type":"string","description":"Aggregation formula (e.g. avg, sum)"},"isActive":{"type":"boolean"},"buildingId":{"type":"string"},"lastValue":{"type":"number","nullable":true},"lastComputed":{"type":"string","format":"date-time","nullable":true}}},"VirtualSensorReading":{"type":"object","properties":{"id":{"type":"string"},"value":{"type":"number"},"unit":{"type":"string"},"timestamp":{"type":"string","format":"date-time"}}},"PredictiveAlert":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"severity":{"type":"string","enum":["low","medium","high","critical"]},"title":{"type":"string"},"description":{"type":"string"},"confidence":{"type":"number","minimum":0,"maximum":1,"description":"Model confidence score (0–1)"},"predictedAt":{"type":"string","format":"date-time"},"estimatedOccurrence":{"type":"string","format":"date-time","nullable":true},"buildingId":{"type":"string"},"sensorId":{"type":"string","nullable":true}}},"SafetyCertificate":{"type":"object","properties":{"id":{"type":"string"},"type":{"type":"string"},"status":{"type":"string","enum":["pending","valid","expired","revoked"]},"hash":{"type":"string","description":"Unique integrity hash for public verification"},"buildingId":{"type":"string"},"issuedAt":{"type":"string","format":"date-time","nullable":true},"expiresAt":{"type":"string","format":"date-time","nullable":true},"createdAt":{"type":"string","format":"date-time"}}},"WebhookSubscription":{"type":"object","properties":{"id":{"type":"string"},"url":{"type":"string","format":"uri"},"events":{"type":"array","items":{"type":"string"}},"isActive":{"type":"boolean"},"failureCount":{"type":"integer"},"createdAt":{"type":"string","format":"date-time"}}},"AnalyzeRequest":{"type":"object","required":["algorithm","data"],"properties":{"algorithm":{"type":"string","description":"Named algorithm identifier (e.g. anomaly_detection, energy_forecast)"},"data":{"type":"object","description":"Algorithm-specific input data","additionalProperties":true}}},"AnalyzeResponse":{"type":"object","properties":{"algorithm":{"type":"string"},"result":{"type":"object","description":"Algorithm-specific output","additionalProperties":true},"processingMs":{"type":"integer","description":"Server-side processing time in milliseconds"}}},"TierInfo":{"type":"object","properties":{"tier":{"type":"string","enum":["basic","premium","enterprise"]},"rateLimit":{"type":"object","properties":{"requestsPerMinute":{"type":"integer"},"requestsPerMonth":{"type":"integer","nullable":true,"description":"null means unlimited"}}},"features":{"type":"array","items":{"type":"string"}}}}}}}