{
  "openapi": "3.0.3",
  "info": {
    "title": "RotorLab API",
    "version": "1.0.0",
    "description": "Personal, key-authenticated HTTP API for the RotorLab multirotor & VTOL performance engine. Each user holds one active API key (created from My account → API access). Every request except `version` and `usage` spends one unit: the plan's daily quota first (resets 00:00 UTC), then any admin-granted or purchased credit balance; when both are exhausted the API returns 429. Available only when the server runs with --auth.",
    "contact": { "name": "RotorLab", "url": "https://rotorlab.app" },
    "license": { "name": "Proprietary" }
  },
  "servers": [
    { "url": "/api/v1", "description": "This RotorLab instance" },
    { "url": "http://127.0.0.1:8765/api/v1", "description": "Local development server" }
  ],
  "security": [ { "bearerAuth": [] } ],
  "tags": [
    { "name": "Meta", "description": "Free, unmetered endpoints" },
    { "name": "Physics", "description": "Performance analysis and reference data" },
    { "name": "Builds", "description": "Your saved build library (per-user)" }
  ],
  "paths": {
    "/version": {
      "get": {
        "tags": ["Meta"], "summary": "API name, version, author", "operationId": "getVersion",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Version" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/usage": {
      "get": {
        "tags": ["Meta"], "summary": "Your current quota, remaining, and credit balance", "operationId": "getUsage",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Usage" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" } }
      }
    },
    "/airframes": {
      "get": {
        "tags": ["Physics"], "summary": "Supported airframe types and their defaults", "operationId": "getAirframes",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "airframe_types": { "type": "object" } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } }
      }
    },
    "/catalog": {
      "get": {
        "tags": ["Physics"], "summary": "Payload parts catalog (controllers, computers, sensors, radios)", "operationId": "getCatalog",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "catalog": { "type": "object" } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } }
      }
    },
    "/analyze": {
      "post": {
        "tags": ["Physics"], "summary": "Analyze a build and return full performance results", "operationId": "analyzeBuild",
        "description": "Send a build-parameters object. Missing fields fall back to the example profile's defaults. Returns headline outputs, chart SVGs, and limit checks.",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "$ref": "#/components/schemas/BuildParams" },
          "example": { "airframe_type": "Quad X", "motor_count": 4, "prop_diameter_in": 7, "prop_pitch_in": 4, "motor_kv": 1700 } } } },
        "responses": {
          "200": { "description": "Analysis result", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/AnalyzeResponse" } } } },
          "400": { "$ref": "#/components/responses/BadRequest" },
          "401": { "$ref": "#/components/responses/Unauthorized" },
          "429": { "$ref": "#/components/responses/RateLimited" }
        }
      }
    },
    "/builds": {
      "get": {
        "tags": ["Builds"], "summary": "List your saved builds", "operationId": "listBuilds",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "type": "object", "properties": { "builds": { "type": "array", "items": { "$ref": "#/components/schemas/BuildSummary" } } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } }
      },
      "post": {
        "tags": ["Builds"], "summary": "Create or overwrite a build by name", "operationId": "saveBuild",
        "requestBody": { "required": true, "content": { "application/json": { "schema": { "type": "object", "required": ["name", "params"],
          "properties": { "name": { "type": "string" }, "params": { "$ref": "#/components/schemas/BuildParams" }, "notes": { "type": "string" } } },
          "example": { "name": "Survey hexa", "params": { "airframe_type": "Hexa", "motor_count": 6 }, "notes": "mapping rig" } } } },
        "responses": { "200": { "description": "Saved", "content": { "application/json": { "schema": { "type": "object", "properties": { "id": { "type": "integer" }, "builds": { "type": "array", "items": { "$ref": "#/components/schemas/BuildSummary" } } } } } } },
          "400": { "$ref": "#/components/responses/BadRequest" }, "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } }
      }
    },
    "/builds/{id}": {
      "parameters": [ { "name": "id", "in": "path", "required": true, "schema": { "type": "integer" }, "description": "Build id (must belong to you)" } ],
      "get": {
        "tags": ["Builds"], "summary": "Fetch one of your builds", "operationId": "getBuild",
        "responses": { "200": { "description": "OK", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Build" } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }, "404": { "$ref": "#/components/responses/NotFound" }, "429": { "$ref": "#/components/responses/RateLimited" } }
      },
      "delete": {
        "tags": ["Builds"], "summary": "Delete one of your builds", "operationId": "deleteBuild",
        "responses": { "200": { "description": "Deleted", "content": { "application/json": { "schema": { "type": "object", "properties": { "ok": { "type": "boolean" }, "builds": { "type": "array", "items": { "$ref": "#/components/schemas/BuildSummary" } } } } } } },
          "401": { "$ref": "#/components/responses/Unauthorized" }, "429": { "$ref": "#/components/responses/RateLimited" } }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "rl_*",
        "description": "Send your key as `Authorization: Bearer rl_...`. The header `X-API-Key: rl_...` is also accepted." }
    },
    "responses": {
      "Unauthorized": { "description": "Missing or invalid API key", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Invalid or missing API key" } } } },
      "BadRequest": { "description": "Invalid request body", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" } } } },
      "NotFound": { "description": "Resource not found or not owned by you", "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Build not found" } } } },
      "RateLimited": { "description": "Daily quota and credits exhausted",
        "headers": { "Retry-After": { "schema": { "type": "integer" }, "description": "Seconds until the daily quota resets (00:00 UTC)" },
          "X-RateLimit-Limit": { "schema": { "type": "integer" } }, "X-RateLimit-Remaining": { "schema": { "type": "integer" } }, "X-RateLimit-Credits": { "schema": { "type": "integer" } } },
        "content": { "application/json": { "schema": { "$ref": "#/components/schemas/Error" }, "example": { "error": "Rate limit reached: daily quota and credits are exhausted.", "limit": 1000, "used": 1000, "credits": 0 } } } }
    },
    "schemas": {
      "Version": { "type": "object", "properties": { "name": { "type": "string" }, "version": { "type": "string" }, "author": { "type": "string" } } },
      "Usage": { "type": "object", "properties": { "limit": { "type": "integer", "description": "requests/day from your plan" }, "used": { "type": "integer" }, "remaining": { "type": "integer" }, "credits": { "type": "integer" }, "day": { "type": "string", "format": "date" }, "key": { "type": "object", "nullable": true, "properties": { "prefix": { "type": "string" }, "created": { "type": "string" }, "last_used": { "type": "string", "nullable": true } } } } },
      "BuildParams": { "type": "object", "description": "Build description. All fields optional; unspecified fields use the example profile's defaults.", "properties": {
        "airframe_type": { "type": "string", "example": "Quad X" }, "motor_count": { "type": "integer", "example": 4 }, "coaxial": { "type": "boolean" },
        "dry_mass_g": { "type": "number" }, "arm_length_mm": { "type": "number" }, "prop_diameter_in": { "type": "number", "example": 7 },
        "prop_pitch_in": { "type": "number" }, "prop_blades": { "type": "integer" }, "motor_kv": { "type": "number" },
        "max_thrust_per_motor_g": { "type": "number" }, "esc_current_a": { "type": "number" }, "altitude_m": { "type": "number" }, "temp_c": { "type": "number" },
        "flat_plate_area_m2": { "type": "number" }, "usable_fraction": { "type": "number" },
        "batteries": { "type": "array", "items": { "type": "object" } }, "aux_rails": { "type": "array", "items": { "type": "object" } } },
        "additionalProperties": true },
      "AnalyzeResponse": { "type": "object", "properties": {
        "out": { "type": "object", "description": "Headline outputs", "properties": { "auw_g": { "type": "number" }, "twr": { "type": "number" }, "hover_min": { "type": "number" }, "cruise_min": { "type": "number" }, "hover_current_total_a": { "type": "number" }, "wot_current_a": { "type": "number" }, "max_speed_kmh": { "type": "number" }, "energy_wh": { "type": "number" } }, "additionalProperties": true },
        "charts": { "type": "object", "description": "Inline SVG chart strings" },
        "checks": { "type": "array", "items": { "type": "array", "items": { "type": "string" } }, "description": "[level, message] pairs (ok|warn|bad)" } } },
      "BuildSummary": { "type": "object", "properties": { "id": { "type": "integer" }, "name": { "type": "string" }, "notes": { "type": "string" }, "created": { "type": "string" }, "updated": { "type": "string" } } },
      "Build": { "type": "object", "properties": { "name": { "type": "string" }, "params": { "$ref": "#/components/schemas/BuildParams" }, "notes": { "type": "string" } } },
      "Error": { "type": "object", "properties": { "error": { "type": "string" } } }
    }
  }
}
