{
  "openapi": "3.1.0",
  "info": {"title":"Desabenab runtime API","version":"2.1.0","description":"On-demand AC IR encoding and exact experimental recording lookup. The API Worker runs its WebAssembly build; the local service runs its native build. The static site serves /embed and calls the separate API Worker. No API key is required. See EMBED.md for the versioned postMessage contract."},
  "servers": [{"url":"https://YOUR_API_ORIGIN"}],
  "paths": {
    "/api/v2/health": {"get":{"summary":"Backend status and limits","responses":{"200":{"description":"Healthy","content":{"application/json":{"schema":{"type":"object"}}}}}}},
    "/api/v2/brands": {"get":{"summary":"Implemented brands","responses":{"200":{"description":"Brand list","content":{"application/json":{"schema":{"type":"object"}}}}}}},
    "/api/v2/models": {"get":{"summary":"Implemented model and remote entries","parameters":[{"name":"brand","in":"query","required":true,"schema":{"type":"string"}}],"responses":{"200":{"description":"Model list","content":{"application/json":{"schema":{"type":"object"}}}}}}},
    "/api/v2/profiles/{profileId}": {"get":{"summary":"Exact profile metadata","parameters":[{"$ref":"#/components/parameters/profileId"}],"responses":{"200":{"description":"Profile","content":{"application/json":{"schema":{"type":"object"}}}}}}},
    "/api/v2/capabilities/{profileId}": {"get":{"summary":"Device and mode capabilities","parameters":[{"$ref":"#/components/parameters/profileId"},{"name":"mode","in":"query","required":false,"schema":{"type":"string"},"description":"When supplied, returns fans and temperatures for that mode."}],"responses":{"200":{"description":"Capabilities","content":{"application/json":{"schema":{"$ref":"#/components/schemas/CapabilitiesResponse"}}}},"422":{"$ref":"#/components/responses/Error"}}}},
    "/api/v2/generate": {"post":{"summary":"Generate or retrieve an exact AC signal","requestBody":{"required":true,"content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateRequest"}}}},"responses":{"200":{"description":"Signal with carrier duty; experimental recording values are assumptions","content":{"application/json":{"schema":{"$ref":"#/components/schemas/GenerateResponse"}}}},"400":{"$ref":"#/components/responses/Error"},"413":{"$ref":"#/components/responses/Error"},"415":{"$ref":"#/components/responses/Error"},"422":{"$ref":"#/components/responses/Error"},"429":{"description":"Cloudflare generation rate limit or native encoder busy. Retry-After is 60 seconds for RATE_LIMITED and 1 second for ENCODER_BUSY.","headers":{"Retry-After":{"description":"Seconds until retry","schema":{"type":"integer"}}},"content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}},"503":{"$ref":"#/components/responses/Error"}}}}
  },
  "components": {
    "parameters":{"profileId":{"name":"profileId","in":"path","required":true,"schema":{"type":"string"}}},
    "schemas":{
      "GenerateRequest":{"type":"object","additionalProperties":false,"required":["power"],"properties":{"profileId":{"type":"string"},"brand":{"type":"string"},"model":{"type":"string"},"power":{"enum":["on","off","toggle"]},"mode":{"enum":["auto","cool","heat","dry","fan_only"]},"temperatureC":{"type":"number"},"fan":{"type":"string"}},"description":"Supply profileId or exact brand and model. Read device powerActions. On and toggle require mode, temperatureC and fan from capabilities. Off omits all three. Toggle changes current appliance power and does not mean unconditional ON or OFF."},
      "CapabilitiesResponse":{"type":"object","required":["capabilities","catalogueVersion"],"properties":{"catalogueVersion":{"type":"string"},"capabilities":{"type":"object","required":["profileId","modes","fans","temperaturesByFan","powerActions","temperatureUnit"],"properties":{"profileId":{"type":"string"},"mode":{"type":["string","null"]},"modes":{"type":"array","items":{"type":"string"}},"fans":{"type":"array","items":{"type":"string"}},"temperaturesByFan":{"type":"object","additionalProperties":{"type":"array","items":{"type":"number"}}},"fanAliases":{"type":"object","additionalProperties":{"type":"string"}},"powerActions":{"type":"array","items":{"type":"string"}},"temperatureUnit":{"const":"C"},"fixedSettings":{"type":"array","items":{"type":"string"}}}}}},
      "GenerateResponse":{"type":"object","required":["format","generationMethod","profileId","settings","frequencyHz","carrierDutyPercent","signal","crc32","durationCount","durationUs"],"properties":{"format":{"const":"ac-ir-array-v2"},"generationMethod":{"type":"string","enum":["calculated","lookup"]},"profileId":{"type":"string"},"settings":{"type":"object"},"frequencyHz":{"type":"integer"},"carrierDutyPercent":{"type":"integer","minimum":1,"maximum":100,"description":"Emitted duty; an explicit unmeasured assumption for experimental recording lookups"},"signal":{"type":"array","items":{"type":"integer","minimum":0},"description":"[frequencyHz, markUs, spaceUs, ..., crc32]"},"crc32":{"type":"integer","minimum":0,"maximum":4294967295},"durationCount":{"type":"integer"},"durationUs":{"type":"integer"},"source":{"type":"object"},"sourceCodeId":{"type":"string"},"experimental":{"type":"boolean"},"compatibility":{"type":"string"},"assumptions":{"type":"object"},"validation":{"type":"object"},"warnings":{"type":"array","items":{"type":"string"}}}},
      "Error":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message"],"properties":{"code":{"type":"string"},"message":{"type":"string"}}}}}
    },
    "responses":{"Error":{"description":"Request failed; no signal is returned","content":{"application/json":{"schema":{"$ref":"#/components/schemas/Error"}}}}}
  }
}
