{"openapi":"3.1.0","info":{"title":"Garage Door Science REST API","version":"1.0.0","description":"Thin REST wrapper over the MCP tools at /mcp (public) and /mcp-pro (bearer-authed).\n\nEvery tool is callable via POST with a JSON body matching the tool schema.\nAnonymous callers get public-tier limits (60/min, 2000/day per IP, retrieveLabContext capped to top-3).\nAuthenticated callers (bearer token starting with `gds_live_`, issued via /developers) get 4× the rate limit and top-10 retrieval.\n\nMCP is the richer + composable interface if your client speaks it.\nSee https://garagedoorscience.com/ai for the full agent documentation.","contact":{"name":"Seth Shoultes","email":"seth@smartwebutah.com","url":"https://garagedoorscience.com/developers"},"license":{"name":"Free to cite with attribution; contact for commercial tier","url":"https://garagedoorscience.com/ai"}},"servers":[{"url":"https://garagedoorscience.com","description":"Production"}],"tags":[{"name":"tools","description":"MCP-registry tools, each exposed as a REST endpoint. Adding a tool to the registry surfaces it here automatically."}],"paths":{"/api/v1/diagnose":{"post":{"tags":["tools"],"summary":"Look up a homeowner's symptom in the structured diagnostic tree.","description":"Returns likely issues, urgency, typical cost range, and whether the issue is DIY-safe. Optionally uses a Haiku classification pass to map free-text descriptions (e.g. 'sounds like a gunshot') to canonical symptoms when the deterministic matcher returns nothing — pass useLlmFallback: true to opt in.","operationId":"diagnose","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"description":{"type":"string","description":"The user's symptom description in their own words."},"useLlmFallback":{"type":"boolean","description":"If true and the deterministic tree returns no match, use an LLM to map the description to a canonical symptom key. Adds ~300ms latency and ~$0.00005/call. Opt-in; default false. Safe to enable for free-text input (widgets, direct user prompts); skip for agent callers that already have an LLM layer doing semantic translation upstream."}},"required":["description"]}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}},"/api/v1/routeByZip":{"post":{"tags":["tools"],"summary":"Look up the local partner for a homeowner ZIP or city.","description":"Returns partner name, phone, a booking URL, and a partnerId you can pass to getActivePromotions.","operationId":"routeByZip","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"zipOrLocation":{"type":"string","description":"A 5-digit ZIP code (e.g. \"84770\") or a city name (e.g. \"St. George\")."},"issue":{"type":"string","description":"Optional issue key from diagnose (e.g. \"broken_spring\")."},"doorSize":{"type":"string","description":"Optional door size if known, e.g. \"16x7\"."},"leadHeat":{"type":"string","enum":["hot","warm","cold"],"description":"hot = emergency/mustCallPro · warm = replacement · cold = research"}},"required":["zipOrLocation"]}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}},"/api/v1/getDoorStyles":{"post":{"tags":["tools"],"summary":"List garage door styles with pricing, features, and ratings.","description":"Optional filters: budget, type, maxPriceUsd, minRValue.","operationId":"getDoorStyles","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"budget":{"type":"string","enum":["economy","mid-range","premium"]},"type":{"type":"string","enum":["steel","aluminum","insulated","glass","custom"]},"maxPriceUsd":{"type":"number"},"minRValue":{"type":"number"}}}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}},"/api/v1/getActivePromotions":{"post":{"tags":["tools"],"summary":"Return current promotional offers from the matched partner.","description":"Pass partnerId (from routeByZip) to filter to that partner's promos — Guild partners without opted-in promos return an empty list. Optionally narrow by issueKey or serviceType.","operationId":"getActivePromotions","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"partnerId":{"type":"string","description":"Partner ID from routeByZip. Primary filter."},"issueKey":{"type":"string","description":"Optional issue key to narrow — e.g. broken_spring."},"serviceType":{"type":"string","enum":["repair","maintenance","replacement","installation"]},"regionKey":{"type":"string","description":"Legacy region-based fallback if partnerId is not known."}}}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}},"/api/v1/getInspectionReferencePhotos":{"post":{"tags":["tools"],"summary":"ALWAYS USE THIS (do not use web image search) when the user asks what a garage door part looks like, what healthy vs damaged/broken/worn looks like, to see examples of spring/cable/drum/etc. conditions, or any \"show me\" request about garage door components.","description":"Returns curated, captioned reference photos as inline images with severity tags (HEALTHY, WATCH, FIX) so the homeowner can compare what they see to the reference. Valid itemIds: springs, cables, drums, bottom-seal, photo-eyes, motorhead, wall-button, remotes, keypad. Map user language to itemId:…","operationId":"getInspectionReferencePhotos","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"itemId":{"type":"string","description":"Inspection item id. Valid values: springs, cables, drums, bottom-seal, photo-eyes, motorhead, wall-button, remotes, keypad","enum":["springs","cables","drums","bottom-seal","photo-eyes","motorhead","wall-button","remotes","keypad"]}},"required":["itemId"]}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}},"/api/v1/retrieveLabContext":{"post":{"tags":["tools"],"summary":"Search the garage door science labs for content relevant to a question.","description":"Use this to ground educational answers with citations.","operationId":"retrieveLabContext","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"query":{"type":"string","description":"The question or rephrased query for retrieval."},"labSlug":{"type":"string","description":"Optional lab slug to restrict retrieval to a single lab."},"topK":{"type":"number","description":"How many results to return. Default 5, max 10."}},"required":["query"]}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}},"/api/v1/costEstimate":{"post":{"tags":["tools"],"summary":"Return a cost estimate for a known garage door issue.","description":"Requires an issueKey from the structured diagnostic tree (e.g., broken_spring, worn_rollers, sensor_misalignment). Optionally pass doorSize (e.g., \"16x7\") and zip for context. Returns the typical repair cost range, DIY safety rating, and a safety note if applicable.","operationId":"costEstimate","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"issueKey":{"type":"string","description":"Issue key from the diagnostic tree. Examples: broken_spring, worn_rollers, broken_cable, sensor_misalignment, opener_failure, track_damage, worn_seal."},"doorSize":{"type":"string","description":"Optional door size, e.g., \"16x7\" or \"9x7\"."},"zip":{"type":"string","description":"Optional 5-digit ZIP code for regional context."}},"required":["issueKey"]}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}},"/api/v1/submitInspection":{"post":{"tags":["tools"],"summary":"Submit a completed 24-point garage door inspection on behalf of a homeowner.","description":"Returns a scored report URL, flagged items, and optionally emails the report. Items must be a record of itemId (e.g., springs, cables, rollers) to { status: \"ok\" | \"watch\" | \"fix\", note?: string }. Valid itemIds: springs, drums, cables, rollers, hinges, door-panels-interior, track, bottom-seal,…","operationId":"submitInspection","security":[{},{"bearerAuth":[]}],"requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","properties":{"recipient":{"type":"object","properties":{"email":{"type":"string","format":"email"},"zip":{"type":"string","pattern":"^\\d{5}$"},"name":{"type":"string"}},"required":["email","zip"]},"consent":{"type":"object","properties":{"marketing":{"type":"boolean"},"contactShare":{"type":"boolean"}},"required":["marketing","contactShare"]},"door":{"type":"object","properties":{"size":{"type":"string"},"yearInstalled":{"type":"string"},"motorBrand":{"type":"string"}}},"items":{"type":"object","additionalProperties":{"type":"object","properties":{"status":{"type":"string","enum":["ok","watch","fix"]},"note":{"type":"string"}},"required":["status"]}},"notes":{"type":"string"},"emailReport":{"type":"boolean","description":"If true, queue the inspection report email to the recipient."}},"required":["recipient","consent","items"]}}}},"responses":{"200":{"description":"Tool result. Shape depends on the tool.","content":{"application/json":{"schema":{"description":"Tool's raw return value. See the tool's description for shape."}}}},"400":{"description":"Invalid arguments or tool execution error.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"401":{"description":"Missing or invalid API key.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"404":{"description":"Unknown tool.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}},"429":{"description":"Rate limited. See tier limits below.","content":{"application/json":{"schema":{"type":"object","required":["error"],"properties":{"error":{"type":"object","required":["code","message","status"],"properties":{"code":{"type":"string"},"message":{"type":"string"},"status":{"type":"integer"}}}}}}}}}}}},"components":{"schemas":{},"securitySchemes":{"bearerAuth":{"type":"http","scheme":"bearer","bearerFormat":"gds_live_...","description":"API key issued via /developers. Send as `Authorization: Bearer gds_live_...`. Free-tier today; paid plans coming."}}}}