{
  "openapi": "3.1.0",
  "info": {
    "title": "MicrogridModeler Simulation API",
    "version": "2026-07-20",
    "description": "Public reproducible 8,760-hour techno-economic and resilience simulation endpoint for PV, wind, battery, diesel, and optional grid-connected microgrids. See https://www.microgridmodeler.com/methodology for equations, assumptions, and model boundaries."
  },
  "servers": [{ "url": "https://www.microgridmodeler.com" }],
  "paths": {
    "/api/v1/simulate": {
      "options": {
        "summary": "CORS preflight",
        "responses": { "204": { "description": "CORS headers" } }
      },
      "post": {
        "operationId": "simulateMicrogrid",
        "summary": "Run a reproducible chronological microgrid simulation",
        "description": "Provide exactly one of benchmarkKey or project. Aggregate technical, economic, and requested resilience results are returned by default; set includeHourly=true to include the complete year-one 8,760-hour dispatch trace. Seeded stochastic disturbance runs are exactly repeatable.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": { "$ref": "#/components/schemas/SimulationRequest" },
              "examples": {
                "benchmark": { "value": { "benchmarkKey": "clinic-small", "includeHourly": false } }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Simulation completed",
            "content": { "application/json": { "schema": { "$ref": "#/components/schemas/SimulationResponse" } } }
          },
          "400": { "$ref": "#/components/responses/Error" },
          "404": { "$ref": "#/components/responses/Error" },
          "413": { "$ref": "#/components/responses/Error" },
          "422": { "$ref": "#/components/responses/Error" }
        }
      }
    }
  },
  "components": {
    "responses": {
      "Error": {
        "description": "Request or simulation error",
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } }
      }
    },
    "schemas": {
      "SimulationRequest": {
        "type": "object",
        "properties": {
          "benchmarkKey": { "type": "string", "description": "Stable key from /benchmarks.json" },
          "project": { "$ref": "#/components/schemas/Project" },
          "includeHourly": { "type": "boolean", "default": false }
        },
        "oneOf": [
          { "required": ["benchmarkKey"], "not": { "required": ["project"] } },
          { "required": ["project"], "not": { "required": ["benchmarkKey"] } }
        ],
        "additionalProperties": false
      },
      "Project": {
        "type": "object",
        "required": ["id", "name", "site", "loadArchetype", "loadKw", "economics", "constraints", "design"],
        "properties": {
          "id": { "type": "string" },
          "name": { "type": "string" },
          "site": { "$ref": "#/components/schemas/Site" },
          "loadArchetype": { "type": "string" },
          "loadKw": {
            "type": "array",
            "minItems": 8760,
            "maxItems": 8760,
            "items": { "type": "number", "minimum": 0 },
            "description": "Chronological hourly load in kW, January 1 00:00 through December 31 23:00; non-leap year."
          },
          "economics": { "$ref": "#/components/schemas/Economics" },
          "constraints": { "$ref": "#/components/schemas/Constraints" },
          "design": { "$ref": "#/components/schemas/SystemDesign" },
          "grid": { "$ref": "#/components/schemas/GridContext" },
          "resilience": { "$ref": "#/components/schemas/Resilience" }
        },
        "additionalProperties": true
      },
      "Site": {
        "type": "object",
        "required": ["name", "latitude", "longitude", "climate", "albedo", "utcOffset"],
        "properties": {
          "name": { "type": "string" },
          "latitude": { "type": "number", "minimum": -90, "maximum": 90 },
          "longitude": { "type": "number", "minimum": -180, "maximum": 180 },
          "climate": { "type": "string", "enum": ["desert", "tropical", "temperate", "continental", "arctic", "maritime"] },
          "albedo": { "type": "number", "minimum": 0, "maximum": 1 },
          "utcOffset": { "type": "number", "minimum": -14, "maximum": 14 }
        },
        "additionalProperties": false
      },
      "SystemDesign": {
        "type": "object",
        "required": ["pv", "battery", "genset", "converter", "strategy"],
        "properties": {
          "pv": { "$ref": "#/components/schemas/Pv" },
          "wind": { "$ref": "#/components/schemas/Wind" },
          "battery": { "$ref": "#/components/schemas/Battery" },
          "genset": { "$ref": "#/components/schemas/Genset" },
          "converter": { "$ref": "#/components/schemas/Converter" },
          "strategy": {
            "type": "string",
            "description": "Selectable energy-management policy: forecast-aware battery-first, NPS favor-diesel, NPS legacy diesel-first, or NPS maintain-maximum-SOC.",
            "enum": ["load-following", "cycle-charging", "diesel-first", "soc-maintaining"]
          }
        },
        "additionalProperties": true
      },
      "Pv": {
        "type": "object",
        "required": ["ratedKw", "tiltDeg", "azimuthDeg", "derate", "tempCoeff", "noct", "degradation"],
        "properties": {
          "ratedKw": { "type": "number", "minimum": 0 },
          "unitCount": { "type": "integer", "minimum": 1, "default": 1 },
          "tracking": { "type": "string", "enum": ["fixed", "dual-axis"], "default": "fixed" },
          "tiltDeg": { "type": "number", "minimum": 0, "maximum": 90 },
          "azimuthDeg": { "type": "number", "minimum": 0, "maximum": 360 },
          "derate": { "type": "number", "minimum": 0, "maximum": 1 },
          "tempCoeff": { "type": "number" },
          "noct": { "type": "number" },
          "degradation": { "type": "number", "minimum": 0, "maximum": 1 }
        },
        "additionalProperties": true
      },
      "Wind": {
        "type": "object",
        "required": ["ratedKw", "sizeClass", "hubHeightM", "meanWindSpeedMs", "referenceHeightM", "shearExponent", "weibullK", "cutInMs", "ratedMs", "cutOutMs", "arrayLossFraction", "degradation"],
        "properties": {
          "ratedKw": { "type": "number", "minimum": 0 },
          "unitCount": { "type": "integer", "minimum": 1, "default": 1 },
          "sizeClass": { "type": "string", "enum": ["residential", "commercial", "medium", "large"] },
          "hubHeightM": { "type": "number", "exclusiveMinimum": 0 },
          "meanWindSpeedMs": { "type": "number", "minimum": 0 },
          "referenceHeightM": { "type": "number", "exclusiveMinimum": 0 },
          "shearExponent": { "type": "number", "minimum": 0 },
          "weibullK": { "type": "number", "exclusiveMinimum": 0 },
          "cutInMs": { "type": "number", "minimum": 0 },
          "ratedMs": { "type": "number", "minimum": 0 },
          "cutOutMs": { "type": "number", "minimum": 0 },
          "arrayLossFraction": { "type": "number", "minimum": 0, "maximum": 1 },
          "degradation": { "type": "number", "minimum": 0, "maximum": 1 }
        },
        "additionalProperties": true
      },
      "Battery": {
        "type": "object",
        "required": ["capacityKwh", "maxChargeKw", "maxDischargeKw", "roundTripEff", "minSoc", "initialSoc", "cycleLife"],
        "properties": {
          "capacityKwh": { "type": "number", "minimum": 0 },
          "unitCount": { "type": "integer", "minimum": 1, "default": 1 },
          "maxChargeKw": { "type": "number", "minimum": 0 },
          "maxDischargeKw": { "type": "number", "minimum": 0 },
          "roundTripEff": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 },
          "chargeEfficiency": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 },
          "dischargeEfficiency": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 },
          "minSoc": { "type": "number", "minimum": 0, "maximum": 1 },
          "maxSoc": { "type": "number", "minimum": 0, "maximum": 1, "default": 1 },
          "initialSoc": { "type": "number", "minimum": 0, "maximum": 1 },
          "cycleLife": { "type": "number", "minimum": 0 }
        },
        "additionalProperties": true
      },
      "Genset": {
        "type": "object",
        "required": ["ratedKw", "minLoadRatio", "fuelInterceptLPerHrPerKw", "fuelSlopeLPerKwh", "lifetimeHours"],
        "properties": {
          "ratedKw": { "type": "number", "minimum": 0 },
          "unitCount": { "type": "integer", "minimum": 1, "default": 1 },
          "minLoadRatio": { "type": "number", "minimum": 0, "maximum": 1 },
          "fuelInterceptLPerHrPerKw": { "type": "number", "minimum": 0 },
          "fuelSlopeLPerKwh": { "type": "number", "minimum": 0 },
          "startupDelayHours": { "type": "number", "minimum": 0, "default": 0 },
          "lifetimeHours": { "type": "number", "minimum": 0 }
        },
        "additionalProperties": true
      },
      "Converter": {
        "type": "object",
        "required": ["ratedKw", "efficiency", "lifetimeYears"],
        "properties": {
          "ratedKw": { "type": "number", "minimum": 0 },
          "efficiency": { "type": "number", "exclusiveMinimum": 0, "maximum": 1 },
          "lifetimeYears": { "type": "number", "minimum": 0 }
        },
        "additionalProperties": true
      },
      "GridContext": {
        "type": "object",
        "required": ["tariff", "spec"],
        "properties": {
          "tariff": { "type": "object", "description": "Normalized hourly/period electricity tariff. See the methodology for supported energy, demand, fixed, export, and coincident-peak fields.", "additionalProperties": true },
          "spec": {
            "type": "object",
            "required": ["canGridCharge", "maxImportKw", "maxExportKw", "netMetering"],
            "properties": {
              "canGridCharge": { "type": "boolean" },
              "maxImportKw": { "type": "number", "minimum": 0 },
              "maxExportKw": { "type": "number", "minimum": 0 },
              "netMetering": { "type": "boolean" }
            },
            "additionalProperties": false
          }
        },
        "additionalProperties": false
      },
      "Resilience": {
        "type": "object",
        "required": ["criticalLoadFraction", "outageDurations", "startHourStride"],
        "properties": {
          "criticalLoadFraction": { "type": "number", "minimum": 0, "maximum": 1 },
          "criticalLoadKw": { "type": "array", "minItems": 8760, "maxItems": 8760, "items": { "type": "number", "minimum": 0 } },
          "outageDurations": { "type": "array", "minItems": 1, "items": { "type": "integer", "minimum": 1, "maximum": 8760 } },
          "startHourStride": { "type": "integer", "minimum": 1, "maximum": 8760 },
          "fuelAvailableL": { "type": "number", "minimum": 0 },
          "vollPerKwh": { "type": "number", "minimum": 0 },
          "disturbance": { "$ref": "#/components/schemas/Disturbance" }
        },
        "additionalProperties": false
      },
      "Disturbance": {
        "type": "object",
        "required": ["mode", "seed", "runs", "startHour", "horizonHours", "localShiftHours", "maxShiftSamples", "assets"],
        "properties": {
          "mode": { "type": "string", "enum": ["deterministic", "stochastic"] },
          "seed": { "type": "integer" },
          "runs": { "type": "integer", "minimum": 1 },
          "startHour": { "type": "integer", "minimum": 0, "maximum": 8759 },
          "horizonHours": { "type": "integer", "minimum": 1, "maximum": 8760 },
          "localShiftHours": { "type": "integer", "minimum": 0, "maximum": 8760 },
          "maxShiftSamples": { "type": "integer", "minimum": 1, "maximum": 8760 },
          "assets": { "type": "array", "items": { "$ref": "#/components/schemas/AssetDisturbance" } }
        },
        "additionalProperties": false
      },
      "AssetDisturbance": {
        "type": "object",
        "required": ["asset", "failureProbability", "meanRepairHours"],
        "properties": {
          "asset": { "type": "string", "enum": ["pv", "wind", "battery", "genset"] },
          "affectedUnits": { "type": "integer", "minimum": 0 },
          "failureProbability": { "type": "number", "minimum": 0, "maximum": 1 },
          "meanRepairHours": { "type": "number", "minimum": 0 }
        },
        "additionalProperties": false
      },
      "Constraints": {
        "type": "object",
        "required": ["maxUnmetFraction", "minRenewableFraction", "maxExcessFraction"],
        "properties": {
          "maxUnmetFraction": { "type": "number", "minimum": 0, "maximum": 1 },
          "minRenewableFraction": { "type": "number", "minimum": 0, "maximum": 1 },
          "maxExcessFraction": { "type": "number", "minimum": 0, "maximum": 1 }
        },
        "additionalProperties": false
      },
      "Economics": {
        "type": "object",
        "required": ["discountRate", "inflationRate", "projectYears", "annualLoadGrowth", "fuelPricePerL", "fuelPriceEscalation", "elecCostEscalation", "voll", "itcFraction", "pvCapexPerKw", "windCapexPerKw", "batteryCapexPerKwh", "gensetCapexPerKw", "converterCapexPerKw", "bosFixed", "pvOmPerKwYr", "windOmPerKwYr", "batteryOmPerKwhYr", "gensetOmPerKwh", "converterOmPerKwYr", "co2PerL", "noxPerL", "so2PerL", "pm25PerL", "batteryCalendarLifeYears", "pvLifeYears", "windLifeYears"],
        "properties": {
          "discountRate": { "type": "number" },
          "inflationRate": { "type": "number" },
          "projectYears": { "type": "integer", "minimum": 1, "maximum": 50 },
          "annualLoadGrowth": { "type": "number" },
          "fuelPricePerL": { "type": "number", "minimum": 0 },
          "fuelPriceEscalation": { "type": "number" },
          "elecCostEscalation": { "type": "number" },
          "voll": { "type": "number", "minimum": 0 },
          "itcFraction": { "type": "number", "minimum": 0, "maximum": 1 },
          "pvCapexPerKw": { "type": "number", "minimum": 0 },
          "windCapexPerKw": { "type": "number", "minimum": 0 },
          "batteryCapexPerKwh": { "type": "number", "minimum": 0 },
          "gensetCapexPerKw": { "type": "number", "minimum": 0 },
          "converterCapexPerKw": { "type": "number", "minimum": 0 },
          "bosFixed": { "type": "number", "minimum": 0 },
          "pvOmPerKwYr": { "type": "number", "minimum": 0 },
          "windOmPerKwYr": { "type": "number", "minimum": 0 },
          "batteryOmPerKwhYr": { "type": "number", "minimum": 0 },
          "gensetOmPerKwh": { "type": "number", "minimum": 0 },
          "converterOmPerKwYr": { "type": "number", "minimum": 0 },
          "co2PerL": { "type": "number", "minimum": 0 },
          "noxPerL": { "type": "number", "minimum": 0 },
          "so2PerL": { "type": "number", "minimum": 0 },
          "pm25PerL": { "type": "number", "minimum": 0 },
          "batteryCalendarLifeYears": { "type": "number", "minimum": 0 },
          "pvLifeYears": { "type": "number", "minimum": 0 },
          "windLifeYears": { "type": "number", "minimum": 0 },
          "costModel": { "$ref": "#/components/schemas/CostModel" }
        },
        "additionalProperties": true
      },
      "CostModel": {
        "type": "object",
        "description": "Optional advanced real-dollar owner/lifecycle cash-flow assumptions. Omitted fields default to zero for backward compatibility.",
        "properties": {
          "capexContingencyFraction": { "type": "number", "minimum": 0 },
          "developmentCostFixed": { "type": "number", "minimum": 0 },
          "annualInsuranceFraction": { "type": "number", "minimum": 0 },
          "omEscalation": { "type": "number", "exclusiveMinimum": -1 },
          "replacementCostDeclineRate": { "type": "number", "exclusiveMinimum": -1, "exclusiveMaximum": 1 },
          "carbonPricePerTonne": { "type": "number", "minimum": 0 },
          "carbonPriceEscalation": { "type": "number", "exclusiveMinimum": -1 },
          "decommissioningCostFraction": { "type": "number", "minimum": 0 }
        },
        "additionalProperties": false
      },
      "SimulationResponse": {
        "type": "object",
        "required": ["schemaVersion", "engine", "fingerprint", "project", "provenance", "resource", "result"],
        "properties": {
          "schemaVersion": { "type": "string" },
          "engine": { "type": "string" },
          "fingerprint": {
            "type": "object",
            "properties": {
              "value": { "type": "string" },
              "method": { "type": "string" },
              "cryptographic": { "type": "boolean", "const": false }
            }
          },
          "project": { "type": "object" },
          "provenance": { "type": "object" },
          "resource": { "type": "object" },
          "result": { "type": "object", "description": "Design, technical results, economics, feasibility, violations, deterministic outage survival, and component disturbance results when requested." },
          "hourly": { "type": "object", "description": "Complete year-one energy-flow series, present only when includeHourly=true." }
        }
      },
      "Error": {
        "type": "object",
        "required": ["error"],
        "properties": {
          "error": { "type": "string" },
          "message": { "type": "string" },
          "details": { "type": "array", "items": { "type": "string" } }
        }
      }
    }
  }
}
