{"openapi":"3.1.0","info":{"title":"Own-creator OTA service","version":"1.0.0","description":"Server contract implementation. Does not assert deployment, actual build product provenance, or hardware acceptance. Device HMAC and operator sessions are independent. Authenticated deployments use the operatorSession requirements below. An explicit local-network no-auth deployment removes operator login requirements from its served schema; device HMAC always remains required. This deployment allows operator access without login. Device HMAC authentication remains required."},"servers":[{"url":"/"}],"paths":{"/api/creator-ota/auth-config":{"get":{"tags":["Operator"],"summary":"Read the current deployment's operator login requirement","security":[],"responses":{"200":{"description":"True requires an independent operator login. False enables local-network management without a browser session.","content":{"application/json":{"schema":{"type":"object","required":["required"],"properties":{"required":{"type":"boolean"}}}}}}}}},"/v1/device/ota":{"post":{"tags":["Device"],"summary":"Bootstrap protocol or explicitly check for a newer compatible application","description":"HMAC over exact raw body and original path/query; no trailing LF in canonical input. bootstrap always firmware=null. Product decisions use signed body plus registered identity. See CREATOR_OTA_SERVER.md and public signature vectors.","security":[{"deviceHmac":[]}],"parameters":[{"name":"Serial-Number","in":"header","required":true,"schema":{"type":"string"}},{"name":"Device-Id","in":"header","required":true,"schema":{"type":"string"}},{"name":"Hardware-Version","in":"header","required":true,"schema":{"type":"string"}},{"name":"Firmware-Version","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9]+(?:\\.[0-9]+){0,3}$","maxLength":31}},{"name":"Activation-Id","in":"header","required":false,"schema":{"type":"string"}},{"name":"Client-Id","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-Device-Timestamp","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9]{1,12}$","description":"Unix seconds; exact header text signed"}},{"name":"X-Device-Nonce","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},{"name":"X-Device-Signature-Alg","in":"header","required":true,"schema":{"const":"HMAC-SHA256"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceRequest"}}}},"responses":{"200":{"description":"Top-level result; no data envelope","content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceResponse"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}}},"/v1/device/ota/firmware/{release_id}.bin":{"get":{"tags":["Device"],"summary":"Authenticated complete application download","description":"Requires a prior signed bootstrap/check version observation. The caller cannot authorize downgrade by changing unsigned Firmware-Version. Only current published compatible release is available; Range is rejected. No redirect, compression or chunked dependency.","security":[{"deviceHmac":[]}],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}},{"name":"Serial-Number","in":"header","required":true,"schema":{"type":"string"}},{"name":"Device-Id","in":"header","required":true,"schema":{"type":"string"}},{"name":"Hardware-Version","in":"header","required":true,"schema":{"type":"string"}},{"name":"Firmware-Version","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9]+(?:\\.[0-9]+){0,3}$","maxLength":31}},{"name":"Activation-Id","in":"header","required":false,"schema":{"type":"string"}},{"name":"Client-Id","in":"header","required":false,"schema":{"type":"string"}},{"name":"X-Device-Timestamp","in":"header","required":true,"schema":{"type":"string","pattern":"^[0-9]{1,12}$","description":"Unix seconds; exact header text signed"}},{"name":"X-Device-Nonce","in":"header","required":true,"schema":{"type":"string","pattern":"^[A-Za-z0-9_-]{16,128}$"}},{"name":"X-Device-Signature-Alg","in":"header","required":true,"schema":{"const":"HMAC-SHA256"}}],"responses":{"200":{"description":"Exact original application bytes; not installation confirmation","headers":{"Content-Length":{"schema":{"type":"integer","minimum":1,"maximum":8388608}},"Content-Encoding":{"schema":{"const":"identity"}}},"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}},"head":{"summary":"Not supported","responses":{"405":{"description":"Use full authenticated GET"}}}},"/api/creator-ota/login":{"post":{"tags":["Operator"],"summary":"Independent operator login","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"username":{"type":"string"},"password":{"type":"string","writeOnly":true}},"required":["username","password"]}}}}}},"/api/creator-ota/logout":{"post":{"tags":["Operator"],"summary":"Revoke current operator session","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[]}},"/api/creator-ota/me":{"get":{"tags":["Operator"],"summary":"Read current operator identity","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[]}},"/api/creator-ota/snapshot":{"get":{"tags":["Operator"],"summary":"Read settings, artifacts, device observations and audit","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Snapshot"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[]}},"/api/creator-ota/settings":{"put":{"tags":["Operator"],"summary":"Operator: update reachable service URLs or production mode","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Settings"}}}}}},"/api/creator-ota/devices":{"post":{"tags":["Operator"],"summary":"Operator: register actual factory identity and migration evidence","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/DeviceRegistration"}}}},"description":"Creates a new serial identity only; duplicate registration returns 409."}},"/api/creator-ota/devices/{serial}":{"patch":{"tags":["Operator"],"summary":"Operator: amend device identity, migration evidence or enabled state","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"type":"object"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"parameters":[{"name":"serial","in":"path","required":true,"schema":{"type":"string"}}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"serial_number":{"type":"string"},"device_id":{"type":"string"},"hardware_model":{"type":"string"},"hardware_version":{"type":"string"},"board":{"type":"string"},"product":{"const":"own_creator"},"partition_layout":{"const":"p4_32m_v2"},"enabled":{"type":"boolean"},"migration":{"$ref":"#/components/schemas/Migration"}}}}}},"description":"Factory device_key/secret cannot be replaced through this endpoint."}},"/api/creator-ota/releases":{"post":{"tags":["Operator"],"summary":"Operator: upload immutable application as draft","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Release"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"file":{"type":"string","format":"binary","description":"Standard ESP32-P4 application, <= 8 MiB"},"metadata":{"type":"string","description":"JSON serialization of ReleaseMetadata"},"evidence":{"type":"string","format":"binary","description":"ZIP whose paths/hashes match metadata.evidence.artifacts"}},"required":["file","metadata"]}}}}}},"/api/creator-ota/releases/{release_id}":{"patch":{"tags":["Operator"],"summary":"Operator: amend draft metadata/evidence without replacing binary","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Release"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}}],"requestBody":{"required":true,"content":{"multipart/form-data":{"schema":{"type":"object","properties":{"metadata":{"type":"string","description":"JSON serialization of ReleaseMetadata"},"evidence":{"type":"string","format":"binary","description":"ZIP whose paths/hashes match metadata.evidence.artifacts"}},"required":["metadata"]}}}}}},"/api/creator-ota/releases/{release_id}/publish":{"post":{"tags":["Operator"],"summary":"Operator: publish release","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Release"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rollout_percent":{"type":"integer","minimum":0,"maximum":100}}}}}}}},"/api/creator-ota/releases/{release_id}/withdraw":{"post":{"tags":["Operator"],"summary":"Operator: withdraw release","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Release"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rollout_percent":{"type":"integer","minimum":0,"maximum":100}}}}}}}},"/api/creator-ota/releases/{release_id}/pause":{"post":{"tags":["Operator"],"summary":"Operator: pause release","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Release"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rollout_percent":{"type":"integer","minimum":0,"maximum":100}}}}}}}},"/api/creator-ota/releases/{release_id}/resume":{"post":{"tags":["Operator"],"summary":"Operator: resume release","responses":{"200":{"description":"Success","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Release"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}}],"requestBody":{"required":false,"content":{"application/json":{"schema":{"type":"object","properties":{"rollout_percent":{"type":"integer","minimum":0,"maximum":100}}}}}}}},"/api/creator-ota/releases/{release_id}/download":{"get":{"tags":["Operator"],"summary":"Operator: download original artifact for review","responses":{"200":{"description":"Application original","content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}},"400":{"description":"Malformed request","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"401":{"description":"Missing/invalid/replayed signature or invalid timestamp","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"403":{"description":"Unregistered, disabled, incompatible, unmigrated or unavailable release","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"404":{"description":"Object not found","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"409":{"description":"Conflicting immutable version or release state","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"413":{"description":"Request too large","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"429":{"description":"Request rate limit","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}},"503":{"description":"Service or artifact unavailable","content":{"application/json":{"schema":{"$ref":"#/components/schemas/OperatorError"}}}}},"security":[],"parameters":[{"name":"release_id","in":"path","required":true,"schema":{"type":"string","pattern":"^[0-9a-f]{32}$"}}]}}},"components":{"securitySchemes":{"deviceHmac":{"type":"apiKey","in":"header","name":"X-Device-Signature","description":"Base64URL(no padding) HMAC-SHA256 of exact canonical request; see local signing client and fixed vectors. Other required identity/signing headers are explicit operation parameters."},"operatorSession":{"type":"http","scheme":"bearer","description":"Independent operator login session; write operations require operator role, viewer is read-only."}},"schemas":{"Error":{"type":"object","properties":{"code":{"type":"string"},"message":{"type":"string"}},"required":["code","message"]},"DeviceRequest":{"type":"object","properties":{"serial_number":{"type":"string"},"device_id":{"type":"string"},"hardware_model":{"type":"string"},"hardware_version":{"type":"string"},"product":{"const":"own_creator"},"partition_layout":{"const":"p4_32m_v2"},"intent":{"type":"string","enum":["bootstrap","check_ota"]},"board_type":{"type":"string"},"current_version":{"type":"string","pattern":"^[0-9]+(?:\\.[0-9]+){0,3}$","maxLength":31},"application":{"type":"object","properties":{"version":{"type":"string","pattern":"^[0-9]+(?:\\.[0-9]+){0,3}$","maxLength":31}}},"partition_table":{},"chip_info":{},"uuid":{"type":"string"}},"required":["intent","serial_number","hardware_model","hardware_version","product","partition_layout","board_type","current_version"]},"Firmware":{"type":"object","properties":{"version":{"type":"string","pattern":"^[0-9]+(?:\\.[0-9]+){0,3}$","maxLength":31},"url":{"type":"string","format":"uri"},"size":{"type":"integer","minimum":1,"maximum":8388608},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"},"hardware_model":{"type":"string"},"hardware_version":{"type":"string"},"board":{"type":"string"},"product":{"const":"own_creator"},"partition_layout":{"const":"p4_32m_v2"}},"required":["version","url","size","sha256","hardware_model","hardware_version","board","product","partition_layout"]},"DeviceResponse":{"type":"object","properties":{"firmware":{"oneOf":[{"$ref":"#/components/schemas/Firmware"},{"type":"null"}]},"server_time":{"type":"object","properties":{"timestamp":{"type":"integer","description":"UTC Unix milliseconds, never offset-adjusted"},"timezone_offset":{"type":"integer","description":"Display offset in minutes"}},"required":["timestamp","timezone_offset"]},"websocket":{"type":"object","properties":{"url":{"type":"string","format":"uri"},"version":{"const":1},"token":{"type":"string","description":"Empty if actual dialogue authentication is disabled/bypassed"},"expires_in":{"type":"integer","maximum":3600}},"required":["url","version","token"]},"mqtt":{"type":"object","properties":{"endpoint":{"type":"string"},"client_id":{"type":"string"},"username":{"type":"string"},"password":{"type":"string"},"publish_topic":{"type":"string"},"subscribe_topic":{"type":"string"}}}},"required":["firmware","server_time"]},"BuildEvidence":{"type":"object","properties":{"schema":{"const":1},"build_commit":{"type":"string","pattern":"^[0-9a-f]{40}$"},"board":{"type":"string"},"hardware_model":{"type":"string"},"product":{"const":"own_creator"},"partition_layout":{"const":"p4_32m_v2"},"flash_model":{"type":"string"},"record_ref":{"type":"string"},"app_sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"},"bootloader_sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"},"artifacts":{"type":"object","properties":{"app_config":{"type":"object","properties":{"path":{"type":"string","description":"Relative ZIP member path, never a server filesystem path"},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}},"required":["path","sha256"]},"bootloader_config":{"type":"object","properties":{"path":{"type":"string","description":"Relative ZIP member path, never a server filesystem path"},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}},"required":["path","sha256"]},"bootloader":{"type":"object","properties":{"path":{"type":"string","description":"Relative ZIP member path, never a server filesystem path"},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}},"required":["path","sha256"]},"hardware_record":{"type":"object","properties":{"path":{"type":"string","description":"Relative ZIP member path, never a server filesystem path"},"sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"}},"required":["path","sha256"]}},"required":["app_config","bootloader_config","bootloader","hardware_record"]}},"required":["schema","build_commit","board","hardware_model","product","partition_layout","flash_model","record_ref","app_sha256","bootloader_sha256","artifacts"]},"ReleaseMetadata":{"type":"object","properties":{"board":{"type":"string"},"hardware_model":{"type":"string"},"hardware_versions":{"type":"array","items":{"type":"string"},"minItems":1,"maxItems":32},"product":{"const":"own_creator"},"partition_layout":{"const":"p4_32m_v2"},"build_commit":{"type":"string","description":"Full build Git SHA; mandatory for publication"},"notes":{"type":"string"},"evidence":{"$ref":"#/components/schemas/BuildEvidence"}},"required":["board","hardware_model","hardware_versions","product","partition_layout"]},"Migration":{"type":"object","properties":{"migrated":{"type":"boolean"},"bootloader_sha256":{"type":"string","pattern":"^[0-9a-fA-F]{64}$"},"flash_model":{"type":"string"},"record_ref":{"type":"string"}},"required":["migrated"]},"DeviceRegistration":{"type":"object","properties":{"serial_number":{"type":"string"},"device_id":{"type":"string"},"hardware_model":{"type":"string"},"hardware_version":{"type":"string"},"board":{"type":"string"},"product":{"const":"own_creator"},"partition_layout":{"const":"p4_32m_v2"},"device_key":{"type":"string","writeOnly":true,"minLength":16,"description":"Raw factory UTF-8 secret, not hex-decoded"},"enabled":{"type":"boolean"},"migration":{"$ref":"#/components/schemas/Migration"}},"required":["serial_number","device_id","hardware_model","hardware_version","board","product","partition_layout","device_key"]},"Settings":{"type":"object","properties":{"public_url":{"type":"string","format":"uri"},"websocket_url":{"type":"string"},"production":{"type":"boolean"}}},"Release":{"type":"object","description":"Parsed immutable image metadata, target dimensions, state, rollout and evidence metadata; no server file paths"},"Snapshot":{"type":"object","properties":{"user":{"type":"object"},"settings":{"$ref":"#/components/schemas/Settings"},"releases":{"type":"array","items":{"$ref":"#/components/schemas/Release"}},"devices":{"type":"array","items":{"type":"object"}},"events":{"type":"array","items":{"type":"object","description":"Observed checks and downloads, never installation completion"}},"audit":{"type":"array","items":{"type":"object"}}}},"OperatorError":{"type":"object","properties":{"detail":{"oneOf":[{"$ref":"#/components/schemas/Error"},{"type":"string"},{"type":"array","items":{"type":"object"}}]}},"required":["detail"]}}},"externalDocs":{"description":"Local protocol, evidence and operational guide","url":"/ota/creator/docs"}}