{
  "openapi": "3.1.0",
  "info": {
    "title": "FitCalcs Calculator API",
    "summary": "Read-only public fitness calculators: TDEE and calories, BMI and waist-to-height, and race-time prediction.",
    "description": "Machine-readable access to the FitCalcs fitness calculators. Each endpoint returns a deterministic result and names the equation behind it: Mifflin-St Jeor for TDEE and calories, NHS BMI categories plus waist-to-height ratio, and the Riegel endurance model for race-time prediction. Read-only, no authentication, no personal data, CC BY 4.0. Informational only, not medical or dietary advice. Also exposed as an MCP server at /mcp (see /.well-known/mcp.json).",
    "version": "2026-06-12",
    "license": {
      "name": "CC BY 4.0",
      "url": "https://creativecommons.org/licenses/by/4.0/"
    },
    "contact": {
      "name": "FitCalcs",
      "url": "https://example.fitgauge.placeholder/api/"
    }
  },
  "servers": [
    { "url": "https://example.fitgauge.placeholder", "description": "Production (placeholder host until launch domain is set)" }
  ],
  "externalDocs": {
    "description": "Human-readable API documentation",
    "url": "https://example.fitgauge.placeholder/api/"
  },
  "paths": {
    "/api/tdee": {
      "get": {
        "operationId": "calculateTdee",
        "summary": "TDEE, BMR and calorie targets (Mifflin-St Jeor)",
        "description": "Returns basal metabolic rate, total daily energy expenditure and maintenance, deficit and lean-gain calorie targets. Informational only, not medical or dietary advice.",
        "parameters": [
          { "name": "sex", "in": "query", "required": true, "schema": { "type": "string", "enum": ["male", "female"] } },
          { "name": "age", "in": "query", "required": true, "description": "Age in years (14 to 100).", "schema": { "type": "integer", "minimum": 14, "maximum": 100 } },
          { "name": "height", "in": "query", "required": true, "description": "Height in cm (120 to 230).", "schema": { "type": "number", "minimum": 120, "maximum": 230 } },
          { "name": "weight", "in": "query", "required": true, "description": "Weight in kg (35 to 300).", "schema": { "type": "number", "minimum": 35, "maximum": 300 } },
          { "name": "activity", "in": "query", "required": true, "description": "Activity multiplier, 1.2 to 1.9.", "schema": { "type": "number", "enum": [1.2, 1.375, 1.55, 1.725, 1.9] } }
        ],
        "responses": {
          "200": {
            "description": "TDEE result.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/TdeeResult" } } }
          },
          "400": {
            "description": "Invalid or missing parameter.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/bmi": {
      "get": {
        "operationId": "calculateBmi",
        "summary": "BMI (NHS categories) and waist-to-height ratio",
        "description": "Returns BMI, its NHS category, the healthy-weight range for the height, and, when a waist is supplied, the waist-to-height ratio and its risk band. Informational only, not a medical diagnosis.",
        "parameters": [
          { "name": "height", "in": "query", "required": true, "description": "Height in cm (120 to 230).", "schema": { "type": "number", "minimum": 120, "maximum": 230 } },
          { "name": "weight", "in": "query", "required": true, "description": "Weight in kg (35 to 300).", "schema": { "type": "number", "minimum": 35, "maximum": 300 } },
          { "name": "waist", "in": "query", "required": false, "description": "Optional waist in cm (40 to 200) for waist-to-height ratio.", "schema": { "type": "number", "minimum": 40, "maximum": 200 } }
        ],
        "responses": {
          "200": {
            "description": "BMI result.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BmiResult" } } }
          },
          "400": {
            "description": "Invalid or missing parameter.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    },
    "/api/race-predict": {
      "get": {
        "operationId": "predictRaceTimes",
        "summary": "Predict 5K, 10K, half and marathon times (Riegel)",
        "description": "From one recent race result, predicts times and per-kilometre pace for 5K, 10K, half marathon and marathon using the Riegel endurance model. Predictions assume even pacing and matched training.",
        "parameters": [
          { "name": "distance", "in": "query", "required": true, "description": "The race you ran: one of 5k, 10k, half, marathon, or a distance in km.", "schema": { "type": "string" } },
          { "name": "timeSeconds", "in": "query", "required": true, "description": "Your time over that distance, in seconds.", "schema": { "type": "number", "minimum": 1, "maximum": 86400 } }
        ],
        "responses": {
          "200": {
            "description": "Race prediction result.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/RacePredictResult" } } }
          },
          "400": {
            "description": "Invalid or missing parameter.",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "TdeeResult": {
        "type": "object",
        "properties": {
          "schema_version": { "type": "string" },
          "inputs": { "type": "object" },
          "bmr": { "type": "integer", "description": "Basal metabolic rate, kcal/day." },
          "tdee": { "type": "integer", "description": "Total daily energy expenditure, kcal/day." },
          "targets": {
            "type": "object",
            "properties": {
              "maintain": { "type": "integer" },
              "mild_loss": { "type": "integer", "description": "About 0.25 kg loss per week." },
              "loss": { "type": "integer", "description": "About 0.5 kg loss per week." },
              "lean_gain": { "type": "integer" }
            }
          },
          "equation": { "type": "string" },
          "units": { "type": "object" },
          "license": { "type": "string", "format": "uri" },
          "source": { "type": "string", "format": "uri" },
          "disclaimer": { "type": "string" }
        }
      },
      "BmiResult": {
        "type": "object",
        "properties": {
          "schema_version": { "type": "string" },
          "inputs": { "type": "object" },
          "bmi": { "type": "number" },
          "category": { "type": "string", "enum": ["underweight", "healthy", "overweight", "obese"] },
          "healthy_weight_range_kg": {
            "type": "object",
            "properties": { "min": { "type": "integer" }, "max": { "type": "integer" } }
          },
          "waist_to_height_ratio": { "type": "number" },
          "wthr_category": { "type": "string", "enum": ["healthy", "increased-risk", "high-risk"] },
          "equation": { "type": "string" },
          "units": { "type": "object" },
          "license": { "type": "string", "format": "uri" },
          "source": { "type": "string", "format": "uri" },
          "disclaimer": { "type": "string" }
        }
      },
      "RacePredictResult": {
        "type": "object",
        "properties": {
          "schema_version": { "type": "string" },
          "inputs": { "type": "object" },
          "basis": {
            "type": "object",
            "properties": { "distance_km": { "type": "number" }, "time_seconds": { "type": "number" } }
          },
          "predictions": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "distance": { "type": "string", "enum": ["5k", "10k", "half", "marathon"] },
                "distance_km": { "type": "number" },
                "time_seconds": { "type": "integer" },
                "time_hms": { "type": "string" },
                "pace_per_km": { "type": "string" }
              }
            }
          },
          "equation": { "type": "string" },
          "license": { "type": "string", "format": "uri" },
          "source": { "type": "string", "format": "uri" },
          "disclaimer": { "type": "string" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": { "type": "string" },
          "detail": { "type": "string" }
        }
      }
    }
  }
}
