{
  "openapi": "3.0.3",
  "info": {
    "title": "eMeteo API",
    "version": "3.0.0",
    "description": "REST API pre aktuálne a historické meteorologické dáta. Všetky časy sú UNIX timestampy v sekundách."
  },
  "servers": [{"url": "/api/v3"}],
  "security": [{"ApiKey": []}, {"Bearer": []}],
  "tags": [
    {"name": "Account", "description": "Kľúč a jeho využitie"},
    {"name": "Stations", "description": "Meteostanice a aktuálne dáta"},
    {"name": "History", "description": "Historické dáta a štatistiky"},
    {"name": "Webcams", "description": "Verejné webkamery"}
  ],
  "paths": {
    "/usage": {
      "get": {
        "tags": ["Account"], "summary": "Využitie a limity API kľúča", "operationId": "getUsage",
        "responses": {"200": {"description": "Využitie kľúča", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/UsageEnvelope"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "429": {"$ref": "#/components/responses/RateLimited"}}
      }
    },
    "/stations": {
      "get": {
        "tags": ["Stations"], "summary": "Zoznam meteostaníc", "operationId": "listStations",
        "parameters": [
          {"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"},
          {"name": "networks", "in": "query", "description": "Čiarkou oddelené siete", "schema": {"type": "string", "example": "emeteo,lovci"}},
          {"name": "include_current", "in": "query", "description": "Doplniť posledné meranie", "schema": {"type": "boolean", "default": false}}
        ],
        "responses": {"200": {"description": "Stránkovaný zoznam staníc", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StationsEnvelope"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}, "429": {"$ref": "#/components/responses/RateLimited"}}
      }
    },
    "/stations/{station}": {
      "get": {
        "tags": ["Stations"], "summary": "Detail meteostanice", "operationId": "getStation",
        "parameters": [{"$ref": "#/components/parameters/Station"}, {"$ref": "#/components/parameters/Network"}],
        "responses": {"200": {"description": "Detail stanice", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StationEnvelope"}}}}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Ambiguous"}}
      }
    },
    "/stations/{station}/current": {
      "get": {
        "tags": ["Stations"], "summary": "Aktuálne počasie", "operationId": "getCurrentWeather",
        "parameters": [
          {"$ref": "#/components/parameters/Station"}, {"$ref": "#/components/parameters/Network"},
          {"name": "sea_level_pressure", "in": "query", "description": "Vypočítať tlak redukovaný na hladinu mora", "schema": {"type": "boolean", "default": false}},
          {"name": "daily_statistics", "in": "query", "description": "Doplniť dnešné štatistiky", "schema": {"type": "boolean", "default": false}}
        ],
        "responses": {"200": {"description": "Posledné meranie", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/CurrentEnvelope"}}}}, "404": {"$ref": "#/components/responses/NotFound"}, "409": {"$ref": "#/components/responses/Ambiguous"}}
      }
    },
    "/stations/{station}/measurements": {
      "get": {
        "tags": ["History"], "summary": "Historické merania", "description": "Raw dáta alebo agregácia do časových intervalov. Obe hranice rozsahu sú zahrnuté.", "operationId": "getMeasurements",
        "parameters": [
          {"$ref": "#/components/parameters/Station"}, {"$ref": "#/components/parameters/Network"},
          {"$ref": "#/components/parameters/From"}, {"$ref": "#/components/parameters/To"},
          {"$ref": "#/components/parameters/Types"}, {"$ref": "#/components/parameters/Interval"}
        ],
        "responses": {"200": {"description": "Časové rady", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MeasurementsEnvelope"}}}}, "413": {"$ref": "#/components/responses/TooManyRows"}, "422": {"$ref": "#/components/responses/ValidationError"}}
      }
    },
    "/stations/{station}/series": {
      "get": {
        "tags": ["History"], "summary": "Časové rady pre graf", "description": "Ako measurements, ale s predvoleným rozsahom dnešného dňa a intervalom 300 sekúnd.", "operationId": "getSeries",
        "parameters": [
          {"$ref": "#/components/parameters/Station"}, {"$ref": "#/components/parameters/Network"},
          {"name": "from", "in": "query", "schema": {"type": "integer", "format": "int64", "minimum": 0}},
          {"name": "to", "in": "query", "schema": {"type": "integer", "format": "int64", "minimum": 0}},
          {"$ref": "#/components/parameters/Types"}, {"$ref": "#/components/parameters/Interval"}
        ],
        "responses": {"200": {"description": "Časové rady", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/MeasurementsEnvelope"}}}}, "413": {"$ref": "#/components/responses/TooManyRows"}, "422": {"$ref": "#/components/responses/ValidationError"}}
      }
    },
    "/stations/{station}/statistics/{year}": {
      "get": {
        "tags": ["History"], "summary": "Denné hodnoty ročných štatistík", "operationId": "getStatistics",
        "parameters": [
          {"$ref": "#/components/parameters/Station"}, {"$ref": "#/components/parameters/Network"},
          {"name": "year", "in": "path", "required": true, "schema": {"type": "integer", "minimum": 1970, "example": 2026}},
          {"name": "type", "in": "query", "schema": {"type": "string", "default": "temperature", "enum": ["temperature", "avg_temperature", "pressure", "wind", "rain", "solar_radiation", "uv"]}},
          {"name": "sea_level_pressure", "in": "query", "description": "Pri type=pressure redukuje hodnoty na hladinu mora", "schema": {"type": "boolean", "default": false}}
        ],
        "responses": {"200": {"description": "Denné štatistiky", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/StatisticsEnvelope"}}}}, "422": {"$ref": "#/components/responses/ValidationError"}}
      }
    },
    "/webcams": {
      "get": {
        "tags": ["Webcams"], "summary": "Zoznam webkamier", "operationId": "listWebcams",
        "parameters": [{"$ref": "#/components/parameters/Page"}, {"$ref": "#/components/parameters/PerPage"}],
        "responses": {"200": {"description": "Stránkovaný zoznam webkamier", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/WebcamsEnvelope"}}}}, "401": {"$ref": "#/components/responses/Unauthorized"}}
      }
    }
  },
  "components": {
    "securitySchemes": {
      "ApiKey": {"type": "apiKey", "in": "header", "name": "X-API-Key"},
      "Bearer": {"type": "http", "scheme": "bearer", "bearerFormat": "API key"}
    },
    "parameters": {
      "Station": {"name": "station", "in": "path", "required": true, "description": "Číselné ID alebo slug stanice", "schema": {"oneOf": [{"type": "integer"}, {"type": "string"}], "example": "banska-bystrica-zelena"}},
      "Network": {"name": "network", "in": "query", "description": "Sieť pri nejednoznačnom slugu", "schema": {"type": "string"}},
      "Page": {"name": "page", "in": "query", "schema": {"type": "integer", "minimum": 1, "default": 1}},
      "PerPage": {"name": "per_page", "in": "query", "schema": {"type": "integer", "minimum": 1, "maximum": 100, "default": 30}},
      "From": {"name": "from", "in": "query", "required": true, "description": "UNIX timestamp v sekundách", "schema": {"type": "integer", "format": "int64", "minimum": 0, "example": 1790265600}},
      "To": {"name": "to", "in": "query", "required": true, "description": "UNIX timestamp v sekundách", "schema": {"type": "integer", "format": "int64", "minimum": 0, "example": 1790351999}},
      "Types": {"name": "types", "in": "query", "description": "Čiarkou oddelené veličiny", "schema": {"type": "string", "example": "temperature,humidity,pressure"}},
      "Interval": {"name": "interval", "in": "query", "description": "0 pre raw, inak 60 až 86400 sekúnd", "schema": {"type": "integer", "default": 0, "minimum": 0, "example": 300}}
    },
    "responses": {
      "Unauthorized": {"description": "Chýbajúci alebo neplatný API kľúč", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorEnvelope"}}}},
      "NotFound": {"description": "Stanica nebola nájdená", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorEnvelope"}}}},
      "Ambiguous": {"description": "Slug existuje vo viacerých sieťach", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorEnvelope"}}}},
      "TooManyRows": {"description": "Výsledok presiahol limit riadkov", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorEnvelope"}}}},
      "ValidationError": {"description": "Neplatný rozsah alebo parameter", "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorEnvelope"}}}},
      "RateLimited": {"description": "Prekročený limit volaní", "headers": {"Retry-After": {"schema": {"type": "integer"}}}, "content": {"application/json": {"schema": {"$ref": "#/components/schemas/ErrorEnvelope"}}}}
    },
    "schemas": {
      "Meta": {"type": "object", "required": ["request_id", "api_version", "generated_at"], "properties": {"request_id": {"type": "string", "example": "c192f20fd7c1423f89e6c7b43aa1d86e"}, "api_version": {"type": "string", "example": "3.0"}, "generated_at": {"type": "integer", "format": "int64", "example": 1790344800}}},
      "Error": {"type": "object", "required": ["code", "message"], "properties": {"code": {"type": "string", "example": "invalid_api_key"}, "message": {"type": "string"}, "details": {"type": "object", "additionalProperties": true}}},
      "ErrorEnvelope": {"type": "object", "required": ["data", "meta", "errors"], "properties": {"data": {"nullable": true}, "meta": {"$ref": "#/components/schemas/Meta"}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}},
      "StationReference": {"type": "object", "required": ["id", "slug", "name", "network"], "properties": {"id": {"type": "integer"}, "slug": {"type": "string"}, "name": {"type": "string"}, "network": {"type": "string"}}},
      "Station": {"allOf": [{"$ref": "#/components/schemas/StationReference"}, {"type": "object", "properties": {"data_source": {"type": "string"}, "latitude": {"type": "number", "nullable": true}, "longitude": {"type": "number", "nullable": true}, "altitude_m": {"type": "number", "nullable": true}, "sensor_height_m": {"type": "number", "nullable": true}, "created_at": {"type": "integer", "format": "int64", "nullable": true}, "last_connection_at": {"type": "integer", "format": "int64", "nullable": true}, "url": {"type": "string", "format": "uri"}, "capabilities": {"type": "array", "items": {"type": "string"}}}}]},
      "CurrentWeather": {"type": "object", "properties": {"measured_at": {"type": "integer", "format": "int64", "nullable": true}, "temperature": {"type": "number", "nullable": true}, "humidity": {"type": "number", "nullable": true}, "pressure": {"type": "number", "nullable": true}, "pressure_sea_level": {"type": "number", "nullable": true}, "wind_speed": {"type": "number", "nullable": true}, "wind_gust": {"type": "number", "nullable": true}, "wind_direction": {"type": "number", "nullable": true}, "rain": {"type": "number", "nullable": true}, "solar_radiation": {"type": "number", "nullable": true}, "uv": {"type": "number", "nullable": true}, "dew_point": {"type": "number", "nullable": true}, "sunrise_at": {"type": "integer", "format": "int64", "nullable": true}, "sunset_at": {"type": "integer", "format": "int64", "nullable": true}, "next_full_moon_at": {"type": "integer", "format": "int64", "nullable": true}, "moon_phase": {"type": "number", "nullable": true}, "daily_statistics": {"type": "object", "nullable": true, "additionalProperties": true}}},
      "MeasurementPoint": {"type": "object", "required": ["time", "value", "samples"], "properties": {"time": {"type": "integer", "format": "int64"}, "value": {"type": "number"}, "samples": {"type": "integer", "minimum": 1}}},
      "MeasurementSeries": {"type": "object", "required": ["unit", "values"], "properties": {"unit": {"type": "string"}, "values": {"type": "array", "items": {"$ref": "#/components/schemas/MeasurementPoint"}}}},
      "Statistic": {"type": "object", "required": ["day", "measurement", "aggregation", "value"], "properties": {"day": {"type": "integer", "format": "int64"}, "measurement": {"type": "string"}, "aggregation": {"type": "string"}, "value": {"type": "number"}, "value_raw": {"type": "number", "nullable": true}, "measured_at": {"type": "integer", "format": "int64", "nullable": true}}},
      "Webcam": {"type": "object", "properties": {"id": {"type": "integer"}, "station_id": {"type": "integer"}, "station_slug": {"type": "string"}, "station_name": {"type": "string"}, "slug": {"type": "string"}, "name": {"type": "string"}, "image_url": {"type": "string", "format": "uri"}, "youtube_stream_id": {"type": "string", "nullable": true}, "last_image_at": {"type": "integer", "format": "int64", "nullable": true}}},
      "StationsEnvelope": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/Station"}}, "meta": {"allOf": [{"$ref": "#/components/schemas/Meta"}, {"type": "object", "properties": {"pagination": {"type": "object"}}}]}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}},
      "StationEnvelope": {"type": "object", "properties": {"data": {"$ref": "#/components/schemas/Station"}, "meta": {"$ref": "#/components/schemas/Meta"}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}},
      "CurrentEnvelope": {"type": "object", "properties": {"data": {"type": "object", "properties": {"station": {"$ref": "#/components/schemas/StationReference"}, "weather": {"$ref": "#/components/schemas/CurrentWeather"}}}, "meta": {"$ref": "#/components/schemas/Meta"}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}},
      "MeasurementsEnvelope": {"type": "object", "properties": {"data": {"type": "object", "properties": {"station": {"$ref": "#/components/schemas/StationReference"}, "series": {"type": "object", "additionalProperties": {"$ref": "#/components/schemas/MeasurementSeries"}}}}, "meta": {"allOf": [{"$ref": "#/components/schemas/Meta"}, {"type": "object", "properties": {"range": {"type": "object"}, "interval": {"type": "integer"}, "row_count": {"type": "integer"}, "rain_mode": {"type": "string"}}}]}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}},
      "StatisticsEnvelope": {"type": "object", "properties": {"data": {"type": "object", "properties": {"station": {"$ref": "#/components/schemas/StationReference"}, "year": {"type": "integer"}, "type": {"type": "string"}, "values": {"type": "array", "items": {"$ref": "#/components/schemas/Statistic"}}}}, "meta": {"$ref": "#/components/schemas/Meta"}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}},
      "WebcamsEnvelope": {"type": "object", "properties": {"data": {"type": "array", "items": {"$ref": "#/components/schemas/Webcam"}}, "meta": {"$ref": "#/components/schemas/Meta"}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}},
      "UsageEnvelope": {"type": "object", "properties": {"data": {"type": "object", "additionalProperties": true}, "meta": {"$ref": "#/components/schemas/Meta"}, "errors": {"type": "array", "items": {"$ref": "#/components/schemas/Error"}}}}
    }
  }
}
