openapi: 3.1.0
info:
  title: Solar Gate Energy API
  version: 2026-07-31
  description: >-
    Read-only, vendor-neutral APIs for energy connectors, sites, devices,
    telemetry, billing evidence, invoices, portfolio health, alarms and
    interval summaries. Access is controlled by scoped API keys and explicit
    project grants.
servers:
  - url: https://{projectRef}.supabase.co/functions/v1
    description: Solar Gate Supabase Edge Functions
    variables:
      projectRef:
        default: uqkbxztsnvaajqsecsrw
        description: Supabase project reference for the deployed environment
security:
  - SolarGateApiKey: []
  - BearerApiKey: []
tags:
  - name: Core
  - name: Insights
paths:
  /energy-developer-api/v1/connectors:
    get:
      tags: [Core]
      summary: List connector catalog
      operationId: listConnectors
      responses:
        '200':
          description: Connector catalog visible to the API plan
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-developer-api/v1/sites:
    get:
      tags: [Core]
      summary: List granted energy sites
      operationId: listSites
      parameters:
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Projects explicitly granted to the API client
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-developer-api/v1/sites/{site_id}/devices:
    get:
      tags: [Core]
      summary: List normalized devices at a granted site
      operationId: listSiteDevices
      parameters:
        - $ref: '#/components/parameters/SiteId'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Devices belonging to the granted site
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-developer-api/v1/devices/{device_id}/points:
    get:
      tags: [Core]
      summary: List normalized points for a granted device
      operationId: listDevicePoints
      parameters:
        - name: device_id
          in: path
          required: true
          schema: { type: string, format: uuid }
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Active points for the device
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-developer-api/v1/points/{point_id}/samples:
    get:
      tags: [Core]
      summary: Read point telemetry within the plan history limit
      operationId: listPointSamples
      parameters:
        - name: point_id
          in: path
          required: true
          schema: { type: string, format: uuid }
        - $ref: '#/components/parameters/From'
        - $ref: '#/components/parameters/To'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Timestamped samples
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-developer-api/v1/sites/{site_id}/billing-evidence:
    get:
      tags: [Core]
      summary: Read normalized commercial billing evidence
      operationId: listBillingEvidence
      parameters:
        - $ref: '#/components/parameters/SiteId'
        - $ref: '#/components/parameters/From'
        - $ref: '#/components/parameters/To'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Granted energy, demand, availability, runtime, savings or water evidence
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-developer-api/v1/sites/{site_id}/invoices:
    get:
      tags: [Core]
      summary: Read site energy invoices
      operationId: listEnergyInvoices
      parameters:
        - $ref: '#/components/parameters/SiteId'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Energy invoice records allowed by the API plan and project grant
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-insights-api/v1/portfolio/summary:
    get:
      tags: [Insights]
      summary: Summarize health across granted sites
      operationId: getPortfolioSummary
      responses:
        '200':
          description: Site, connector, device and alarm counts
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponse'
        '401': { $ref: '#/components/responses/Unauthorized' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-insights-api/v1/sites/{site_id}/latest:
    get:
      tags: [Insights]
      summary: Return the newest sample for every active point
      operationId: getLatestSiteSnapshot
      parameters:
        - $ref: '#/components/parameters/SiteId'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Latest point values with device and connector context
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-insights-api/v1/sites/{site_id}/alarms:
    get:
      tags: [Insights]
      summary: Read site alarms
      operationId: listSiteAlarms
      parameters:
        - $ref: '#/components/parameters/SiteId'
        - $ref: '#/components/parameters/From'
        - $ref: '#/components/parameters/To'
        - $ref: '#/components/parameters/Limit'
        - name: severity
          in: query
          schema:
            type: string
            enum: [info, warning, critical]
        - name: state
          in: query
          schema:
            type: string
            enum: [open, cleared, all]
            default: open
      responses:
        '200':
          description: Filtered site alarm events
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ListResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '429': { $ref: '#/components/responses/RateLimited' }
  /energy-insights-api/v1/sites/{site_id}/energy-summary:
    get:
      tags: [Insights]
      summary: Calculate safe per-point interval statistics and cumulative deltas
      operationId: getSiteEnergySummary
      parameters:
        - $ref: '#/components/parameters/SiteId'
        - $ref: '#/components/parameters/From'
        - $ref: '#/components/parameters/To'
        - $ref: '#/components/parameters/Limit'
      responses:
        '200':
          description: Per-point statistics without unsafe automatic summation of overlapping meters
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ObjectResponse'
        '403': { $ref: '#/components/responses/Forbidden' }
        '422':
          description: Invalid time range
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ErrorResponse'
        '429': { $ref: '#/components/responses/RateLimited' }
components:
  securitySchemes:
    SolarGateApiKey:
      type: apiKey
      in: header
      name: X-Solar-Gate-Key
    BearerApiKey:
      type: http
      scheme: bearer
  parameters:
    SiteId:
      name: site_id
      in: path
      required: true
      schema: { type: string, format: uuid }
    From:
      name: from
      in: query
      required: false
      description: ISO 8601 timestamp clamped to the plan history limit
      schema: { type: string, format: date-time }
    To:
      name: to
      in: query
      required: false
      description: ISO 8601 timestamp not later than the current time
      schema: { type: string, format: date-time }
    Limit:
      name: limit
      in: query
      required: false
      schema:
        type: integer
        minimum: 1
        maximum: 1000
  responses:
    Unauthorized:
      description: Missing, invalid, expired or revoked API key
      content:
        application/json:
          schema: { $ref: '#/components/schemas/ErrorResponse' }
    Forbidden:
      description: API scope or project grant denied
      content:
        application/json:
          schema: { $ref: '#/components/schemas/ErrorResponse' }
    RateLimited:
      description: Client plan quota exceeded
      headers:
        X-RateLimit-Limit-Minute:
          schema: { type: string }
        X-RateLimit-Remaining-Minute:
          schema: { type: string }
        X-RateLimit-Limit-Day:
          schema: { type: string }
        X-RateLimit-Remaining-Day:
          schema: { type: string }
        X-RateLimit-Limit-Month:
          schema: { type: string }
        X-RateLimit-Remaining-Month:
          schema: { type: string }
      content:
        application/json:
          schema: { $ref: '#/components/schemas/ErrorResponse' }
  schemas:
    ListResponse:
      type: object
      required: [data, request_id]
      properties:
        data:
          type: array
          items: {}
        meta:
          type: object
          additionalProperties: true
        request_id:
          type: string
          format: uuid
    ObjectResponse:
      type: object
      required: [data, request_id]
      properties:
        data:
          type: object
          additionalProperties: true
        meta:
          type: object
          additionalProperties: true
        request_id:
          type: string
          format: uuid
    ErrorResponse:
      type: object
      required: [error, request_id]
      properties:
        error:
          type: object
          required: [code, message]
          properties:
            code: { type: string }
            message: { type: string }
        request_id:
          type: string
