openapi: 3.1.0
info:
  title: Forest OS Public and Client Spectral API
  version: 1.4.0
  description: Public H3 r7 and authorized client time-series contract for eleven published spectral indices.
servers:
  - url: https://forestosglobal.com
tags:
  - name: Public
  - name: Client
x-public-indices:
  - ndvi
  - evi
  - nbr
  - ndwi
  - lai
  - dnbr
  - fapar
  - ndmi
  - cci
  - bais2
  - sipi
paths:
  /api/public/summary:
    get:
      tags: [Public]
      summary: Public platform and spectral registry summary
      responses:
        '200':
          description: Public summary with the v1.4 spectral registry.
          content:
            application/json:
              schema:
                type: object
                properties:
                  ok: {type: boolean}
                  spectral_indices:
                    $ref: '#/components/schemas/SpectralRegistry'
  /api/public/h3-cell:
    get:
      tags: [Public]
      summary: Read one public H3 r7 cell for at most twelve months
      parameters:
        - $ref: '#/components/parameters/H3Cell'
        - $ref: '#/components/parameters/StartMonth'
        - $ref: '#/components/parameters/EndMonth'
        - $ref: '#/components/parameters/PublicVariables'
      responses:
        '200':
          $ref: '#/components/responses/TimeSeries'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotAvailable'
        '503':
          $ref: '#/components/responses/Unavailable'
  /api/public/h3-at-point:
    get:
      tags: [Public]
      summary: Resolve a coordinate to H3 r7 and return public time series
      parameters:
        - name: lat
          in: query
          required: true
          schema: {type: number, minimum: -90, maximum: 90}
        - name: lon
          in: query
          required: true
          schema: {type: number, minimum: -180, maximum: 180}
        - $ref: '#/components/parameters/StartMonth'
        - $ref: '#/components/parameters/EndMonth'
        - $ref: '#/components/parameters/PublicVariables'
      responses:
        '200':
          $ref: '#/components/responses/TimeSeries'
        '400':
          $ref: '#/components/responses/BadRequest'
        '404':
          $ref: '#/components/responses/NotAvailable'
        '503':
          $ref: '#/components/responses/Unavailable'
  /api/client/timeseries:
    get:
      tags: [Client]
      summary: Authorized time series for a client-owned plot
      security:
        - ClientApiKey: []
      parameters:
        - name: plot_id
          in: query
          required: true
          schema: {type: integer, minimum: 1}
        - name: months
          in: query
          schema: {type: integer, minimum: 6, maximum: 24, default: 12}
        - $ref: '#/components/parameters/PublicVariables'
      responses:
        '200':
          $ref: '#/components/responses/TimeSeries'
        '401':
          description: Missing or invalid client API key.
        '404':
          $ref: '#/components/responses/NotAvailable'
        '503':
          $ref: '#/components/responses/Unavailable'
components:
  securitySchemes:
    ClientApiKey:
      type: http
      scheme: bearer
      bearerFormat: fos_lk_*
  parameters:
    H3Cell:
      name: h3
      in: query
      required: true
      description: H3 resolution 7 cell.
      schema: {type: string, pattern: '^[0-9a-f]{15}$'}
    StartMonth:
      name: start
      in: query
      schema: {type: string, pattern: '^\\d{4}-(0[1-9]|1[0-2])$'}
    EndMonth:
      name: end
      in: query
      schema: {type: string, pattern: '^\\d{4}-(0[1-9]|1[0-2])$'}
    PublicVariables:
      name: var
      in: query
      description: Comma-separated public variables. Published indices are ndvi,evi,nbr,ndwi,lai,dnbr,fapar,ndmi,cci,bais2,sipi; actual H3 availability is reported by the registry.
      schema:
        type: string
        example: ndvi,ndwi,lai
  schemas:
    SpectralRegistry:
      type: object
      required: [version, index_count, new_index_count, groups, indices]
      properties:
        version: {type: string, const: '1.4'}
        index_count: {type: integer, const: 11}
        new_index_count: {type: integer, const: 8}
        groups: {type: object, additionalProperties: {type: array, items: {type: string}}}
        indices:
          type: object
          additionalProperties:
            $ref: '#/components/schemas/SpectralIndex'
    SpectralIndex:
      type: object
      properties:
        name: {type: string}
        title: {type: string}
        group: {type: string}
        formula: {type: string}
        status: {type: string, enum: [ready_to_materialize, aoi_only]}
        available_in_canonical_cube: {type: boolean}
        public_ready: {type: boolean}
    Error:
      type: object
      required: [ok, error]
      properties:
        ok: {type: boolean, const: false}
        error: {type: string}
        message: {type: string}
        variables: {type: array, items: {type: string}}
  responses:
    TimeSeries:
      description: Time series. Missing observations remain null and are never replaced with zero.
      content:
        application/json:
          schema:
            type: object
            additionalProperties: true
    BadRequest:
      description: Invalid coordinates, range, H3 cell, or unsupported public variable.
      content:
        application/json:
          schema: {$ref: '#/components/schemas/Error'}
    NotAvailable:
      description: Requested plot or variable is not available in this access contour.
      content:
        application/json:
          schema: {$ref: '#/components/schemas/Error'}
    Unavailable:
      description: Canonical cube or analytics service is temporarily unavailable.
      content:
        application/json:
          schema: {$ref: '#/components/schemas/Error'}
