openapi: 3.0.3
info:
  title: Starnberger See API
  description: Public API for Starnberger See water-temperature measurements and forecasts.
  version: 1.4.0
servers:
  - url: https://starnberger.app
    description: Production server
paths:
  /api/v1/latest:
    get:
      summary: Get the latest measurement
      description: Returns the single most recent water-temperature measurement. Offsetless timestamps are Europe/Berlin wall-clock time.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Measurement'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/entries:
    get:
      summary: Get the last N entries
      description: Returns up to N most recent temperature measurements in chronological order. Offsetless timestamps are Europe/Berlin wall-clock time.
      parameters:
        - name: limit
          in: query
          description: The number of entries to return. Must be between 1 and 128.
          required: false
          schema:
            type: integer
            default: 24
            minimum: 1
            maximum: 128
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                type: array
                items:
                  $ref: '#/components/schemas/Measurement'
        '400':
          description: Invalid limit parameter
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'

  /api/v1/forecast:
    get:
      summary: Get the water temperature forecast
      description: Returns the next 12 predicted lake-temperature hours with 50 and 90 percent prediction intervals. Offsetless base_time and forecast point times are Europe/Berlin wall-clock time; generated_at is a UTC instant.
      responses:
        '200':
          description: Successful response
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Forecast'
        '404':
          description: No fresh forecast available
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '500':
          description: Internal server error
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Error'
        '429':
          $ref: '#/components/responses/RateLimited'

components:
  responses:
    RateLimited:
      description: Too many requests. Retry after the number of seconds in the Retry-After header.
      headers:
        Retry-After:
          schema:
            type: integer
          description: Seconds until the current rate-limit window resets.
        RateLimit-Limit:
          schema:
            type: integer
          description: Requests permitted in the rate-limit window.
        RateLimit-Remaining:
          schema:
            type: integer
          description: Requests remaining in the current window.
        RateLimit-Reset:
          schema:
            type: integer
          description: Seconds until the current rate-limit window resets.
      content:
        application/json:
          schema:
            $ref: '#/components/schemas/Error'
  schemas:
    Measurement:
      type: object
      required:
        - temperature
        - datetime
      properties:
        temperature:
          type: number
          description: The water temperature.
        datetime:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$'
          example: '2026-04-29T10:15:00'
          description: The timestamp of the measurement as Germany local time (Europe/Berlin), matching the NID Bayern source table.
    Forecast:
      type: object
      required:
        - base_time
        - lake_temp_now
        - generated_at
        - forecast
      properties:
        base_time:
          type: string
          pattern: '^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}$'
          example: '2026-05-31T11:00:00'
          description: Europe/Berlin wall-clock hour of the latest observation used as the forecast base. This is offsetless and is not a UTC instant.
        lake_temp_now:
          type: number
          example: 18.4
          description: The measured lake temperature at the forecast base time.
        generated_at:
          type: string
          format: date-time
          example: '2026-05-31T10:38:44Z'
          description: The timestamp when the prediction was generated.
        forecast:
          type: array
          description: Hourly prediction points, typically horizons 1 through 12.
          items:
            $ref: '#/components/schemas/ForecastPoint'
        mean_skill_pct:
          type: number
          example: 36.0
          description: Mean model skill as percent MAE reduction versus persistence, when provided.
        model:
          type: string
          example: LightGBM (L1 central + CQR quantiles) on temperature deltas
          description: Human-readable model description, when provided.
    ForecastPoint:
      type: object
      required:
        - h
        - time
        - temp
        - p5
        - p95
        - p25
        - p75
      properties:
        h:
          type: integer
          minimum: 1
          maximum: 12
          example: 1
          description: Forecast horizon in hours after base_time.
        time:
          type: string
          pattern: '^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}$'
          example: '2026-05-31T12:00:00'
          description: Predicted point timestamp as an offsetless Europe/Berlin wall-clock string, matching measurement timestamps.
        temp:
          type: number
          example: 18.7
          description: The central predicted water temperature in Celsius.
        p5:
          type: number
          example: 18.4
          description: Lower bound of the 90 percent prediction interval in Celsius.
        p95:
          type: number
          example: 19.0
          description: Upper bound of the 90 percent prediction interval in Celsius.
        p25:
          type: number
          example: 18.6
          description: Lower bound of the 50 percent prediction interval in Celsius.
        p75:
          type: number
          example: 18.8
          description: Upper bound of the 50 percent prediction interval in Celsius.
    Error:
      type: object
      required:
        - error
      properties:
        error:
          type: string
          description: The error message.
