{"components":{"schemas":{"AnalysisListV1":{"additionalProperties":false,"description":"Cursor-paginated public analyses, ordered newest first.","examples":[{"data":[],"nextCursor":null}],"properties":{"data":{"description":"Public analyses on the current page.","examples":[[]],"items":{"additionalProperties":false,"description":"Public organization analysis snapshot. Internal persistence and AI diagnostics are excluded.","examples":[{"completedAt":null,"createdAt":"2026-10-12T10:00:00.000Z","expiresAt":null,"externalId":null,"failure":null,"id":"507f1f77bcf86cd799439011","input":{"height":1000,"imageUrl":"https://storage.example.com/signed-image","width":1000},"links":{"report":"","share":""},"livemode":false,"locale":"en","metadata":{},"north":{"angle":0,"confidence":"high","direction":"N","source":"provided"},"object":"analysis","result":null,"review":null,"reviewMode":"auto","status":"queued","unit":null}],"properties":{"completedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Completion timestamp; null before completion.","examples":[null]},"createdAt":{"description":"Creation timestamp in ISO 8601 format.","examples":["2026-10-12T10:00:00.000Z"],"type":"string"},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Review deadline; null outside a pending gate. Gates expire after seven days.","examples":[null]},"externalId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional caller reference (up to 128 characters).","examples":["project-001"]},"failure":{"anyOf":[{"additionalProperties":false,"properties":{"code":{"description":"Stable machine-readable error code.","examples":["internal"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"}},"required":["code","message"],"type":"object"},{"type":"null"}],"description":"Public failure details; null unless failed.","examples":[null]},"id":{"description":"Public analysis identifier.","examples":["507f1f77bcf86cd799439011"],"type":"string"},"input":{"additionalProperties":false,"description":"Uploaded image and normalized dimensions.","examples":[{"height":1000,"imageUrl":"https://storage.example.com/signed-image","width":1000}],"properties":{"height":{"anyOf":[{"minimum":1,"type":"integer"},{"type":"null"}],"description":"Image height in pixels; null when unavailable.","examples":[1000]},"imageUrl":{"description":"Short-lived signed image URL. Fetch the analysis again to refresh.","examples":["https://storage.example.com/signed-image"],"type":"string"},"width":{"anyOf":[{"minimum":1,"type":"integer"},{"type":"null"}],"description":"Image width in pixels; null when unavailable.","examples":[1000]}},"required":["imageUrl","width","height"],"type":"object"},"links":{"additionalProperties":false,"description":"Hosted report and public share links. Unavailable links are empty strings.","examples":[{"report":"","share":""}],"properties":{"report":{"description":"Hosted organization report URL.","examples":["https://grihafy.com/org/sample/report/507f1f77bcf86cd799439011"],"type":"string"},"share":{"description":"Public report URL; empty if sharing is unavailable.","examples":[""],"type":"string"}},"required":["report","share"],"type":"object"},"livemode":{"description":"False for fixture-backed sandbox analyses.","examples":[false],"type":"boolean"},"locale":{"description":"Report language. Default is English; requested completed translations may require polling.","examples":["en"],"title":"ApiLocale","type":"string","enum":["en","hi","ar"]},"metadata":{"additionalProperties":{"type":"string"},"description":"Caller-defined string values, up to 20 entries and 500 characters per value.","examples":[{"project":"sample"}],"type":"object"},"north":{"additionalProperties":false,"description":"North orientation and its provenance.","examples":[{"angle":0,"confidence":"low","direction":"N","source":"provided"}],"properties":{"angle":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"North orientation in clockwise degrees; null when unknown.","examples":[0]},"confidence":{"description":"Confidence in north orientation.","examples":["low"],"type":"string","enum":["high","medium","low","none"]},"direction":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Calculated direction; MULTI spans zones and UNKNOWN lacks direction evidence.","examples":["N"]},"source":{"description":"Whether north was detected, supplied on submission or confirmed by review.","examples":["provided"],"type":"string","enum":["detected","provided","reviewed"]}},"required":["angle","direction","source","confidence"],"type":"object"},"object":{"description":"Resource discriminator.","enum":["analysis"],"examples":["analysis"],"type":"string"},"result":{"anyOf":[{"additionalProperties":false,"description":"Immutable curated report, localized when a translation is ready.","examples":[{"band":"good-foundation","categories":[],"findings":[],"floors":[],"potentialScore":85,"recommendations":[],"reportRevision":"revision-1","rooms":[],"score":80,"summary":"Sample report."}],"properties":{"band":{"anyOf":[{"type":"string","enum":["strong-alignment","good-foundation","mixed","needs-focused-attention"]},{"type":"null"}],"description":"Stored score interpretation; null when unavailable.","examples":["good-foundation"]},"categories":{"description":"Category assessments from the immutable report.","examples":[[]],"items":{"additionalProperties":false,"properties":{"key":{"description":"Category identifier.","examples":["room-placement"],"type":"string","enum":["room-placement","brahmasthana"]},"label":{"description":"Localized human-readable label.","examples":["Room placement"],"type":"string"},"score":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Assessed score from 0 to 100; null when assessment is unavailable.","examples":[80]}},"required":["key","label","score"],"type":"object"},"type":"array"},"findings":{"description":"Curated findings from the report.","examples":[[]],"items":{"additionalProperties":false,"properties":{"detail":{"description":"Localized finding detail.","examples":["Sample detail."],"type":"string"},"findingId":{"description":"Stable finding identity.","examples":["finding-1"],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"severity":{"anyOf":[{"type":"string","enum":["normal","critical"]},{"type":"null"}],"description":"Stored issue severity; null when unavailable.","examples":["normal"]},"title":{"description":"Localized finding title.","examples":["Sample finding"],"type":"string"}},"required":["findingId","roomId","severity","title","detail"],"type":"object"},"type":"array"},"floors":{"description":"Immutable floor geometry; empty for older reports without panels.","examples":[[]],"items":{"additionalProperties":false,"properties":{"bounds":{"additionalProperties":false,"description":"Normalized floor rectangle within the image.","examples":[{"h":1,"w":1,"x":0,"y":0}],"properties":{"h":{"description":"Height relative to image height (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"w":{"description":"Width relative to image width (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"x":{"description":"Left coordinate relative to image width (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"},"y":{"description":"Top coordinate relative to image height (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"}},"required":["x","y","w","h"],"title":"Box","type":"object"},"floorLevel":{"description":"Floor identifier; preserve detected floor values during review.","examples":["0"],"type":"string"},"score":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Assessed score from 0 to 100; null when assessment is unavailable.","examples":[80]}},"required":["floorLevel","bounds","score"],"type":"object"},"type":"array"},"potentialScore":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Potential score from the stored report; null when unavailable.","examples":[85]},"recommendations":{"description":"Curated recommendations from the report.","examples":[[]],"items":{"additionalProperties":false,"properties":{"actionId":{"description":"Stable recommendation identity.","examples":["action-1"],"type":"string"},"category":{"description":"Recommendation category.","examples":["placement"],"type":"string"},"cost":{"description":"Estimated cost level.","examples":["free"],"type":"string","enum":["free","low","medium","high"]},"effort":{"description":"Estimated effort level.","examples":["low"],"type":"string","enum":["low","medium","high"]},"findingId":{"description":"Stable finding identity.","examples":["finding-1"],"type":"string"},"issue":{"description":"Localized issue addressed by this action.","examples":["Sample issue."],"type":"string"},"optional":{"description":"Whether the recommendation is optional.","examples":[true],"type":"boolean"},"priority":{"description":"Recommendation priority.","examples":["low"],"type":"string","enum":["high","medium","low"]},"remedy":{"description":"Localized action from the stored report.","examples":["Sample action."],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"scorePoints":{"description":"Potential score contribution assigned in the stored report.","examples":[0],"minimum":0,"type":"integer"}},"required":["actionId","findingId","roomId","priority","category","issue","remedy","effort","cost","optional","scorePoints"],"type":"object"},"type":"array"},"reportRevision":{"description":"Immutable report revision used by this result.","examples":["revision-1"],"type":"string"},"rooms":{"description":"Detected or assessed rooms. Review rooms are null at a north gate.","examples":[[]],"items":{"additionalProperties":false,"properties":{"box":{"anyOf":[{"additionalProperties":false,"description":"Rectangle normalized to image width and height.","examples":[{"h":0.3,"w":0.3,"x":0.1,"y":0.1}],"properties":{"h":{"description":"Height relative to image height (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"w":{"description":"Width relative to image width (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"x":{"description":"Left coordinate relative to image width (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"},"y":{"description":"Top coordinate relative to image height (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"}},"required":["x","y","w","h"],"title":"Box","type":"object"},{"type":"null"}],"description":"Normalized image rectangle; result rooms without geometry use null.","examples":[{"h":0.3,"w":0.3,"x":0.1,"y":0.1}]},"concerns":{"description":"Localized concerns from the report.","examples":[[]],"items":{"type":"string"},"type":"array"},"direction":{"description":"Calculated direction; MULTI spans zones and UNKNOWN lacks direction evidence.","examples":["N"],"type":"string","enum":["N","NE","E","SE","S","SW","W","NW","CENTER","MULTI","UNKNOWN"]},"floorLevel":{"description":"Floor identifier; preserve detected floor values during review.","examples":["0"],"type":"string"},"idealDirections":{"description":"Suggested directions from the stored report.","examples":[[]],"items":{"type":"string"},"type":"array"},"label":{"description":"Localized human-readable label.","examples":["Room placement"],"type":"string"},"reason":{"description":"Localized explanation from the report.","examples":["Sample explanation."],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"roomType":{"description":"Canonical room type.","examples":["kitchen"],"type":"string","enum":["kitchen","master-bedroom","children-bedroom","guest-bedroom","bathroom","toilet","living-room","dining-room","prayer-room","study","entrance","staircase","balcony","storage","utility","hallway","garage","open-terrace","passage","lobby","servant-room","wash-area","verandah","swimming-pool","walk-in-closet","dressing-room","office","generator-room","porch","work-area","lift","alcove","courtyard","well","water-source","overhead-water-tank","underground-sump","septic-tank","granary","treasury","cowshed","medicine-room","other"]},"severity":{"anyOf":[{"type":"string","enum":["normal","critical"]},{"type":"null"}],"description":"Stored issue severity; null when unavailable.","examples":["normal"]},"sharedArea":{"description":"True for a space shared by several dwellings, such as a common lobby or stair and lift core. Shared areas are listed but never scored.","examples":[false],"type":"boolean"},"strengths":{"description":"Localized strengths from the report.","examples":[[]],"items":{"type":"string"},"type":"array"},"unitLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Dwelling this room belongs to on a multi-flat plan; null for a single dwelling.","examples":["Flat A"]},"verdict":{"anyOf":[{"type":"string","enum":["well-placed","acceptable","needs-attention","could-not-assess"]},{"type":"null"}],"description":"Stored room assessment; null when unavailable.","examples":["acceptable"]},"zones":{"description":"Occupied direction zones.","examples":[["N"]],"items":{"type":"string","enum":["N","NE","E","SE","S","SW","W","NW","CENTER"]},"type":"array"}},"required":["roomId","roomType","label","floorLevel","sharedArea","unitLabel","direction","zones","box","verdict","severity","reason","strengths","concerns","idealDirections"],"type":"object"},"type":"array"},"score":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Assessed score from 0 to 100; null when assessment is unavailable.","examples":[80]},"summary":{"description":"Localized report summary.","examples":["Sample report summary."],"type":"string"}},"required":["reportRevision","score","potentialScore","band","summary","categories","floors","rooms","findings","recommendations"],"title":"AnalysisResult","type":"object"},{"type":"null"}],"description":"Immutable curated report; null until completion.","examples":[null]},"review":{"anyOf":[{"additionalProperties":false,"properties":{"north":{"description":"North orientation and its provenance.","examples":[{"angle":0,"confidence":"low"}],"properties":{"angle":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"North orientation in clockwise degrees; null when unknown.","examples":[0]},"confidence":{"description":"Confidence in north orientation.","examples":["low"],"type":"string","enum":["high","medium","low","none"]}},"required":["angle","confidence"],"type":"object"},"rooms":{"anyOf":[{"items":{"additionalProperties":false,"description":"Room geometry for human review.","examples":[{"box":{"h":0.3,"w":0.3,"x":0.1,"y":0.1},"displayLabel":"Room","floorLevel":"0","roomId":"room-1","roomType":"kitchen"}],"properties":{"box":{"additionalProperties":false,"description":"Normalized image rectangle; result rooms without geometry use null.","examples":[{"h":0.3,"w":0.3,"x":0.1,"y":0.1}],"properties":{"h":{"description":"Height relative to image height (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"w":{"description":"Width relative to image width (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"x":{"description":"Left coordinate relative to image width (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"},"y":{"description":"Top coordinate relative to image height (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"}},"required":["x","y","w","h"],"title":"Box","type":"object"},"displayLabel":{"description":"Human-readable room label.","examples":["Bedroom"],"type":"string"},"floorLevel":{"description":"Floor identifier; preserve detected floor values during review.","examples":["0"],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"roomType":{"description":"Canonical room type.","examples":["kitchen"],"type":"string","enum":["kitchen","master-bedroom","children-bedroom","guest-bedroom","bathroom","toilet","living-room","dining-room","prayer-room","study","entrance","staircase","balcony","storage","utility","hallway","garage","open-terrace","passage","lobby","servant-room","wash-area","verandah","swimming-pool","walk-in-closet","dressing-room","office","generator-room","porch","work-area","lift","alcove","courtyard","well","water-source","overhead-water-tank","underground-sump","septic-tank","granary","treasury","cowshed","medicine-room","other"]},"sharedArea":{"description":"True for a space shared by several dwellings, such as a common lobby or stair and lift core. Shared areas are listed but never scored.","examples":[false],"type":"boolean"},"unitLabel":{"description":"Dwelling this room belongs to on a multi-flat plan; null for a single dwelling.","examples":["Flat A"],"type":"string"}},"required":["roomId","roomType","displayLabel","floorLevel","box"],"title":"ReviewRoom","type":"object"},"type":"array"},{"type":"null"}],"description":"Detected or assessed rooms. Review rooms are null at a north gate.","examples":[[]]},"stage":{"description":"Review gate currently awaiting confirmation.","examples":["north"],"type":"string","enum":["north","rooms"]}},"required":["stage","north","rooms"],"type":"object"},{"type":"null"}],"description":"Required human review data; null outside a review gate.","examples":[null]},"reviewMode":{"description":"Which review gates to use. Auto skips north review; invalid detected rooms may still require room review. north_if_low_confidence pauses for low or missing north confidence.","examples":["auto"],"type":"string","enum":["auto","north_if_low_confidence","rooms","north_and_rooms"]},"status":{"description":"Public asynchronous analysis state.","examples":["queued"],"title":"AnalysisStatus","type":"string","enum":["queued","processing","review_required","completed","failed","expired"]},"unit":{"anyOf":[{"additionalProperties":false,"properties":{"label":{"description":"Localized human-readable label.","examples":["Room placement"],"type":"string"},"siblings":{"description":"Other flats split from the same plan, each its own analysis.","examples":[[]],"items":{"additionalProperties":false,"properties":{"analysisId":{"description":"Public identifier of the sibling flat analysis.","examples":["507f1f77bcf86cd799439012"],"type":"string"},"unitLabel":{"description":"Dwelling this room belongs to on a multi-flat plan; null for a single dwelling.","examples":["Flat A"],"type":"string"}},"required":["analysisId","unitLabel"],"type":"object"},"type":"array"}},"required":["label","siblings"],"type":"object"},{"type":"null"}],"description":"Set when this analysis is one flat of a multi-flat plan; null otherwise. Each flat is its own analysis.","examples":[null]}},"required":["id","object","livemode","status","reviewMode","review","externalId","metadata","locale","createdAt","completedAt","expiresAt","failure","input","north","result","unit","links"],"title":"Analysis","type":"object"},"type":"array"},"nextCursor":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Opaque next-page cursor; null when there are no further results.","examples":[null]}},"required":["data","nextCursor"],"title":"AnalysisList","type":"object"},"AnalysisV1":{"additionalProperties":false,"description":"Public organization analysis snapshot. Internal persistence and AI diagnostics are excluded.","examples":[{"completedAt":null,"createdAt":"2026-10-12T10:00:00.000Z","expiresAt":null,"externalId":null,"failure":null,"id":"507f1f77bcf86cd799439011","input":{"height":1000,"imageUrl":"https://storage.example.com/signed-image","width":1000},"links":{"report":"","share":""},"livemode":false,"locale":"en","metadata":{},"north":{"angle":0,"confidence":"high","direction":"N","source":"provided"},"object":"analysis","result":null,"review":null,"reviewMode":"auto","status":"queued","unit":null}],"properties":{"completedAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Completion timestamp; null before completion.","examples":[null]},"createdAt":{"description":"Creation timestamp in ISO 8601 format.","examples":["2026-10-12T10:00:00.000Z"],"type":"string"},"expiresAt":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Review deadline; null outside a pending gate. Gates expire after seven days.","examples":[null]},"externalId":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Optional caller reference (up to 128 characters).","examples":["project-001"]},"failure":{"anyOf":[{"additionalProperties":false,"properties":{"code":{"description":"Stable machine-readable error code.","examples":["internal"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"}},"required":["code","message"],"type":"object"},{"type":"null"}],"description":"Public failure details; null unless failed.","examples":[null]},"id":{"description":"Public analysis identifier.","examples":["507f1f77bcf86cd799439011"],"type":"string"},"input":{"additionalProperties":false,"description":"Uploaded image and normalized dimensions.","examples":[{"height":1000,"imageUrl":"https://storage.example.com/signed-image","width":1000}],"properties":{"height":{"anyOf":[{"minimum":1,"type":"integer"},{"type":"null"}],"description":"Image height in pixels; null when unavailable.","examples":[1000]},"imageUrl":{"description":"Short-lived signed image URL. Fetch the analysis again to refresh.","examples":["https://storage.example.com/signed-image"],"type":"string"},"width":{"anyOf":[{"minimum":1,"type":"integer"},{"type":"null"}],"description":"Image width in pixels; null when unavailable.","examples":[1000]}},"required":["imageUrl","width","height"],"type":"object"},"links":{"additionalProperties":false,"description":"Hosted report and public share links. Unavailable links are empty strings.","examples":[{"report":"","share":""}],"properties":{"report":{"description":"Hosted organization report URL.","examples":["https://grihafy.com/org/sample/report/507f1f77bcf86cd799439011"],"type":"string"},"share":{"description":"Public report URL; empty if sharing is unavailable.","examples":[""],"type":"string"}},"required":["report","share"],"type":"object"},"livemode":{"description":"False for fixture-backed sandbox analyses.","examples":[false],"type":"boolean"},"locale":{"description":"Report language. Default is English; requested completed translations may require polling.","examples":["en"],"title":"ApiLocale","type":"string","enum":["en","hi","ar"]},"metadata":{"additionalProperties":{"type":"string"},"description":"Caller-defined string values, up to 20 entries and 500 characters per value.","examples":[{"project":"sample"}],"type":"object"},"north":{"additionalProperties":false,"description":"North orientation and its provenance.","examples":[{"angle":0,"confidence":"low","direction":"N","source":"provided"}],"properties":{"angle":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"North orientation in clockwise degrees; null when unknown.","examples":[0]},"confidence":{"description":"Confidence in north orientation.","examples":["low"],"type":"string","enum":["high","medium","low","none"]},"direction":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Calculated direction; MULTI spans zones and UNKNOWN lacks direction evidence.","examples":["N"]},"source":{"description":"Whether north was detected, supplied on submission or confirmed by review.","examples":["provided"],"type":"string","enum":["detected","provided","reviewed"]}},"required":["angle","direction","source","confidence"],"type":"object"},"object":{"description":"Resource discriminator.","enum":["analysis"],"examples":["analysis"],"type":"string"},"result":{"anyOf":[{"additionalProperties":false,"description":"Immutable curated report, localized when a translation is ready.","examples":[{"band":"good-foundation","categories":[],"findings":[],"floors":[],"potentialScore":85,"recommendations":[],"reportRevision":"revision-1","rooms":[],"score":80,"summary":"Sample report."}],"properties":{"band":{"anyOf":[{"type":"string","enum":["strong-alignment","good-foundation","mixed","needs-focused-attention"]},{"type":"null"}],"description":"Stored score interpretation; null when unavailable.","examples":["good-foundation"]},"categories":{"description":"Category assessments from the immutable report.","examples":[[]],"items":{"additionalProperties":false,"properties":{"key":{"description":"Category identifier.","examples":["room-placement"],"type":"string","enum":["room-placement","brahmasthana"]},"label":{"description":"Localized human-readable label.","examples":["Room placement"],"type":"string"},"score":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Assessed score from 0 to 100; null when assessment is unavailable.","examples":[80]}},"required":["key","label","score"],"type":"object"},"type":"array"},"findings":{"description":"Curated findings from the report.","examples":[[]],"items":{"additionalProperties":false,"properties":{"detail":{"description":"Localized finding detail.","examples":["Sample detail."],"type":"string"},"findingId":{"description":"Stable finding identity.","examples":["finding-1"],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"severity":{"anyOf":[{"type":"string","enum":["normal","critical"]},{"type":"null"}],"description":"Stored issue severity; null when unavailable.","examples":["normal"]},"title":{"description":"Localized finding title.","examples":["Sample finding"],"type":"string"}},"required":["findingId","roomId","severity","title","detail"],"type":"object"},"type":"array"},"floors":{"description":"Immutable floor geometry; empty for older reports without panels.","examples":[[]],"items":{"additionalProperties":false,"properties":{"bounds":{"additionalProperties":false,"description":"Normalized floor rectangle within the image.","examples":[{"h":1,"w":1,"x":0,"y":0}],"properties":{"h":{"description":"Height relative to image height (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"w":{"description":"Width relative to image width (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"x":{"description":"Left coordinate relative to image width (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"},"y":{"description":"Top coordinate relative to image height (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"}},"required":["x","y","w","h"],"title":"Box","type":"object"},"floorLevel":{"description":"Floor identifier; preserve detected floor values during review.","examples":["0"],"type":"string"},"score":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Assessed score from 0 to 100; null when assessment is unavailable.","examples":[80]}},"required":["floorLevel","bounds","score"],"type":"object"},"type":"array"},"potentialScore":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Potential score from the stored report; null when unavailable.","examples":[85]},"recommendations":{"description":"Curated recommendations from the report.","examples":[[]],"items":{"additionalProperties":false,"properties":{"actionId":{"description":"Stable recommendation identity.","examples":["action-1"],"type":"string"},"category":{"description":"Recommendation category.","examples":["placement"],"type":"string"},"cost":{"description":"Estimated cost level.","examples":["free"],"type":"string","enum":["free","low","medium","high"]},"effort":{"description":"Estimated effort level.","examples":["low"],"type":"string","enum":["low","medium","high"]},"findingId":{"description":"Stable finding identity.","examples":["finding-1"],"type":"string"},"issue":{"description":"Localized issue addressed by this action.","examples":["Sample issue."],"type":"string"},"optional":{"description":"Whether the recommendation is optional.","examples":[true],"type":"boolean"},"priority":{"description":"Recommendation priority.","examples":["low"],"type":"string","enum":["high","medium","low"]},"remedy":{"description":"Localized action from the stored report.","examples":["Sample action."],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"scorePoints":{"description":"Potential score contribution assigned in the stored report.","examples":[0],"minimum":0,"type":"integer"}},"required":["actionId","findingId","roomId","priority","category","issue","remedy","effort","cost","optional","scorePoints"],"type":"object"},"type":"array"},"reportRevision":{"description":"Immutable report revision used by this result.","examples":["revision-1"],"type":"string"},"rooms":{"description":"Detected or assessed rooms. Review rooms are null at a north gate.","examples":[[]],"items":{"additionalProperties":false,"properties":{"box":{"anyOf":[{"additionalProperties":false,"description":"Rectangle normalized to image width and height.","examples":[{"h":0.3,"w":0.3,"x":0.1,"y":0.1}],"properties":{"h":{"description":"Height relative to image height (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"w":{"description":"Width relative to image width (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"x":{"description":"Left coordinate relative to image width (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"},"y":{"description":"Top coordinate relative to image height (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"}},"required":["x","y","w","h"],"title":"Box","type":"object"},{"type":"null"}],"description":"Normalized image rectangle; result rooms without geometry use null.","examples":[{"h":0.3,"w":0.3,"x":0.1,"y":0.1}]},"concerns":{"description":"Localized concerns from the report.","examples":[[]],"items":{"type":"string"},"type":"array"},"direction":{"description":"Calculated direction; MULTI spans zones and UNKNOWN lacks direction evidence.","examples":["N"],"type":"string","enum":["N","NE","E","SE","S","SW","W","NW","CENTER","MULTI","UNKNOWN"]},"floorLevel":{"description":"Floor identifier; preserve detected floor values during review.","examples":["0"],"type":"string"},"idealDirections":{"description":"Suggested directions from the stored report.","examples":[[]],"items":{"type":"string"},"type":"array"},"label":{"description":"Localized human-readable label.","examples":["Room placement"],"type":"string"},"reason":{"description":"Localized explanation from the report.","examples":["Sample explanation."],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"roomType":{"description":"Canonical room type.","examples":["kitchen"],"type":"string","enum":["kitchen","master-bedroom","children-bedroom","guest-bedroom","bathroom","toilet","living-room","dining-room","prayer-room","study","entrance","staircase","balcony","storage","utility","hallway","garage","open-terrace","passage","lobby","servant-room","wash-area","verandah","swimming-pool","walk-in-closet","dressing-room","office","generator-room","porch","work-area","lift","alcove","courtyard","well","water-source","overhead-water-tank","underground-sump","septic-tank","granary","treasury","cowshed","medicine-room","other"]},"severity":{"anyOf":[{"type":"string","enum":["normal","critical"]},{"type":"null"}],"description":"Stored issue severity; null when unavailable.","examples":["normal"]},"sharedArea":{"description":"True for a space shared by several dwellings, such as a common lobby or stair and lift core. Shared areas are listed but never scored.","examples":[false],"type":"boolean"},"strengths":{"description":"Localized strengths from the report.","examples":[[]],"items":{"type":"string"},"type":"array"},"unitLabel":{"anyOf":[{"type":"string"},{"type":"null"}],"description":"Dwelling this room belongs to on a multi-flat plan; null for a single dwelling.","examples":["Flat A"]},"verdict":{"anyOf":[{"type":"string","enum":["well-placed","acceptable","needs-attention","could-not-assess"]},{"type":"null"}],"description":"Stored room assessment; null when unavailable.","examples":["acceptable"]},"zones":{"description":"Occupied direction zones.","examples":[["N"]],"items":{"type":"string","enum":["N","NE","E","SE","S","SW","W","NW","CENTER"]},"type":"array"}},"required":["roomId","roomType","label","floorLevel","sharedArea","unitLabel","direction","zones","box","verdict","severity","reason","strengths","concerns","idealDirections"],"type":"object"},"type":"array"},"score":{"anyOf":[{"maximum":100,"minimum":0,"type":"integer"},{"type":"null"}],"description":"Assessed score from 0 to 100; null when assessment is unavailable.","examples":[80]},"summary":{"description":"Localized report summary.","examples":["Sample report summary."],"type":"string"}},"required":["reportRevision","score","potentialScore","band","summary","categories","floors","rooms","findings","recommendations"],"title":"AnalysisResult","type":"object"},{"type":"null"}],"description":"Immutable curated report; null until completion.","examples":[null]},"review":{"anyOf":[{"additionalProperties":false,"properties":{"north":{"description":"North orientation and its provenance.","examples":[{"angle":0,"confidence":"low"}],"properties":{"angle":{"anyOf":[{"type":"number"},{"type":"null"}],"description":"North orientation in clockwise degrees; null when unknown.","examples":[0]},"confidence":{"description":"Confidence in north orientation.","examples":["low"],"type":"string","enum":["high","medium","low","none"]}},"required":["angle","confidence"],"type":"object"},"rooms":{"anyOf":[{"items":{"additionalProperties":false,"description":"Room geometry for human review.","examples":[{"box":{"h":0.3,"w":0.3,"x":0.1,"y":0.1},"displayLabel":"Room","floorLevel":"0","roomId":"room-1","roomType":"kitchen"}],"properties":{"box":{"additionalProperties":false,"description":"Normalized image rectangle; result rooms without geometry use null.","examples":[{"h":0.3,"w":0.3,"x":0.1,"y":0.1}],"properties":{"h":{"description":"Height relative to image height (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"w":{"description":"Width relative to image width (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"x":{"description":"Left coordinate relative to image width (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"},"y":{"description":"Top coordinate relative to image height (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"}},"required":["x","y","w","h"],"title":"Box","type":"object"},"displayLabel":{"description":"Human-readable room label.","examples":["Bedroom"],"type":"string"},"floorLevel":{"description":"Floor identifier; preserve detected floor values during review.","examples":["0"],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"roomType":{"description":"Canonical room type.","examples":["kitchen"],"type":"string","enum":["kitchen","master-bedroom","children-bedroom","guest-bedroom","bathroom","toilet","living-room","dining-room","prayer-room","study","entrance","staircase","balcony","storage","utility","hallway","garage","open-terrace","passage","lobby","servant-room","wash-area","verandah","swimming-pool","walk-in-closet","dressing-room","office","generator-room","porch","work-area","lift","alcove","courtyard","well","water-source","overhead-water-tank","underground-sump","septic-tank","granary","treasury","cowshed","medicine-room","other"]},"sharedArea":{"description":"True for a space shared by several dwellings, such as a common lobby or stair and lift core. Shared areas are listed but never scored.","examples":[false],"type":"boolean"},"unitLabel":{"description":"Dwelling this room belongs to on a multi-flat plan; null for a single dwelling.","examples":["Flat A"],"type":"string"}},"required":["roomId","roomType","displayLabel","floorLevel","box"],"title":"ReviewRoom","type":"object"},"type":"array"},{"type":"null"}],"description":"Detected or assessed rooms. Review rooms are null at a north gate.","examples":[[]]},"stage":{"description":"Review gate currently awaiting confirmation.","examples":["north"],"type":"string","enum":["north","rooms"]}},"required":["stage","north","rooms"],"type":"object"},{"type":"null"}],"description":"Required human review data; null outside a review gate.","examples":[null]},"reviewMode":{"description":"Which review gates to use. Auto skips north review; invalid detected rooms may still require room review. north_if_low_confidence pauses for low or missing north confidence.","examples":["auto"],"type":"string","enum":["auto","north_if_low_confidence","rooms","north_and_rooms"]},"status":{"description":"Public asynchronous analysis state.","examples":["queued"],"title":"AnalysisStatus","type":"string","enum":["queued","processing","review_required","completed","failed","expired"]},"unit":{"anyOf":[{"additionalProperties":false,"properties":{"label":{"description":"Localized human-readable label.","examples":["Room placement"],"type":"string"},"siblings":{"description":"Other flats split from the same plan, each its own analysis.","examples":[[]],"items":{"additionalProperties":false,"properties":{"analysisId":{"description":"Public identifier of the sibling flat analysis.","examples":["507f1f77bcf86cd799439012"],"type":"string"},"unitLabel":{"description":"Dwelling this room belongs to on a multi-flat plan; null for a single dwelling.","examples":["Flat A"],"type":"string"}},"required":["analysisId","unitLabel"],"type":"object"},"type":"array"}},"required":["label","siblings"],"type":"object"},{"type":"null"}],"description":"Set when this analysis is one flat of a multi-flat plan; null otherwise. Each flat is its own analysis.","examples":[null]}},"required":["id","object","livemode","status","reviewMode","review","externalId","metadata","locale","createdAt","completedAt","expiresAt","failure","input","north","result","unit","links"],"title":"Analysis","type":"object"},"CreditsV1":{"additionalProperties":false,"description":"Organization credit pool. Test keys do not read or change credits.","examples":[{"available":null,"expiringSoon":[],"held":0}],"properties":{"available":{"anyOf":[{"minimum":0,"type":"number"},{"type":"null"}],"description":"Unreserved credit balance; null for test keys.","examples":[null]},"expiringSoon":{"description":"Remaining granted credits expiring within 30 days.","examples":[[]],"items":{"properties":{"amount":{"description":"Remaining credits in the grant.","examples":[10],"minimum":0,"type":"number"},"expiresAt":{"description":"Credit grant expiry timestamp in ISO 8601 format.","examples":["2026-10-20T10:00:00.000Z"],"type":"string"}},"required":["amount","expiresAt"],"type":"object"},"type":"array"},"held":{"description":"Credits reserved for active analyses.","examples":[0],"minimum":0,"type":"number"}},"required":["available","held","expiringSoon"],"title":"Credits","type":"object"},"HttpError":{"properties":{"code":{"type":"string"},"error":{"type":"string"},"message":{"type":"string"},"statusCode":{"type":"number"}},"type":"object"}},"securitySchemes":{"apiKey":{"description":"Alternative to Bearer authentication.","in":"header","name":"x-api-key","type":"apiKey"},"bearerAuth":{"description":"Organization API key (gfy_live_ or gfy_test_).","scheme":"bearer","type":"http"}}},"info":{"description":"Organization floor-plan analysis API. Use a live or test API key.","title":"Grihafy API","version":"1.0.0"},"openapi":"3.1.0","paths":{"/v1/analyses":{"get":{"description":"List analyses for the API key organization and mode, newest first. Archived records are hidden unless archived=true. Continue with nextCursor as cursor.","operationId":"listAnalyses","parameters":[{"description":"Public asynchronous analysis state.","example":"queued","in":"query","name":"status","required":false,"schema":{"type":"string","enum":["queued","processing","review_required","completed","failed","expired"]}},{"description":"Optional caller reference (up to 128 characters).","example":"project-001","in":"query","name":"externalId","required":false,"schema":{"maxLength":128,"type":"string"}},{"description":"Exclusive lower bound on creation time.","example":"2026-10-01T00:00:00.000Z","in":"query","name":"createdAfter","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Exclusive upper bound on creation time.","example":"2026-11-01T00:00:00.000Z","in":"query","name":"createdBefore","required":false,"schema":{"format":"date-time","type":"string"}},{"description":"Filter for archived records when true; otherwise archived records are hidden.","example":false,"in":"query","name":"archived","required":false,"schema":{"type":"boolean"}},{"description":"Page size from 1 to 100; default 20.","example":20,"in":"query","name":"limit","required":false,"schema":{"default":20,"maximum":100,"minimum":1,"type":"integer"}},{"description":"Opaque cursor returned as nextCursor by the previous page.","example":"eyJjcmVhdGVkQXQiOiIyMDI2LTEwLTEyVDEwOjAwOjAwWiIsIl9pZCI6IjUwN2YxZjc3YmNmODZjZDc5OTQzOTAxMSJ9","in":"query","name":"cursor","required":false,"schema":{"maxLength":512,"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisListV1"}}},"description":"Cursor-paginated public analyses, ordered newest first."},"400":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The request does not pass validation.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["validation_failed"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The request does not pass validation."},"401":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The API key is missing, invalid, revoked or expired.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unauthorized"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The API key is missing, invalid, revoked or expired."},"403":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The organization is suspended.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["org_suspended"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The organization is suspended."},"429":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"API key request limit exceeded; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["rate_limited"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"API key request limit exceeded; honor Retry-After."},"500":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"An unexpected error occurred; include requestId when contacting support.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["internal"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"An unexpected error occurred; include requestId when contacting support."}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"List analyses","tags":["Analyses"]},"post":{"description":"Upload one image using a required idempotency key. Live submissions reserve one organization credit; test submissions use fixtures. Poll the returned analysis, then resume any required review within seven days.","operationId":"createAnalysis","parameters":[{"description":"Required printable ASCII retry key, scoped to organization and live/test mode for 24 hours. Reuse only for an identical file and fields.","example":"floor-plan-2026-10-12-001","in":"header","name":"idempotency-key","required":true,"schema":{"maxLength":255,"minLength":1,"pattern":"^[\\x20-\\x7e]+$","type":"string"}}],"requestBody":{"content":{"multipart/form-data":{"schema":{"additionalProperties":false,"properties":{"externalId":{"description":"Optional caller reference (up to 128 characters).","examples":["project-001"],"maxLength":128,"type":"string"},"file":{"description":"One JPEG, PNG or WebP image, maximum 10 MB.","format":"binary","type":"string"},"locale":{"description":"Report language. Default is English; requested completed translations may require polling.","examples":["en"],"title":"ApiLocale","type":"string","enum":["en","hi","ar"]},"metadata":{"description":"JSON-encoded object with up to 20 string values (500 characters each).","examples":["{\"project\":\"sample\"}"],"type":"string"},"northAngle":{"description":"Clockwise north angle from 0 to 359.99 degrees.","examples":["0"],"type":"string"},"reviewMode":{"description":"Which review gates to use. Auto skips north review; invalid detected rooms may still require room review. north_if_low_confidence pauses for low or missing north confidence.","examples":["auto"],"type":"string","enum":["auto","north_if_low_confidence","rooms","north_and_rooms"]}},"required":["reviewMode","file"],"type":"object"}}},"required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisV1"}}},"description":"Public organization analysis snapshot. Internal persistence and AI diagnostics are excluded."},"400":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The request does not pass validation.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["validation_failed"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The request does not pass validation."},"401":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The API key is missing, invalid, revoked or expired.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unauthorized"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The API key is missing, invalid, revoked or expired."},"402":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Organization has no available credit.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["insufficient_credits"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Organization has no available credit."},"403":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The organization is suspended.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["org_suspended"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The organization is suspended."},"409":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Conflicting analysis state or a submission with this key is still running.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["invalid_state","idempotency_in_progress"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Conflicting analysis state or a submission with this key is still running."},"413":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Image exceeds 10 MB.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["file_too_large"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Image exceeds 10 MB."},"415":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Image must be JPEG, PNG or WebP.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unsupported_media"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Image must be JPEG, PNG or WebP."},"422":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Key was reused for different input, or image decoding failed.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["idempotency_key_reused","image_unreadable"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Key was reused for different input, or image decoding failed."},"429":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"API key or organization queue limit reached; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["rate_limited","queue_full"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"API key or organization queue limit reached; honor Retry-After."},"500":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"An unexpected error occurred; include requestId when contacting support.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["internal"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"An unexpected error occurred; include requestId when contacting support."},"503":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Workers or accepted analysis temporarily unavailable; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["service_unavailable"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Workers or accepted analysis temporarily unavailable; honor Retry-After."}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Submit a floor plan","tags":["Analyses"]}},"/v1/analyses/{id}":{"delete":{"description":"Permanently delete the analysis and its image. Completed analyses keep their captured credit; other deletable analyses release their hold. Active processing cannot be deleted.","operationId":"deleteAnalysis","parameters":[{"description":"Analysis identifier returned by submission.","example":"507f1f77bcf86cd799439011","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"204":{"description":"Analysis permanently deleted. No response body."},"400":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The request does not pass validation.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["validation_failed"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The request does not pass validation."},"401":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The API key is missing, invalid, revoked or expired.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unauthorized"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The API key is missing, invalid, revoked or expired."},"403":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The organization is suspended.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["org_suspended"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The organization is suspended."},"404":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Analysis does not exist in this organization and mode.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["not_found"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Analysis does not exist in this organization and mode."},"409":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Analysis is processing or changed before deletion.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["invalid_state"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Analysis is processing or changed before deletion."},"429":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"API key request limit exceeded; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["rate_limited"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"API key request limit exceeded; honor Retry-After."},"500":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"An unexpected error occurred; include requestId when contacting support.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["internal"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"An unexpected error occurred; include requestId when contacting support."}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Delete an analysis","tags":["Analyses"]},"get":{"description":"Poll the public analysis snapshot. Request locale=en, hi or ar; completed translations not yet ready return translation_pending with Retry-After. Image URLs are short-lived; fetch again to refresh.","operationId":"getAnalysis","parameters":[{"description":"Report language. Default is English; requested completed translations may require polling.","example":"en","in":"query","name":"locale","required":false,"schema":{"type":"string","enum":["en","hi","ar"]}},{"description":"Analysis identifier returned by submission.","example":"507f1f77bcf86cd799439011","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisV1"}}},"description":"Public organization analysis snapshot. Internal persistence and AI diagnostics are excluded."},"400":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The request does not pass validation.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["validation_failed"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The request does not pass validation."},"401":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The API key is missing, invalid, revoked or expired.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unauthorized"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The API key is missing, invalid, revoked or expired."},"403":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The organization is suspended.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["org_suspended"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The organization is suspended."},"404":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Analysis does not exist in this organization and mode.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["not_found"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Analysis does not exist in this organization and mode."},"409":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Requested translation is processing; retry after 10 seconds.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["translation_pending"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Requested translation is processing; retry after 10 seconds."},"429":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"API key request limit exceeded; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["rate_limited"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"API key request limit exceeded; honor Retry-After."},"500":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"An unexpected error occurred; include requestId when contacting support.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["internal"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"An unexpected error occurred; include requestId when contacting support."}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Get an analysis","tags":["Analyses"]}},"/v1/analyses/{id}/north":{"post":{"description":"Confirm the north angle and enqueue the next stage. Requires the matching review stage and an unexpired gate.","operationId":"resumeNorth","parameters":[{"description":"Analysis identifier returned by submission.","example":"507f1f77bcf86cd799439011","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"northAngle":0},"schema":{"additionalProperties":false,"description":"Confirmed north angle for a pending north gate.","properties":{"northAngle":{"description":"Clockwise north angle from 0 to 359.99 degrees.","examples":[0],"maximum":359.99,"minimum":0,"type":"number"}},"required":["northAngle"],"title":"NorthResume","type":"object"}}},"description":"Confirmed north angle for a pending north gate.","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisV1"}}},"description":"Public organization analysis snapshot. Internal persistence and AI diagnostics are excluded."},"400":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The request does not pass validation.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["validation_failed"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The request does not pass validation."},"401":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The API key is missing, invalid, revoked or expired.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unauthorized"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The API key is missing, invalid, revoked or expired."},"403":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The organization is suspended.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["org_suspended"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The organization is suspended."},"404":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Analysis does not exist in this organization and mode.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["not_found"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Analysis does not exist in this organization and mode."},"409":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Analysis is not awaiting this review, or its state changed.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["invalid_state"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Analysis is not awaiting this review, or its state changed."},"429":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"API key or queue limit reached; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["rate_limited","queue_full"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"API key or queue limit reached; honor Retry-After."},"500":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"An unexpected error occurred; include requestId when contacting support.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["internal"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"An unexpected error occurred; include requestId when contacting support."},"503":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Workers or accepted analysis temporarily unavailable; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["service_unavailable"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Workers or accepted analysis temporarily unavailable; honor Retry-After."}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Resume north review","tags":["Analyses"]}},"/v1/analyses/{id}/rooms":{"post":{"description":"Accept all detected rooms or submit corrected rooms. Existing IDs must match detected rooms; use user-room- IDs for added rooms and preserve known floor levels. Enqueue the next stage. On a plan that shows several flats, every review mode pauses here: choose the flat to analyse with primaryUnitLabel, send treatAsOneHome if the image is one home, or set analyzeAllUnits to queue every flat now. Requires the matching review stage and an unexpired gate.","operationId":"resumeRooms","parameters":[{"description":"Analysis identifier returned by submission.","example":"507f1f77bcf86cd799439011","in":"path","name":"id","required":true,"schema":{"type":"string"}}],"requestBody":{"content":{"application/json":{"example":{"acceptDetected":true},"schema":{"anyOf":[{"additionalProperties":false,"properties":{"analyzeAllUnits":{"description":"Set true to queue every other flat of a multi-flat plan now, with its detected rooms accepted. A flat that cannot be queued stays at review_required.","examples":[false],"type":"boolean"},"primaryUnitLabel":{"description":"Flat to analyse now on a multi-flat plan; defaults to the first. The other flats wait at room review as sibling analyses.","examples":["Flat A"],"maxLength":100,"minLength":1,"type":"string"},"rooms":{"description":"Detected or assessed rooms. Review rooms are null at a north gate.","examples":[[{"box":{"h":0.3,"w":0.3,"x":0.1,"y":0.1},"displayLabel":"Room","floorLevel":"0","roomId":"room-1","roomType":"kitchen"}]],"items":{"additionalProperties":false,"description":"Room geometry for human review.","examples":[{"box":{"h":0.3,"w":0.3,"x":0.1,"y":0.1},"displayLabel":"Room","floorLevel":"0","roomId":"room-1","roomType":"kitchen"}],"properties":{"box":{"additionalProperties":false,"description":"Normalized image rectangle; result rooms without geometry use null.","examples":[{"h":0.3,"w":0.3,"x":0.1,"y":0.1}],"properties":{"h":{"description":"Height relative to image height (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"w":{"description":"Width relative to image width (0–1).","examples":[0.3],"maximum":1,"minimum":0,"type":"number"},"x":{"description":"Left coordinate relative to image width (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"},"y":{"description":"Top coordinate relative to image height (0–1).","examples":[0.1],"maximum":1,"minimum":0,"type":"number"}},"required":["x","y","w","h"],"title":"Box","type":"object"},"displayLabel":{"description":"Human-readable room label.","examples":["Bedroom"],"type":"string"},"floorLevel":{"description":"Floor identifier; preserve detected floor values during review.","examples":["0"],"type":"string"},"roomId":{"description":"Stable detected room ID; use user-room- IDs for added review rooms.","examples":["room-1"],"type":"string"},"roomType":{"description":"Canonical room type.","examples":["kitchen"],"type":"string","enum":["kitchen","master-bedroom","children-bedroom","guest-bedroom","bathroom","toilet","living-room","dining-room","prayer-room","study","entrance","staircase","balcony","storage","utility","hallway","garage","open-terrace","passage","lobby","servant-room","wash-area","verandah","swimming-pool","walk-in-closet","dressing-room","office","generator-room","porch","work-area","lift","alcove","courtyard","well","water-source","overhead-water-tank","underground-sump","septic-tank","granary","treasury","cowshed","medicine-room","other"]},"sharedArea":{"description":"True for a space shared by several dwellings, such as a common lobby or stair and lift core. Shared areas are listed but never scored.","examples":[false],"type":"boolean"},"unitLabel":{"description":"Dwelling this room belongs to on a multi-flat plan; null for a single dwelling.","examples":["Flat A"],"type":"string"}},"required":["roomId","roomType","displayLabel","floorLevel","box"],"title":"ReviewRoom","type":"object"},"maxItems":50,"minItems":1,"type":"array"},"treatAsOneHome":{"description":"Set true only when every room belongs to one home. Flats on the same floor are then analysed together and their directions will be wrong.","examples":[false],"type":"boolean"}},"required":["rooms"],"type":"object"},{"additionalProperties":false,"properties":{"acceptDetected":{"description":"Set true to confirm all detected rooms without editing.","enum":[true],"examples":[true],"type":"boolean"},"analyzeAllUnits":{"description":"Set true to queue every other flat of a multi-flat plan now, with its detected rooms accepted. A flat that cannot be queued stays at review_required.","examples":[false],"type":"boolean"},"primaryUnitLabel":{"description":"Flat to analyse now on a multi-flat plan; defaults to the first. The other flats wait at room review as sibling analyses.","examples":["Flat A"],"maxLength":100,"minLength":1,"type":"string"},"treatAsOneHome":{"description":"Set true only when every room belongs to one home. Flats on the same floor are then analysed together and their directions will be wrong.","examples":[false],"type":"boolean"}},"required":["acceptDetected"],"type":"object"}],"description":"Accept detected rooms or replace the reviewed room set.","title":"RoomResume"}}},"description":"Accept detected rooms or replace the reviewed room set.","required":true},"responses":{"202":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/AnalysisV1"}}},"description":"Public organization analysis snapshot. Internal persistence and AI diagnostics are excluded."},"400":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The request does not pass validation.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["validation_failed"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The request does not pass validation."},"401":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The API key is missing, invalid, revoked or expired.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unauthorized"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The API key is missing, invalid, revoked or expired."},"403":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The organization is suspended.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["org_suspended"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The organization is suspended."},"404":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Analysis does not exist in this organization and mode.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["not_found"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Analysis does not exist in this organization and mode."},"409":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Analysis is not awaiting this review, or its state changed.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["invalid_state"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Analysis is not awaiting this review, or its state changed."},"429":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"API key or queue limit reached; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["rate_limited","queue_full"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"API key or queue limit reached; honor Retry-After."},"500":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"An unexpected error occurred; include requestId when contacting support.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["internal"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"An unexpected error occurred; include requestId when contacting support."},"503":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Workers or accepted analysis temporarily unavailable; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["service_unavailable"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"Workers or accepted analysis temporarily unavailable; honor Retry-After."}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Resume rooms review","tags":["Analyses"]}},"/v1/credits":{"get":{"description":"Return available and reserved credits, plus grants expiring within 30 days. Test keys return available=null, held=0 and an empty expiringSoon list.","operationId":"getCredits","responses":{"200":{"content":{"application/json":{"schema":{"$ref":"#/components/schemas/CreditsV1"}}},"description":"Organization credit pool. Test keys do not read or change credits."},"400":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The request does not pass validation.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["validation_failed"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The request does not pass validation."},"401":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The API key is missing, invalid, revoked or expired.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["unauthorized"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The API key is missing, invalid, revoked or expired."},"403":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"The organization is suspended.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["org_suspended"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"The organization is suspended."},"429":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"API key request limit exceeded; honor Retry-After.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["rate_limited"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"API key request limit exceeded; honor Retry-After."},"500":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"An unexpected error occurred; include requestId when contacting support.","properties":{"code":{"description":"Stable machine-readable error code.","enum":["internal"],"type":"string"},"details":{"description":"Optional validation details; may contain Fastify validation entries or path/message entries.","examples":[[{"message":"Required","path":"/reviewMode"}]]},"error":{"description":"HTTP status name.","examples":["Internal Server Error"],"type":"string"},"message":{"description":"Human-readable error message.","examples":["Internal Server Error"],"type":"string"},"requestId":{"description":"Request identity for diagnostics; also returned in x-request-id.","examples":["req-1"],"type":"string"},"statusCode":{"description":"HTTP response status.","examples":[500],"type":"integer"}},"required":["statusCode","error","message","code","requestId"],"type":"object"}}},"description":"An unexpected error occurred; include requestId when contacting support."}},"security":[{"bearerAuth":[]},{"apiKey":[]}],"summary":"Get organization credits","tags":["Credits"]}}},"servers":[{"url":"https://api.grihafy.com"}],"webhooks":{"analysis.completed":{"post":{"description":"Delivered at least once to the configured organization endpoint. Verify Grihafy-Signature over the raw body; deduplicate by id. Event types form an open set.","operationId":"analysis_completed","parameters":[{"description":"HMAC-SHA256(secret, \"<t>.<raw body>\"). Reject timestamps older than 5 minutes. Rotation includes both v1 signatures for 24 hours.","in":"header","name":"Grihafy-Signature","required":true,"schema":{"examples":["t=1791280872,v1=<hex HMAC-SHA256>"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Signed webhook event envelope.","properties":{"createdAt":{"description":"Event creation time.","examples":["2026-10-12T10:01:12Z"],"format":"date-time","type":"string"},"data":{"description":"Public analysis snapshot at transition time.","properties":{"analysis":{"$ref":"#/components/schemas/AnalysisV1"}},"required":["analysis"],"type":"object"},"id":{"description":"Event identity for deduplication.","examples":["evt_01J_SAMPLE"],"type":"string"},"livemode":{"description":"False for test-key events.","examples":[false],"type":"boolean"},"type":{"const":"analysis.completed","description":"Event type; ignore unknown types.","type":"string"}},"required":["id","type","createdAt","livemode","data"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Any 2xx response within 10 seconds acknowledges receipt. Retry delays are approximately 1m, 5m, 30m, 2h, 6h, 12h and 24h; stop after 8 attempts."}},"summary":"analysis.completed"}},"analysis.expired":{"post":{"description":"Delivered at least once to the configured organization endpoint. Verify Grihafy-Signature over the raw body; deduplicate by id. Event types form an open set.","operationId":"analysis_expired","parameters":[{"description":"HMAC-SHA256(secret, \"<t>.<raw body>\"). Reject timestamps older than 5 minutes. Rotation includes both v1 signatures for 24 hours.","in":"header","name":"Grihafy-Signature","required":true,"schema":{"examples":["t=1791280872,v1=<hex HMAC-SHA256>"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Signed webhook event envelope.","properties":{"createdAt":{"description":"Event creation time.","examples":["2026-10-12T10:01:12Z"],"format":"date-time","type":"string"},"data":{"description":"Public analysis snapshot at transition time.","properties":{"analysis":{"$ref":"#/components/schemas/AnalysisV1"}},"required":["analysis"],"type":"object"},"id":{"description":"Event identity for deduplication.","examples":["evt_01J_SAMPLE"],"type":"string"},"livemode":{"description":"False for test-key events.","examples":[false],"type":"boolean"},"type":{"const":"analysis.expired","description":"Event type; ignore unknown types.","type":"string"}},"required":["id","type","createdAt","livemode","data"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Any 2xx response within 10 seconds acknowledges receipt. Retry delays are approximately 1m, 5m, 30m, 2h, 6h, 12h and 24h; stop after 8 attempts."}},"summary":"analysis.expired"}},"analysis.failed":{"post":{"description":"Delivered at least once to the configured organization endpoint. Verify Grihafy-Signature over the raw body; deduplicate by id. Event types form an open set.","operationId":"analysis_failed","parameters":[{"description":"HMAC-SHA256(secret, \"<t>.<raw body>\"). Reject timestamps older than 5 minutes. Rotation includes both v1 signatures for 24 hours.","in":"header","name":"Grihafy-Signature","required":true,"schema":{"examples":["t=1791280872,v1=<hex HMAC-SHA256>"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Signed webhook event envelope.","properties":{"createdAt":{"description":"Event creation time.","examples":["2026-10-12T10:01:12Z"],"format":"date-time","type":"string"},"data":{"description":"Public analysis snapshot at transition time.","properties":{"analysis":{"$ref":"#/components/schemas/AnalysisV1"}},"required":["analysis"],"type":"object"},"id":{"description":"Event identity for deduplication.","examples":["evt_01J_SAMPLE"],"type":"string"},"livemode":{"description":"False for test-key events.","examples":[false],"type":"boolean"},"type":{"const":"analysis.failed","description":"Event type; ignore unknown types.","type":"string"}},"required":["id","type","createdAt","livemode","data"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Any 2xx response within 10 seconds acknowledges receipt. Retry delays are approximately 1m, 5m, 30m, 2h, 6h, 12h and 24h; stop after 8 attempts."}},"summary":"analysis.failed"}},"analysis.review_required":{"post":{"description":"Delivered at least once to the configured organization endpoint. Verify Grihafy-Signature over the raw body; deduplicate by id. Event types form an open set.","operationId":"analysis_review_required","parameters":[{"description":"HMAC-SHA256(secret, \"<t>.<raw body>\"). Reject timestamps older than 5 minutes. Rotation includes both v1 signatures for 24 hours.","in":"header","name":"Grihafy-Signature","required":true,"schema":{"examples":["t=1791280872,v1=<hex HMAC-SHA256>"],"type":"string"}}],"requestBody":{"content":{"application/json":{"schema":{"additionalProperties":false,"description":"Signed webhook event envelope.","properties":{"createdAt":{"description":"Event creation time.","examples":["2026-10-12T10:01:12Z"],"format":"date-time","type":"string"},"data":{"description":"Public analysis snapshot at transition time.","properties":{"analysis":{"$ref":"#/components/schemas/AnalysisV1"}},"required":["analysis"],"type":"object"},"id":{"description":"Event identity for deduplication.","examples":["evt_01J_SAMPLE"],"type":"string"},"livemode":{"description":"False for test-key events.","examples":[false],"type":"boolean"},"type":{"const":"analysis.review_required","description":"Event type; ignore unknown types.","type":"string"}},"required":["id","type","createdAt","livemode","data"],"type":"object"}}},"required":true},"responses":{"200":{"description":"Any 2xx response within 10 seconds acknowledges receipt. Retry delays are approximately 1m, 5m, 30m, 2h, 6h, 12h and 24h; stop after 8 attempts."}},"summary":"analysis.review_required"}}}}