openapi: 3.1.0
info:
  title: Terminal Weather API Preview
  version: 0.1.0-preview
  summary: Proposed aerodrome weather observation and evidence contract
  description: |
    This is a non-production contract published for the Terminal Weather Services
    private technical preview. The customer API is not generally available. Paths,
    fields, authentication, retention, limits and commercial data rights may change
    before access is offered.

    The contract is intended for non-safety-critical analytics, observability and
    infrastructure evaluation. It must not be relied on for aircraft navigation,
    communication, control or operational meteorological briefing.
  contact:
    name: Pilot evaluations
    email: pilot@terminalweather.com
  license:
    name: Preview terms
    url: https://terminalweather.com/terms/
externalDocs:
  description: Methodology and data provenance
  url: https://terminalweather.com/methodology/
servers:
  - url: https://api.terminalweather.com
    description: Planned customer host; credentials and production access are not offered
tags:
  - name: Stations
    description: Planned station-first observation resources
  - name: Events
    description: Planned integrity and report-condition event stream
  - name: Webhooks
    description: Proposed webhook destination management
security:
  - bearerAuth: []
paths:
  /v1/stations/{icao}/latest:
    get:
      operationId: getLatestStationObservation
      tags: [Stations]
      summary: Get the latest normalized station observation with source evidence
      description: Planned route. It is documented for contract evaluation and is not generally available.
      parameters:
        - $ref: '#/components/parameters/Icao'
      responses:
        '200':
          description: Current normalized observation and all available representations
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/LatestObservation'
              examples:
                aligned:
                  summary: Three paths aligned on nominal time and canonical content
                  externalValue: https://terminalweather.com/developers/examples/latest-observation.json
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
        '503':
          $ref: '#/components/responses/Unavailable'
  /v1/stations/{icao}/observations:
    get:
      operationId: listStationObservations
      tags: [Stations]
      summary: List retained observations and revisions for a station
      description: |
        Planned route. Historical availability and retention will depend on upstream
        licences and commercial terms agreed before release.
      parameters:
        - $ref: '#/components/parameters/Icao'
        - $ref: '#/components/parameters/Cursor'
        - name: limit
          in: query
          schema:
            type: integer
            minimum: 1
            maximum: 250
            default: 50
          description: Preview proposal only; no production limit is committed.
      responses:
        '200':
          description: Cursor-based collection of observations and their revisions
          content:
            application/json:
              schema:
                type: object
                required: [object, data, next_cursor]
                properties:
                  object:
                    const: aerodrome_observation_collection
                  data:
                    type: array
                    items:
                      $ref: '#/components/schemas/LatestObservation'
                  next_cursor:
                    type: [string, 'null']
              examples:
                correctionChain:
                  summary: Illustrative correction chain
                  externalValue: https://terminalweather.com/developers/examples/correction-chain.json
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/events:
    get:
      operationId: listStationEvents
      tags: [Events]
      summary: List integrity and report-condition events
      description: Planned cursor-based event route; the public preview does not claim a retained event history.
      parameters:
        - $ref: '#/components/parameters/Cursor'
        - name: station
          in: query
          schema:
            type: string
            pattern: '^[A-Z]{4}$'
        - name: type
          in: query
          schema:
            type: string
      responses:
        '200':
          description: Proposed station event collection
          content:
            application/json:
              schema:
                type: object
                required: [object, data, next_cursor]
                properties:
                  object:
                    const: station_event_collection
                  data:
                    type: array
                    items:
                      $ref: 'https://terminalweather.com/developers/schemas/station-event.schema.json'
                  next_cursor:
                    type: [string, 'null']
              examples:
                sourceLag:
                  summary: One path remains on an older nominal observation
                  externalValue: https://terminalweather.com/developers/examples/source-lag-event.json
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
  /v1/webhook-endpoints:
    post:
      operationId: createWebhookEndpoint
      tags: [Webhooks]
      summary: Register a proposed HTTPS event destination
      description: |
        Planned only. Final signature headers, key rotation, retry semantics and
        endpoint limits have not been committed. The proposal uses stable delivery
        and event identifiers for receiver-side idempotency.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              type: object
              additionalProperties: false
              required: [url, event_types]
              properties:
                url:
                  type: string
                  format: uri
                  pattern: '^https://'
                event_types:
                  type: array
                  minItems: 1
                  uniqueItems: true
                  items:
                    type: string
                stations:
                  type: array
                  uniqueItems: true
                  items:
                    type: string
                    pattern: '^[A-Z]{4}$'
      responses:
        '201':
          description: Proposed endpoint object
          content:
            application/json:
              schema:
                type: object
                required: [id, object, status, created_at]
                properties:
                  id:
                    type: string
                  object:
                    const: webhook_endpoint
                  status:
                    enum: [pending-verification]
                  created_at:
                    type: string
                    format: date-time
        '400':
          $ref: '#/components/responses/BadRequest'
        '401':
          $ref: '#/components/responses/Unauthorized'
components:
  securitySchemes:
    bearerAuth:
      type: http
      scheme: bearer
      bearerFormat: preview-token
      description: Planned authentication model; tokens are not being issued generally.
  parameters:
    Icao:
      name: icao
      in: path
      required: true
      description: Uppercase four-letter ICAO location indicator
      schema:
        type: string
        pattern: '^[A-Z]{4}$'
        example: LEMD
    Cursor:
      name: cursor
      in: query
      description: Opaque continuation cursor proposed for ordered collections
      schema:
        type: string
  schemas:
    LatestObservation:
      type: object
      additionalProperties: false
      required: [object, schema, availability, station, observation, integrity, representations, source_paths]
      properties:
        object:
          const: aerodrome_observation
        schema:
          type: string
          example: terminal-weather.observation.preview.v1
        availability:
          const: not-generally-available
        station:
          $ref: '#/components/schemas/Station'
        observation:
          $ref: '#/components/schemas/Observation'
        integrity:
          $ref: '#/components/schemas/Integrity'
        representations:
          type: array
          items:
            $ref: '#/components/schemas/Representation'
        source_paths:
          type: array
          items:
            $ref: '#/components/schemas/SourcePath'
    Station:
      type: object
      additionalProperties: false
      required: [icao]
      properties:
        icao:
          type: string
          pattern: '^[A-Z]{4}$'
        name:
          type: [string, 'null']
        country:
          type: [string, 'null']
    Observation:
      type: object
      additionalProperties: false
      required: [observed_at, observed_at_basis, report_kind, flags, canonical_variants]
      properties:
        observed_at:
          type: [string, 'null']
          format: date-time
        observed_at_basis:
          type: [string, 'null']
        report_kind:
          type: [string, 'null']
          enum: [METAR, SPECI, null]
        flags:
          type: object
          required: [automatic, correction, nil]
          properties:
            automatic: { type: [boolean, 'null'] }
            correction: { type: [boolean, 'null'] }
            nil: { type: [boolean, 'null'] }
        canonical_variants:
          type: array
          items:
            type: object
            required: [canonical_tac, source_path_ids]
            properties:
              canonical_tac: { type: string }
              source_path_ids:
                type: array
                items: { type: string }
    Integrity:
      type: object
      additionalProperties: false
      required: [state, summary, available_path_count, expected_path_count, missing_path_ids, lagging_path_ids, observation_time_aligned, canonical_content_aligned, variant_count]
      properties:
        state:
          enum: [aligned, content-difference, source-lag, incomplete]
        summary: { type: string }
        available_path_count: { type: integer, minimum: 0 }
        expected_path_count: { type: integer, minimum: 1 }
        missing_path_ids:
          type: array
          items: { type: string }
        lagging_path_ids:
          type: array
          items: { type: string }
        observation_time_aligned: { type: [boolean, 'null'] }
        canonical_content_aligned: { type: [boolean, 'null'] }
        variant_count: { type: integer, minimum: 0 }
    Representation:
      type: object
      additionalProperties: false
      required: [source_path, available, observed_at, report_kind, raw_tac, fingerprint]
      properties:
        source_path: { type: string }
        available: { type: boolean }
        observed_at: { type: [string, 'null'], format: date-time }
        report_kind: { type: [string, 'null'] }
        raw_tac: { type: [string, 'null'] }
        fingerprint:
          type: object
          required: [algorithm, value]
          properties:
            algorithm: { const: SHA-256 }
            value:
              type: [string, 'null']
              pattern: '^[a-f0-9]{64}$'
    SourcePath:
      type: object
      additionalProperties: true
      required: [id, name, timestamp_classification, timestamps]
      properties:
        id: { type: string }
        name: { type: [string, 'null'] }
        organisation: { type: [string, 'null'] }
        timestamp_classification: { type: [string, 'null'] }
        timestamps:
          type: object
          required: [observation, source, terminal_weather]
          properties:
            observation: { type: [string, 'null'], format: date-time }
            source: { type: [string, 'null'], format: date-time }
            terminal_weather: { type: [string, 'null'], format: date-time }
    Error:
      type: object
      additionalProperties: false
      required: [error]
      properties:
        error:
          type: object
          additionalProperties: false
          required: [code, message, request_id]
          properties:
            code: { type: string }
            message: { type: string }
            request_id: { type: string }
  responses:
    BadRequest:
      description: Invalid route or query input
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unauthorized:
      description: Missing or invalid planned bearer credential
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    NotFound:
      description: Station or observation not found
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
    Unavailable:
      description: Required preview data is temporarily unavailable
      content:
        application/json:
          schema: { $ref: '#/components/schemas/Error' }
x-terminal-weather-stage: private-technical-preview
x-terminal-weather-availability: not-generally-available
