# Proposed contract, version 1: endpoints, errors, paging, idempotency, security and the capability of every
# operation. Resource schemas were initialized from the data model (docs/06-data) and are kept aligned with it; input
# schemas (*Input, *Request) and views are specific to this contract. Status: proposal for review, not confirmed design.
# Conventions: docs/05-interfaces/choosing-an-interface.md. Vendor extensions: x-moonitoring-audience (who calls),
# x-moonitoring-capability (the capability checked), x-moonitoring-entitlement (the entitlement feature checked),
# x-moonitoring-requirements (the requirements of 1.requisiti-raffinati.txt the operation serves).
openapi: 3.1.0
info:
  title: Farm Sources API
  version: 1.0.0
  description: 'Where farm data comes from: the origins that produce values and the channels that deliver them (global
    catalogs maintained by staff, plus an Organization''s own), each farm''s feeds with their coverage, and the
    devices installed at the farm. Organization users connect their feeds and devices; staff maintain the catalogs
    and see every feed.'
servers:
- url: https://farm.moonitoring.com/sources/v1
  description: Prod
- url: https://stage-farm.moonitoring.com/sources/v1
  description: Stage, through IAP
security:
- bearer: []
tags:
- name: Feeds
  description: One farm's data through one channel
- name: Devices
  description: Physical devices at the farm
- name: Channels
  description: How values reach us
- name: Origins
  description: Who or what produces values
- name: Producers
  description: Lineage of a record
- name: Adapters
  description: Readers of each source, by version
- name: Integration gaps
  description: What we cannot read yet
paths:
  /organizations/{organization_id}/feeds:
    get:
      summary: List a farm's feeds
      operationId: listOrganizationFeeds
      tags:
      - Feeds
      parameters:
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Organization.
      - name: include_disconnected
        in: query
        required: false
        schema:
          type: boolean
      - name: sync_client
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only feeds read by this client.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/SourceFeed'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability:
      - farm.ingestion.read
      - farm.ingestion.read_all
      x-moonitoring-requirements:
      - '44'
      - '1002.17'
      - '1006.20'
    post:
      summary: Connect a feed
      operationId: createFeed
      description: 'Publishes `source_feed.connected.v1`. (farm, source_channel, name) must be unique. Called by
        the farm sync client with the token of the signed-in person when they set up an integration, with `sync_client`
        set to the client; the sign-in must be at most five minutes old, otherwise 403 reauthentication-required.'
      tags:
      - Feeds
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Organization.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceFeedInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceFeed'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '44'
      - '44.5'
      - '44.8'
      - '1002.16'
  /feeds:
    get:
      summary: List every feed
      operationId: listFeeds
      tags:
      - Feeds
      parameters:
      - name: farm
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only this farm.
      - name: channel
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only this channel.
      - name: silent
        in: query
        required: false
        schema:
          type: boolean
        description: Only feeds whose schedule passed with no SyncRun at all.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/SourceFeed'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.ingestion.read_all
      x-moonitoring-requirements:
      - '44'
      - '1006.20'
  /feeds/{feed_id}:
    get:
      summary: Read a feed
      operationId: getFeed
      tags:
      - Feeds
      parameters:
      - name: feed_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The SourceFeed.
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceFeed'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability:
      - farm.ingestion.read
      - farm.ingestion.read_all
      x-moonitoring-requirements:
      - '44'
    patch:
      summary: Update a feed
      operationId: updateFeed
      description: '`farm.sources.manage` is an admin capability: a person''s sign-in must be at most five minutes old,
        otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Feeds
      parameters:
      - name: feed_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The SourceFeed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceFeedUpdate'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceFeed'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '44.4'
      - '44.6'
      - '44.7'
      - '44.9'
      - '1002.16'
  /feeds/{feed_id}/disconnect:
    post:
      summary: Disconnect a feed
      operationId: disconnectFeed
      description: 'Closes the feed''s validity; its data stays. Publishes `source_feed.disconnected.v1`.
        `farm.sources.manage` is an admin capability: a person''s sign-in must be at most five minutes old,
        otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Feeds
      parameters:
      - name: feed_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The SourceFeed.
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClosePeriodRequest'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceFeed'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '44.5'
      - '1002.16'
  /feeds/{feed_id}/credential:
    put:
      summary: Set a feed's vendor credential
      operationId: setFeedCredential
      description: 'Only for feeds on a third-party platform that our vendor puller calls. The secret goes to Secret Manager
        and is never returned. Never for software the sync client reads on the farm; those credentials stay on
        the computer. `farm.sources.manage` is an admin capability: a person''s sign-in must be at most five
        minutes old, otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Feeds
      parameters:
      - name: feed_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The SourceFeed.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/FeedCredentialInput'
      responses:
        '204':
          description: Done.
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '44'
      - 32.*.3
      - '1002.16'
  /feeds/{feed_id}/coverage:
    get:
      summary: Read a feed's coverage
      operationId: listFeedCoverage
      description: 'Per kind of data: from when data is present, until when it is complete and until when the source
        no longer changes it. Recomputed after every sync.'
      tags:
      - Feeds
      parameters:
      - name: feed_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The SourceFeed.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/AsOfSeq
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/FeedCoverage'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability:
      - farm.ingestion.read
      - farm.ingestion.read_all
      x-moonitoring-requirements:
      - '66'
  /organizations/{organization_id}/devices:
    get:
      summary: List a farm's devices
      operationId: listDevices
      tags:
      - Devices
      parameters:
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Organization.
      - name: include_removed
        in: query
        required: false
        schema:
          type: boolean
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/Device'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability:
      - farm.ingestion.read
      - farm.ingestion.read_all
      x-moonitoring-requirements:
      - '33'
      - '1002.17'
    post:
      summary: Register a device
      operationId: createDevice
      description: '`farm.sources.manage` is an admin capability: a person''s sign-in must be at most five minutes old,
        otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Devices
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Organization.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeviceInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Device'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '33'
      - '1002.16'
  /devices/{device_id}:
    get:
      summary: Read a device
      operationId: getDevice
      tags:
      - Devices
      parameters:
      - name: device_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Device'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability:
      - farm.ingestion.read
      - farm.ingestion.read_all
      x-moonitoring-requirements:
      - '33'
    patch:
      summary: Update a device
      operationId: updateDevice
      description: 'Firmware is the current inventory value only; historical observations keep their own origin version.
        `farm.sources.manage` is an admin capability: a person''s sign-in must be at most five minutes old,
        otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Devices
      parameters:
      - name: device_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeviceInput'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/Device'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '33.4'
      - '33.5'
      - '33.6'
      - '33.7'
      - '1002.16'
  /devices/{device_id}/assignments:
    get:
      summary: List who wore a device
      operationId: listDeviceAssignments
      tags:
      - Devices
      parameters:
      - name: device_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/AsOfSeq
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/DeviceAssignment'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability:
      - farm.ingestion.read
      - farm.ingestion.read_all
      x-moonitoring-requirements:
      - '34'
    post:
      summary: Assign a device to an animal
      operationId: createDeviceAssignment
      description: 'Periods of the same device must not overlap: the previous assignment is closed at the new start.
        `farm.sources.manage` is an admin capability: a person''s sign-in must be at most five minutes old,
        otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Devices
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: device_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/DeviceAssignmentInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceAssignment'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '34'
      - '1002.16'
  /device-assignments/{assignment_id}/close:
    post:
      summary: End a device assignment
      operationId: closeDeviceAssignment
      description: '`farm.sources.manage` is an admin capability: a person''s sign-in must be at most five minutes old,
        otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Devices
      parameters:
      - name: assignment_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: false
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/ClosePeriodRequest'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/DeviceAssignment'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '34.4'
      - '1002.16'
  /channels:
    get:
      summary: List channels
      operationId: listChannels
      description: Global channels and, for an Organization user, the Organization's own.
      tags:
      - Channels
      parameters:
      - name: type
        in: query
        required: false
        schema:
          type: string
          enum:
          - DirectDeviceChannel
          - ManagementSoftwareChannel
          - ThirdPartyPlatformChannel
          - MoonitoringAppChannel
          - FileChannel
        description: Only this kind.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/SourceChannel'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: any
      x-moonitoring-capability: null
      x-moonitoring-requirements:
      - '32'
    post:
      summary: Create a global channel
      operationId: createChannel
      tags:
      - Channels
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceChannelInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceChannel'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.source_origins.manage
      x-moonitoring-requirements:
      - '32'
      - '1006.18'
  /organizations/{organization_id}/channels:
    post:
      summary: Create an Organization's channel
      operationId: createOrganizationChannel
      description: '`farm.sources.manage` is an admin capability: a person''s sign-in must be at most five minutes old,
        otherwise 403 with the problem type reauthentication-required.'
      tags:
      - Channels
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Organization.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceChannelInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceChannel'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '32.3'
      - '1002.16'
  /channels/{channel_id}/versions:
    get:
      summary: List a channel's versions
      operationId: listChannelVersions
      tags:
      - Channels
      parameters:
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/ChannelVersion'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability: null
      x-moonitoring-requirements:
      - '18'
      - 18.*.2
    post:
      summary: Register a channel version
      operationId: createChannelVersion
      tags:
      - Channels
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: channel_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceVersionInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ChannelVersion'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.source_origins.manage
      x-moonitoring-requirements:
      - '18'
      - 18.*.2
      - '1006.18'
  /origins:
    get:
      summary: List origins
      operationId: listOrigins
      tags:
      - Origins
      parameters:
      - name: type
        in: query
        required: false
        schema:
          type: string
          enum:
          - SensorSourceOrigin
          - OperatorSourceOrigin
          - LabSourceOrigin
          - ComputedSourceOrigin
          - UnknownSourceOrigin
        description: Only this kind.
      - name: vendor
        in: query
        required: false
        schema:
          type: string
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/AsOfSeq
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/SourceOrigin'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: any
      x-moonitoring-capability: null
      x-moonitoring-requirements:
      - '19'
    post:
      summary: Create a global origin
      operationId: createOrigin
      tags:
      - Origins
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceOriginInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceOrigin'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.source_origins.manage
      x-moonitoring-requirements:
      - '19'
      - '19.5'
      - '1006.18'
  /organizations/{organization_id}/origins:
    post:
      summary: Create an Organization's origin
      operationId: createOrganizationOrigin
      description: 'For example a specific operator or an in-house lab of the Organization. `farm.sources.manage` is an
        admin capability: a person''s sign-in must be at most five minutes old, otherwise 403 with the problem
        type reauthentication-required.'
      tags:
      - Origins
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: organization_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
        description: The Organization.
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceOriginInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceOrigin'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: organization
      x-moonitoring-capability: farm.sources.manage
      x-moonitoring-requirements:
      - '19.3'
      - '1002.16'
  /origins/{origin_id}:
    patch:
      summary: Update an origin
      operationId: updateOrigin
      description: A change of assurance keeps the previous image, so data read at an earlier write number keeps
        the assurance known then.
      tags:
      - Origins
      parameters:
      - name: origin_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceOriginInput'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceOrigin'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.source_origins.manage
      x-moonitoring-requirements:
      - '19.4'
      - '19.5'
      - '19.6'
      - '1006.18'
  /origins/{origin_id}/versions:
    get:
      summary: List an origin's versions
      operationId: listOriginVersions
      tags:
      - Origins
      parameters:
      - name: origin_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/OriginVersion'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability: null
      x-moonitoring-requirements:
      - '18'
      - 18.*.1
    post:
      summary: Register an origin version
      operationId: createOriginVersion
      tags:
      - Origins
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      - name: origin_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceVersionInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/OriginVersion'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.source_origins.manage
      x-moonitoring-requirements:
      - '18'
      - 18.*.1
      - '1006.18'
  /producers/{producer_id}:
    get:
      summary: Read a producer's lineage
      operationId: getProducer
      description: Resolves the source_producer of a canonical record to who produced it, through which channel,
        from which versions.
      tags:
      - Producers
      parameters:
      - name: producer_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/ProducerLineage'
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: any
      x-moonitoring-capability:
      - farm.ingestion.read
      - farm.ingestion.read_all
      x-moonitoring-requirements:
      - '17'
      - '18'
      - '19'
      - '32'
      - '44'
  /source-adapters:
    get:
      summary: List source adapters
      operationId: listSourceAdapters
      description: The readers of every source and the version ranges they cover.
      tags:
      - Adapters
      parameters:
      - name: side
        in: query
        required: false
        schema:
          type: string
          enum:
          - client
          - parser
          - puller
        description: Only one side.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/SourceAdapter'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.ingestion.read_all
      x-moonitoring-requirements:
      - '135'
    post:
      summary: Register a source adapter
      operationId: createSourceAdapter
      description: Called when a client or parser release ships a new adapter; refused when its range overlaps an active adapter of the same channel and side.
      tags:
      - Adapters
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceAdapterInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceAdapter'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.source_adapters.manage
      x-moonitoring-requirements:
      - '135'
      - '1006.42'
  /source-adapters/{adapter_id}/status:
    post:
      summary: Deprecate or withdraw a source adapter
      operationId: setSourceAdapterStatus
      tags:
      - Adapters
      parameters:
      - name: adapter_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/SourceAdapterStatusInput'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/SourceAdapter'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.source_adapters.manage
      x-moonitoring-requirements:
      - '135.8'
      - '1006.42'
  /adapter-mappings:
    get:
      summary: List adapter mappings
      operationId: listAdapterMappings
      description: Which adapter reads which detected version, by product, scope and side.
      tags:
      - Adapters
      parameters:
      - name: side
        in: query
        required: false
        schema:
          type: string
          enum:
          - client
          - parser
          - puller
        description: Only one side.
      - name: source_channel
        in: query
        required: false
        schema:
          type: string
          format: uuid
        description: Only mappings of this product.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/AdapterMapping'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.ingestion.read_all
      x-moonitoring-requirements:
      - '146'
    post:
      summary: Map a detected version to an adapter
      operationId: createAdapterMapping
      description: Maps one detected version or a range to an existing adapter of the same product and side, for everyone, one Organization or one feed. Refused when its range overlaps an active mapping of the same side, product and scope. A mapping of side `puller` must name a ThirdPartyPlatformChannel, the only kind of channel a puller reads, and answers 422 otherwise (decided 2026-11-11). Clients receive it with their next configuration.
      tags:
      - Adapters
      parameters:
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/IdempotencyKey
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/AdapterMappingInput'
      responses:
        '201':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdapterMapping'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.adapter_mappings.manage
      x-moonitoring-requirements:
      - '146'
      - '1006.44'
  /adapter-mappings/{mapping_id}/retire:
    post:
      summary: Retire an adapter mapping
      operationId: retireAdapterMapping
      description: The versions it covered fall back to a less specific mapping, or to none, which records an integration gap at the next run.
      tags:
      - Adapters
      parameters:
      - name: mapping_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdapterMapping'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.adapter_mappings.manage
      x-moonitoring-requirements:
      - '146.9'
      - '1006.44'
  /adapter-mappings/resolve:
    get:
      summary: Resolve the adapter for a detection
      operationId: resolveAdapterMapping
      description: 'Which mapping wins for a product, a detected version and a feed: the most specific active one, feed before Organization before global. The Console uses it before and after a change.'
      tags:
      - Adapters
      parameters:
      - name: side
        in: query
        required: false
        schema:
          type: string
          enum:
          - client
          - parser
          - puller
        description: Only one side.
      - name: source_channel
        in: query
        required: true
        schema:
          type: string
          format: uuid
      - name: version
        in: query
        required: true
        schema:
          type: string
        description: The detected version, as the source names it.
      - name: source_feed
        in: query
        required: false
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/AdapterResolution'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.ingestion.read_all
      x-moonitoring-requirements:
      - '146'
  /integration-gaps:
    get:
      summary: List integration gaps
      operationId: listIntegrationGaps
      description: What we cannot read yet, ordered by the number of farms affected.
      tags:
      - Integration gaps
      parameters:
      - name: side
        in: query
        required: false
        schema:
          type: string
          enum:
          - client
          - parser
          - puller
        description: Only one side.
      - name: status
        in: query
        required: false
        schema:
          type: string
          enum:
          - open
          - investigating
          - supported
          - wont_support
        description: Only gaps in this status.
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/IntegrationGap'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.integration_gaps.read
      x-moonitoring-requirements:
      - '136'
      - '1006.40'
  /integration-gaps/{gap_id}:
    get:
      summary: Get an integration gap
      operationId: getIntegrationGap
      tags:
      - Integration gaps
      parameters:
      - name: gap_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IntegrationGap'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.integration_gaps.read
      x-moonitoring-requirements:
      - '136'
      - '1006.40'
    patch:
      summary: Assign or resolve an integration gap
      operationId: updateIntegrationGap
      description: Setting status supported with the resolving adapter retries the runs and parse jobs that failed on the gap.
      tags:
      - Integration gaps
      parameters:
      - name: gap_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      requestBody:
        required: true
        content:
          application/json:
            schema:
              $ref: '#/components/schemas/IntegrationGapUpdate'
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '#/components/schemas/IntegrationGap'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
        '409':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Conflict
        '422':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/UnprocessableEntity
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.integration_gaps.manage
      x-moonitoring-requirements:
      - '136.7'
      - '136.8'
      - '136.9'
      - '136.10'
      - '1006.41'
  /integration-gaps/{gap_id}/occurrences:
    get:
      summary: List the occurrences of a gap
      operationId: listIntegrationGapOccurrences
      tags:
      - Integration gaps
      parameters:
      - name: gap_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Cursor
      - $ref: ../../../../common/v1/schemas.yaml#/components/parameters/Limit
      responses:
        '200':
          description: One page of results.
          content:
            application/json:
              schema:
                type: object
                description: One page of items.
                properties:
                  items:
                    type: array
                    items:
                      $ref: '#/components/schemas/IntegrationGapOccurrence'
                  next_cursor:
                    type: string
                    description: Where the next page starts; absent on the last page.
                required:
                - items
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.integration_gaps.read
      x-moonitoring-requirements:
      - '137'
      - '1006.40'
  /integration-gaps/{gap_id}/occurrences/{occurrence_id}/sample-url:
    post:
      summary: Get a download link for a sample
      operationId: getIntegrationGapSampleUrl
      description: A short-lived signed link to the sample of one occurrence; every call is a PlatformAuditEvent.
      tags:
      - Integration gaps
      parameters:
      - name: gap_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      - name: occurrence_id
        in: path
        required: true
        schema:
          type: string
          format: uuid
      responses:
        '200':
          description: The result.
          content:
            application/json:
              schema:
                $ref: '../../../../common/v1/schemas.yaml#/components/schemas/SignedUrl'
        '400':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/BadRequest
        '401':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Unauthorized
        '403':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/Forbidden
        '404':
          $ref: ../../../../common/v1/schemas.yaml#/components/responses/NotFound
      x-moonitoring-audience: staff
      x-moonitoring-capability: farm.integration_gaps.read
      x-moonitoring-requirements:
      - '137.7'
      - '1006.40'
components:
  schemas:
    SourceAdapter:
      description: A reader of one kind of source, for a range of its versions. Client adapters ship with the farm
        sync client; parser adapters ship with the parsers. The active ranges of one channel and side never overlap.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        code:
          type: string
          description: Stable name of the reader, e.g. delpro.sql.
        side:
          type: string
          enum:
          - client
          - parser
          - puller
        source_channel:
          type: string
          format: uuid
          description: ID of the SourceChannel.
        supported_versions:
          type: string
          description: The versions it was tested against when released, e.g. ">=5.3, <6.0"; a hint for mappings, never a
            selection by itself.
        adapter_version:
          type: string
          description: Semantic version; for a parser, the parser_version of its ParseJobs.
        release:
          type: string
          format: uuid
          description: ID of the first Release it was activated with; only for side = client.
        build_number:
          type: integer
          description: The lowest build number of the farm sync client that carries it; only for side = client.
        status:
          type: string
          enum:
          - active
          - deprecated
          - withdrawn
      required:
      - id
      - code
      - side
      - source_channel
      - supported_versions
      - adapter_version
      - status
    SourceAdapterInput:
      type: object
      properties:
        code:
          type: string
        side:
          type: string
          enum:
          - client
          - parser
          - puller
        source_channel:
          type: string
          format: uuid
        supported_versions:
          type: string
        adapter_version:
          type: string
        release:
          type: string
          format: uuid
      required:
      - code
      - side
      - source_channel
      - supported_versions
      - adapter_version
    SourceAdapterStatusInput:
      type: object
      properties:
        status:
          type: string
          enum:
          - active
          - deprecated
          - withdrawn
      required:
      - status
    AdapterMapping:
      description: Which adapter reads which detected source version, chosen by staff instead of built into the client.
        The most specific active mapping wins, feed before Organization before global.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        side:
          type: string
          enum:
          - client
          - parser
          - puller
        source_channel:
          type: string
          format: uuid
          description: ID of the SourceChannel, the product.
        version_range:
          type: string
          description: One version, e.g. "3.0.2", or a range, e.g. ">=3.0.1, <3.1", in the product's own scheme.
        adapter:
          type: string
          format: uuid
          description: ID of the SourceAdapter, the strategy and its version.
        scope:
          type: string
          enum:
          - global
          - organization
          - feed
        organization:
          type: string
          format: uuid
        source_feed:
          type: string
          format: uuid
        status:
          type: string
          enum:
          - active
          - retired
        note:
          type: string
        created_by:
          type: string
          format: uuid
          description: ID of the MoonitoringUser.
        created_at:
          type: string
          format: date-time
      required:
      - id
      - side
      - source_channel
      - version_range
      - adapter
      - scope
      - status
      - created_by
      - created_at
    AdapterMappingInput:
      type: object
      properties:
        side:
          type: string
          enum:
          - client
          - parser
          - puller
        source_channel:
          type: string
          format: uuid
          description: ID of the SourceChannel; a ThirdPartyPlatformChannel when side is puller, otherwise 422.
        version_range:
          type: string
        adapter:
          type: string
          format: uuid
        scope:
          type: string
          enum:
          - global
          - organization
          - feed
          default: global
        organization:
          type: string
          format: uuid
          description: Required when scope is organization.
        source_feed:
          type: string
          format: uuid
          description: Required when scope is feed.
        note:
          type: string
      required:
      - side
      - source_channel
      - version_range
      - adapter
    AdapterResolution:
      type: object
      properties:
        mapping:
          $ref: '#/components/schemas/AdapterMapping'
        adapter:
          $ref: '#/components/schemas/SourceAdapter'
      description: Both absent when no mapping covers the version, which becomes an integration gap at the next run.
    IntegrationGap:
      description: Something we cannot read yet, recorded once however many farms meet it. Occurrences are grouped
        by fingerprint; first and last seen and the number of farms are computed from them.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        fingerprint:
          type: string
          description: Hash of side, channel, detected version and structure signature.
        side:
          type: string
          enum:
          - client
          - parser
          - puller
        source_channel:
          type: string
          format: uuid
          description: ID of the SourceChannel; absent when the source was not recognised.
        detected_version:
          type: string
        structure_signature:
          type: string
          description: The structure of the input as JSON, without values.
        status:
          type: string
          enum:
          - open
          - investigating
          - supported
          - wont_support
        assignee:
          type: string
          format: uuid
          description: ID of the MoonitoringUser working on it.
        resolved_by:
          type: string
          format: uuid
          description: ID of the AdapterMapping that now covers it, when status = supported.
        note:
          type: string
        farms:
          type: integer
          description: Distinct farms that met it, computed from the occurrences.
        occurrences:
          type: integer
          description: Number of occurrences, computed.
        first_seen_at:
          type: string
          format: date-time
        last_seen_at:
          type: string
          format: date-time
      required:
      - id
      - fingerprint
      - side
      - structure_signature
      - status
    IntegrationGapUpdate:
      type: object
      properties:
        status:
          type: string
          enum:
          - open
          - investigating
          - supported
          - wont_support
        assignee:
          type: string
          format: uuid
        resolved_by:
          type: string
          format: uuid
          description: ID of the AdapterMapping that covers the gap; required when status becomes supported. The failed
            runs and jobs of the gap are then retried.
        note:
          type: string
    IntegrationGapOccurrence:
      description: One meeting of a gap by one farm. The first occurrence of each farm carries a sample of the input.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        gap:
          type: string
          format: uuid
        farm:
          type: string
          format: uuid
        source_feed:
          type: string
          format: uuid
        sync_run:
          type: string
          format: uuid
        parse_job:
          type: string
          format: uuid
        sample:
          type: string
          format: uuid
          description: ID of the RawMetadata holding the sample, when this occurrence carries one.
        seen_at:
          type: string
          format: date-time
      required:
      - id
      - gap
      - farm
      - seen_at
    SourceProducerEntity:
      description: 'Says where a piece of data comes from: which origin version produced it, through which channel
        version and feed it arrived, when it was produced and when we received it. Every raw file and canonical
        record points to one, so the question "where does this come from?" is answered the same way everywhere.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        origin_version:
          type: string
          format: uuid
          description: 'ID of the SourceVersion that is a OriginVersion. Version of the origin: sensor firmware,
            lab method, algorithm version.'
        channel_version:
          type: string
          format: uuid
          description: ID of the SourceVersion that is a ChannelVersion. Version of the channel that delivered the
            data, e.g. the management software release. Empty when the value was produced and delivered by the same
            system (e.g. typed into our app).
        validity:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/Period
          description: '`valid_until` = open: the source validity doesn''t expire.'
        produced_at:
          type: string
          format: date-time
          description: When the data was produced; empty when unknown.
        received_at:
          type: string
          format: date-time
          description: When our system received the data. Never used as a substitute for `produced_at`.
        source_feed:
          type: string
          format: uuid
          description: ID of the SourceFeed. The stable connection the data came through. A production context is
            created per delivery/origin, so logical source keys are feed-scoped, not producer-scoped (see `CanonicalObservation.source_record_key`,
            `CanonicalEvent.source_record_key`, `ObservationSession.source_record_key`). A SyncRun may contain multiple
            producer contexts; origin unknown remains explicit, not guessed from its channel.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - origin_version
      - validity
      - received_at
      - source_feed
      - created_at
      - updated_at
    SourceVersion:
      description: A version of an origin (sensor firmware, lab method, algorithm) or of a channel (a management-software
        release). Supplier versions we do not know stay unknown; our own algorithms and mappings always carry a
        real version.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        version:
          type: string
          description: Empty when externally unknown; our algorithms/mappings require a real version, never an invented
            supplier version.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        type:
          type: string
          enum:
          - OriginVersion
          - ChannelVersion
          description: Which kind of SourceVersion this is (enum, disjoint + complete).
      required:
      - id
      - created_at
      - updated_at
      - type
    OriginVersion:
      allOf:
      - $ref: '#/components/schemas/SourceVersion'
      - type: object
        properties:
          source_origin:
            type: string
            format: uuid
            description: ID of the SourceOrigin.
        required:
        - source_origin
      description: A SourceVersion whose type is OriginVersion.
    ChannelVersion:
      allOf:
      - $ref: '#/components/schemas/SourceVersion'
      - type: object
        properties:
          source_channel:
            type: string
            format: uuid
            description: ID of the SourceChannel.
        required:
        - source_channel
      description: A SourceVersion whose type is ChannelVersion.
    SourceOrigin:
      description: 'Who or what produces values: a kind of sensor, a human operator, a lab, a computation or an
        unknown producer. It is a kind of producer, not a physical device, and its assurance records who answers
        for the values.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        name:
          type: string
          description: Unique.
        organization:
          type: string
          format: uuid
          description: ID of the Organization. Empty for origins shared by all Organizations (e.g. a robot model,
            a lab, our algorithms).
        observation_accuracy:
          type: string
          enum:
          - precise
          - approximate
          - unknown
          default: unknown
        assurance:
          type: string
          enum:
          - official_registry
          - accredited_lab
          - approved_device
          - legal_prescription
          - none
          - unknown
          default: unknown
          description: 'Who answers for the values: an official registry, a lab accredited for the method, a device
            model approved for milk recording (e.g. ICAR), a legally signed prescription. none: self-declared, e.g.
            a farm worker typing a value. Set only from a document we hold; never guessed. A lost accreditation
            is a new image (`system_version`), so data read at an earlier write number keep the assurance known
            then.'
        system_version:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/SystemVersion
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        type:
          type: string
          enum:
          - SensorSourceOrigin
          - OperatorSourceOrigin
          - LabSourceOrigin
          - ComputedSourceOrigin
          - UnknownSourceOrigin
          description: Which kind of SourceOrigin this is (enum, disjoint + complete).
      required:
      - id
      - name
      - observation_accuracy
      - assurance
      - system_version
      - created_at
      - updated_at
      - type
    SensorSourceOrigin:
      allOf:
      - $ref: '#/components/schemas/SourceOrigin'
      - type: object
        properties:
          vendor:
            type: string
          model:
            type: string
        required:
        - vendor
      description: A SourceOrigin whose type is SensorSourceOrigin.
    OperatorSourceOrigin:
      allOf:
      - $ref: '#/components/schemas/SourceOrigin'
      description: A SourceOrigin whose type is OperatorSourceOrigin.
    LabSourceOrigin:
      allOf:
      - $ref: '#/components/schemas/SourceOrigin'
      description: A SourceOrigin whose type is LabSourceOrigin.
    ComputedSourceOrigin:
      allOf:
      - $ref: '#/components/schemas/SourceOrigin'
      - type: object
        properties:
          computed_by:
            type: string
            enum:
            - moonitoring
            - vendor
            description: '`moonitoring`: our algorithm, versioned through OriginVersion. `vendor`: computed by the
              provider''s software; tied to the provider''s version when known.'
        required:
        - computed_by
      description: A SourceOrigin whose type is ComputedSourceOrigin.
    UnknownSourceOrigin:
      allOf:
      - $ref: '#/components/schemas/SourceOrigin'
      description: A SourceOrigin whose type is UnknownSourceOrigin.
    SourceChannel:
      description: 'How values reach us: read directly from a device, through management software, through a third-party
        platform, typed in our app or uploaded as a file. The channel is independent of the origin, so the same
        robot reading can arrive through two channels.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        name:
          type: string
          description: Unique.
        organization:
          type: string
          format: uuid
          description: ID of the Organization.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
        type:
          type: string
          enum:
          - DirectDeviceChannel
          - ManagementSoftwareChannel
          - ThirdPartyPlatformChannel
          - MoonitoringAppChannel
          - FileChannel
          description: Which kind of SourceChannel this is (enum, disjoint + complete).
      required:
      - id
      - name
      - created_at
      - updated_at
      - type
    DirectDeviceChannel:
      allOf:
      - $ref: '#/components/schemas/SourceChannel'
      description: A SourceChannel whose type is DirectDeviceChannel.
    ManagementSoftwareChannel:
      allOf:
      - $ref: '#/components/schemas/SourceChannel'
      description: A SourceChannel whose type is ManagementSoftwareChannel.
    ThirdPartyPlatformChannel:
      allOf:
      - $ref: '#/components/schemas/SourceChannel'
      description: A SourceChannel whose type is ThirdPartyPlatformChannel.
    MoonitoringAppChannel:
      allOf:
      - $ref: '#/components/schemas/SourceChannel'
      description: A SourceChannel whose type is MoonitoringAppChannel.
    FileChannel:
      allOf:
      - $ref: '#/components/schemas/SourceChannel'
      description: A SourceChannel whose type is FileChannel.
    Device:
      description: 'A physical device on a farm: a specific robot, meter, collar, tag, scale or camera. It is an
        instance of a sensor origin, with its serial number, provider address and installation period.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        source_origin:
          type: string
          format: uuid
          description: ID of the SourceOrigin that is a SensorSourceOrigin. The kind of device (vendor, model).
        farm:
          type: string
          format: uuid
          description: ID of the Organization that is a Farm.
        serial_number:
          type: string
        external_address:
          type: string
          description: 'The address used by the provider''s software (e.g. robot 101). Not unique: providers reuse
            addresses.'
        validity:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/Period
          description: When the device was installed and removed.
        firmware_version:
          type: string
          description: Current inventory value only; historical observations retain their actual OriginVersion when
            known. Do not apply today's firmware retroactively; any learning-period exclusion is a versioned analysis
            rule.
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - source_origin
      - farm
      - validity
      - created_at
      - updated_at
    DeviceAssignment:
      description: Records which animal wears or carries a mobile device (a collar, tag or bolus) over time, so
        its readings are attributed to the right animal. Fixed devices such as robots have no assignment.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        device:
          type: string
          format: uuid
          description: ID of the Device.
        animal:
          type: string
          format: uuid
          description: ID of the Animal.
        period:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/Period
          description: Periods of the same device must not overlap.
        source_producer:
          type: string
          format: uuid
          description: ID of the SourceProducerEntity.
        system_version:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/SystemVersion
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - device
      - animal
      - period
      - source_producer
      - system_version
      - created_at
      - updated_at
    SourceFeed:
      description: 'One farm''s data arriving through one channel, for example a farm''s data from its management
        software. Data is synchronised feed by feed, and each feed records custody: who is responsible for the data,
        and whether values can be changed before they reach us.'
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        farm:
          type: string
          format: uuid
          description: ID of the Organization that is a Farm.
        source_channel:
          type: string
          format: uuid
          description: ID of the SourceChannel.
        name:
          type: string
        validity:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/Period
          description: When the feed was connected and disconnected.
        reliability_class:
          type: string
          enum:
          - official_registry
          - lab
          - e_prescription
          - device_direct
          - management_software
          - moonitoring_app
          - file
          - unknown
          description: 'Default only: a feed can carry laboratory, registry and sensor results; assess record origin/method
            per SourceReliability.'
        sync_client:
          type: string
          format: uuid
          description: ID of the SyncClient. The sync client that reads this feed at the farm. Empty for feeds that
            reach us without our client (our app, uploaded files, a vendor cloud we call directly). Must work for
            the feed's farm.
        owner_organization:
          type: string
          format: uuid
          description: ID of the Organization. Who is responsible for the data of this feed and for fixing it at
            the source.
        upstream_editable:
          type: string
          enum:
          - 'no'
          - 'yes'
          - unknown
          default: unknown
          description: 'Can the farm change values before they reach us? e.g. no: our client reads the robot itself;
            yes: a management software where values can be corrected, a file uploaded by the farm, our app. Origin
            (SourceOrigin) says who produced a value; this says who could have changed it on the way. The same robot
            reading has a different answer on a direct feed and on a management-software feed.'
        created_at:
          type: string
          format: date-time
        updated_at:
          type: string
          format: date-time
      required:
      - id
      - farm
      - source_channel
      - name
      - validity
      - reliability_class
      - owner_organization
      - upstream_editable
      - created_at
      - updated_at
    FeedCoverage:
      description: Says which period of a feed's data is present, complete and final, for each kind of data. Without
        it, a missing record cannot be told apart from data that has not arrived yet.
      type: object
      properties:
        id:
          type: string
          format: uuid
          description: Key.
        source_feed:
          type: string
          format: uuid
          description: ID of the SourceFeed.
        data_kind:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/CodedValue
          description: An observation type family, an event type, sessions or registry data, as declared by the
            adapter.
        data_from:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/EventTime
        complete_until:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/EventTime
          description: Every record of this kind up to here has been received. After it, absence means "not known
            yet".
        settled_until:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/EventTime
          description: 'The source no longer changes records up to here, by the adapter''s rule (e.g. Lely feeding:
            `complete_until` minus 4 days). Later corrections are still possible and arrive as revisions; labels
            for models should stay before this date.'
        rule:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/CodedValue
          description: Versioned adapter rule that computes the two dates.
        computed_in:
          type: string
          format: uuid
          description: ID of the SyncRun.
        revision:
          $ref: ../../../../common/v1/schemas.yaml#/components/schemas/RecordRevision
        created_at:
          type: string
          format: date-time
      required:
      - id
      - source_feed
      - data_kind
      - data_from
      - rule
      - computed_in
      - revision
      - created_at
    SourceFeedInput:
      type: object
      description: 'Connects a feed to a farm: the channel it comes through, a name, its reliability class, the
        sync client that reads it (empty for feeds we receive without our client) and whether the farm can change
        values upstream. The farm and the owner Organization come from the path and the token.'
      properties:
        source_channel:
          type: string
          format: uuid
          description: ID of the SourceChannel.
        name:
          type: string
        reliability_class:
          type: string
          enum:
          - official_registry
          - lab
          - e_prescription
          - device_direct
          - management_software
          - moonitoring_app
          - file
          - unknown
          description: 'Default only: a feed can carry laboratory, registry and sensor results; assess record origin/method
            per SourceReliability.'
        sync_client:
          type: string
          format: uuid
          description: ID of the SyncClient. The sync client that reads this feed at the farm. Empty for feeds that
            reach us without our client (our app, uploaded files, a vendor cloud we call directly). Must work for
            the feed's farm.
        upstream_editable:
          type: string
          enum:
          - 'no'
          - 'yes'
          - unknown
          default: unknown
          description: 'Can the farm change values before they reach us? e.g. no: our client reads the robot itself;
            yes: a management software where values can be corrected, a file uploaded by the farm, our app. Origin
            (SourceOrigin) says who produced a value; this says who could have changed it on the way. The same robot
            reading has a different answer on a direct feed and on a management-software feed.'
      required:
      - source_channel
      - name
      - reliability_class
      - upstream_editable
      additionalProperties: false
    SourceFeedUpdate:
      type: object
      description: Fields of a feed that may change after it is connected.
      properties:
        name:
          type: string
        reliability_class:
          type: string
          enum:
          - official_registry
          - lab
          - e_prescription
          - device_direct
          - management_software
          - moonitoring_app
          - file
          - unknown
          description: 'Default only: a feed can carry laboratory, registry and sensor results; assess record origin/method
            per SourceReliability.'
        upstream_editable:
          type: string
          enum:
          - 'no'
          - 'yes'
          - unknown
          default: unknown
          description: 'Can the farm change values before they reach us? e.g. no: our client reads the robot itself;
            yes: a management software where values can be corrected, a file uploaded by the farm, our app. Origin
            (SourceOrigin) says who produced a value; this says who could have changed it on the way. The same robot
            reading has a different answer on a direct feed and on a management-software feed.'
        sync_client:
          type: string
          format: uuid
          description: ID of the SyncClient that reads it; empty to detach.
    FeedCredentialInput:
      type: object
      description: The credential our vendor puller uses for a feed on a third-party platform. Stored in Secret
        Manager; the database keeps only a reference. Never returned.
      properties:
        kind:
          type: string
          enum:
          - api_key
          - username_password
          - oauth_refresh_token
        secret:
          type: object
          additionalProperties:
            type: string
          description: The fields of the credential, by kind.
        account_reference:
          type: string
          description: The farm's identifier on the platform, e.g. its registry code.
      required:
      - kind
      - secret
    DeviceInput:
      type: object
      description: 'A physical device at the farm: a robot, a meter, a collar, a scale. `source_origin` is the kind
        of device (vendor, model).'
      properties:
        source_origin:
          type: string
          format: uuid
          description: ID of the SourceOrigin that is a SensorSourceOrigin. The kind of device (vendor, model).
        serial_number:
          type: string
        external_address:
          type: string
          description: 'The address used by the provider''s software (e.g. robot 101). Not unique: providers reuse
            addresses.'
        validity:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/Period
          description: When the device was installed and removed.
        firmware_version:
          type: string
          description: Current inventory value only; historical observations retain their actual OriginVersion when
            known. Do not apply today's firmware retroactively; any learning-period exclusion is a versioned analysis
            rule.
      required:
      - source_origin
      - validity
      additionalProperties: false
    DeviceAssignmentInput:
      type: object
      description: Which animal wears the device, from when. The producer of the assignment is the Organization's
        app channel.
      properties:
        animal:
          type: string
          format: uuid
          description: ID of the Animal.
        period:
          allOf:
          - $ref: ../../../../common/v1/schemas.yaml#/components/schemas/Period
          description: Periods of the same device must not overlap.
      required:
      - animal
      - period
      additionalProperties: false
    ClosePeriodRequest:
      type: object
      description: Closes an open period now or at a given time.
      properties:
        valid_until:
          type: string
          format: date-time
          description: 'Default: now.'
    SourceChannelInput:
      type: object
      description: 'A channel: the `type` says the kind (direct device, management software, third-party platform,
        our app, file). Staff create global channels; an Organization creates its own, scoped to it.'
      properties:
        name:
          type: string
          description: Unique.
        type:
          type: string
          enum:
          - DirectDeviceChannel
          - ManagementSoftwareChannel
          - ThirdPartyPlatformChannel
          - MoonitoringAppChannel
          - FileChannel
          description: Which kind of SourceChannel this is (enum, disjoint + complete).
      required:
      - name
      - type
      additionalProperties: false
    SourceOriginInput:
      type: object
      description: 'An origin: the `type` says the kind; `vendor` and `model` apply to a sensor origin, `computed_by`
        to a computed one. Assurance is set only from a document we hold.'
      properties:
        name:
          type: string
          description: Unique.
        observation_accuracy:
          type: string
          enum:
          - precise
          - approximate
          - unknown
          default: unknown
        assurance:
          type: string
          enum:
          - official_registry
          - accredited_lab
          - approved_device
          - legal_prescription
          - none
          - unknown
          default: unknown
          description: 'Who answers for the values: an official registry, a lab accredited for the method, a device
            model approved for milk recording (e.g. ICAR), a legally signed prescription. none: self-declared, e.g.
            a farm worker typing a value. Set only from a document we hold; never guessed. A lost accreditation
            is a new image (`system_version`), so data read at an earlier write number keep the assurance known
            then.'
        type:
          type: string
          enum:
          - SensorSourceOrigin
          - OperatorSourceOrigin
          - LabSourceOrigin
          - ComputedSourceOrigin
          - UnknownSourceOrigin
          description: Which kind of SourceOrigin this is (enum, disjoint + complete).
        vendor:
          type: string
          description: Required for a SensorSourceOrigin; absent for the other kinds.
        model:
          type: string
        computed_by:
          type: string
          enum:
          - moonitoring
          - vendor
          description: Required for a ComputedSourceOrigin; absent for the other kinds.
      required:
      - name
      - observation_accuracy
      - assurance
      - type
      allOf:
      - if:
          properties:
            type:
              const: SensorSourceOrigin
        then:
          required:
          - vendor
      - if:
          properties:
            type:
              const: ComputedSourceOrigin
        then:
          required:
          - computed_by
      additionalProperties: false
    SourceVersionInput:
      type: object
      description: Registers a version of an origin or a channel, such as a firmware, a lab method or a software
        release. Empty when externally unknown.
      properties:
        version:
          type: string
    ProducerLineage:
      type: object
      description: 'A source producer with everything it points to: the origin and its version, the channel and
        its version, the feed and its farm. The answer to who produced a value and how it reached us.'
      properties:
        producer:
          $ref: '#/components/schemas/SourceProducerEntity'
        origin_version:
          $ref: '#/components/schemas/OriginVersion'
        origin:
          $ref: '#/components/schemas/SourceOrigin'
        channel_version:
          $ref: '#/components/schemas/ChannelVersion'
        channel:
          $ref: '#/components/schemas/SourceChannel'
        feed:
          $ref: '#/components/schemas/SourceFeed'
      required:
      - producer
      - origin_version
      - origin
      - feed
  securitySchemes:
    bearer:
      type: http
      scheme: bearer
      bearerFormat: JWT
      description: 'The short-lived token signed by `access`: an Organization user token, a staff token or a client
        token, as the operation''s audience says.'
