{
  "openapi": "3.1.0",
  "info": {
    "title": "Rough Estimator API",
    "version": "1.1.0",
    "description": "Free construction material calculator API. Estimate concrete, gravel, mulch, drywall, tile, deck, paint, fence, lumber, flooring, and roofing quantities. All calculations are also available client-side at roughestimator.com.",
    "contact": { "email": "support.cosyslabs@gmail.com" },
    "license": { "name": "MIT" }
  },
  "servers": [
    { "url": "https://roughestimator.com/rough-estimator/api", "description": "Production" }
  ],
  "paths": {
    "/health": {
      "get": {
        "operationId": "health",
        "summary": "Health check",
        "tags": ["System"],
        "responses": {
          "200": {
            "description": "OK",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "status": { "type": "string", "example": "ok" },
                    "version": { "type": "string", "example": "1.1.0" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/calc/concrete": {
      "post": {
        "operationId": "calcConcrete",
        "summary": "Calculate concrete volume, bags, and cost",
        "tags": ["Calculators"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["length", "width", "depth"],
                "properties": {
                  "shape": { "type": "string", "enum": ["slab", "footing", "column", "stairs"], "default": "slab" },
                  "length": { "type": "number", "description": "Length in feet" },
                  "width": { "type": "number", "description": "Width in feet" },
                  "depth": { "type": "number", "description": "Thickness in inches" },
                  "diameter": { "type": "number", "description": "Column diameter in inches (shape=column only)" },
                  "height": { "type": "number", "description": "Column height in feet (shape=column only)" },
                  "waste_pct": { "type": "number", "default": 10, "description": "Overage percentage (ACI 301: 5–10%)" },
                  "price_per_yard": { "type": "number", "default": 0, "description": "Optional ready-mix price per yd³" }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Concrete estimate",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cubic_yards": { "type": "number" },
                    "cubic_meters": { "type": "number" },
                    "cubic_feet": { "type": "number" },
                    "bags_80lb": { "type": "number" },
                    "bags_60lb": { "type": "number" },
                    "bags_40lb": { "type": "number" },
                    "cost": { "type": "number", "description": "Optional cost in USD" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/calc/gravel": {
      "post": {
        "operationId": "calcGravel",
        "summary": "Calculate gravel tons and cubic yards",
        "tags": ["Calculators"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["length", "width", "depth"],
                "properties": {
                  "length": { "type": "number", "description": "Length in feet" },
                  "width": { "type": "number", "description": "Width in feet" },
                  "depth": { "type": "number", "description": "Depth in inches" },
                  "density": {
                    "type": "number",
                    "default": 1.5,
                    "description": "Density in ton/yd³. Pea gravel=1.4, crushed stone=1.5, #57 base=1.7"
                  },
                  "price_per_ton": { "type": "number", "default": 0 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Gravel estimate",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "cubic_yards": { "type": "number" },
                    "cubic_feet": { "type": "number" },
                    "tons": { "type": "number" },
                    "cost": { "type": "number" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/calc/roofing": {
      "post": {
        "operationId": "calcRoofing",
        "summary": "Calculate roofing squares, bundles, and underlayment",
        "tags": ["Calculators"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["length", "width"],
                "properties": {
                  "length": { "type": "number", "description": "Roof footprint length in feet" },
                  "width": { "type": "number", "description": "Roof footprint width in feet" },
                  "pitch": { "type": "number", "default": 6, "description": "Rise per 12 inches of run (e.g. 6 for 6/12)" },
                  "waste_pct": { "type": "number", "default": 10, "description": "NRCA: 10% gable, 15% hip, 20% complex" },
                  "price_per_square": { "type": "number", "default": 0 }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Roofing estimate",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "squares": { "type": "number" },
                    "bundles": { "type": "number", "description": "3 bundles per square (architectural shingles)" },
                    "underlayment_rolls": { "type": "number", "description": "4 sq/roll standard" },
                    "cost": { "type": "number" }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/subscribe": {
      "post": {
        "operationId": "subscribe",
        "summary": "Subscribe to the newsletter (triggers double opt-in email)",
        "tags": ["Newsletter"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["email"],
                "properties": {
                  "email": { "type": "string", "format": "email" },
                  "captchaToken": { "type": "string", "description": "Cloudflare Turnstile verification token" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Confirmation email sent" },
          "400": { "description": "Invalid email or CAPTCHA" },
          "429": { "description": "Rate limited" }
        }
      }
    },
    "/subscribe/confirm": {
      "post": {
        "operationId": "subscribeConfirm",
        "summary": "Confirm newsletter subscription via email token",
        "tags": ["Newsletter"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["token"],
                "properties": {
                  "token": { "type": "string", "description": "Token from confirmation email link" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Subscription confirmed" },
          "400": {
            "description": "Invalid or expired token",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "code": { "type": "string", "enum": ["invalid", "expired"] }
                  }
                }
              }
            }
          }
        }
      }
    },
    "/contact": {
      "post": {
        "operationId": "contact",
        "summary": "Send a contact message (relayed to support.cosyslabs@gmail.com)",
        "tags": ["Contact"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["name", "subject", "message"],
                "properties": {
                  "name": { "type": "string" },
                  "email": { "type": "string", "format": "email" },
                  "phone": { "type": "string" },
                  "subject": { "type": "string" },
                  "message": { "type": "string" },
                  "captchaToken": { "type": "string" }
                }
              }
            }
          }
        },
        "responses": {
          "200": { "description": "Message sent" },
          "400": { "description": "Validation error" },
          "429": { "description": "Rate limited (10/hour per IP)" }
        }
      }
    },
    "/chat": {
      "post": {
        "operationId": "chat",
        "summary": "Chat with Alex, the Rough Estimator AI assistant",
        "tags": ["AI"],
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "type": "object",
                "required": ["message"],
                "properties": {
                  "message": { "type": "string", "description": "User message" },
                  "history": {
                    "type": "array",
                    "items": {
                      "type": "object",
                      "properties": {
                        "role": { "type": "string", "enum": ["user", "assistant"] },
                        "content": { "type": "string" }
                      }
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Alex's reply",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "reply": { "type": "string" }
                  }
                }
              }
            }
          },
          "503": { "description": "AI features disabled (flags.aiEnabled=false)" }
        }
      }
    },
    "/mcp": {
      "get": {
        "operationId": "mcpInfo",
        "summary": "MCP server info — lists available tools for AI agents",
        "tags": ["AI"],
        "responses": {
          "200": {
            "description": "MCP server details",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "tools": {
                      "type": "array",
                      "items": { "type": "string" },
                      "example": ["concrete_calc", "gravel_calc", "roofing_calc", "paint_calc", "lumber_calc", "blog_search"]
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
