farmOS JSON:API

The farmOS JSON:API provides access to farm assets, logs, plans, and records. Follows the JSON:API specification with UUID-based resource identifiers. The root endpoint at /api returns server metadata and available resource types. Resource endpoints follow the pattern /api/[entity-type]/[bundle].

OpenAPI Specification

farmos-farmos-api-openapi.yml Raw ↑
openapi: 3.0.3
info:
  title: farmOS JSON:API
  description: |
    The farmOS JSON:API provides access to farm assets, logs, plans, and records.
    It follows the JSON:API specification (https://jsonapi.org/) with UUID-based
    resource identifiers. The root endpoint at /api returns server metadata and
    available resource types. Resource endpoints follow the pattern
    /api/[entity-type]/[bundle].

    farmOS is an open-source farm management and record-keeping system built on
    Drupal. It supports self-hosted deployments and managed hosting via Farmier.
  version: '2.x'
  contact:
    name: farmOS Community
    url: https://farmos.org/community/
  license:
    name: GNU General Public License v2.0
    url: https://github.com/farmOS/farmOS/blob/main/LICENSE.txt
  termsOfService: https://farmos.org/

externalDocs:
  description: farmOS API Documentation
  url: https://farmos.org/development/api/

servers:
  - url: https://{farmOS-host}/api
    description: Self-hosted farmOS instance
    variables:
      farmOS-host:
        default: example.farmos.net
        description: The hostname of your farmOS instance (self-hosted or Farmier-managed)

security:
  - oauth2AuthorizationCode:
      - farm_manager
  - oauth2ClientCredentials:
      - farm_manager

tags:
  - name: Server Info
    description: Server metadata and available resource types
  - name: Assets
    description: Physical or logical farm assets (land, animals, equipment, plants, etc.)
  - name: Logs
    description: Farm activity records (activities, observations, inputs, harvests, etc.)
  - name: Plans
    description: Farm planning records
  - name: Quantities
    description: Measurement quantities associated with logs
  - name: Taxonomy
    description: Taxonomy term resources (categories, types, units)

paths:
  /:
    get:
      operationId: getServerInfo
      summary: Get server metadata
      description: |
        Returns metadata about the farmOS server, including authenticated user
        information, farm details (name, URL, version, measurement system), and
        available resource types with their endpoint URLs.
      tags:
        - Server Info
      responses:
        '200':
          description: Server metadata
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/ServerInfo'
        '401':
          $ref: '#/components/responses/Unauthorized'

  # ── ASSET ENDPOINTS ───────────────────────────────────────────────────────

  /asset/animal:
    get:
      operationId: listAnimalAssets
      summary: List animal assets
      description: Returns a collection of animal assets.
      tags: [Assets]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of animal assets
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createAnimalAsset
      summary: Create an animal asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '201':
          description: Animal asset created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /asset/animal/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getAnimalAsset
      summary: Get an animal asset
      tags: [Assets]
      responses:
        '200':
          description: An animal asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateAnimalAsset
      summary: Update an animal asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '200':
          description: Updated animal asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteAnimalAsset
      summary: Delete an animal asset
      tags: [Assets]
      responses:
        '204':
          description: Animal asset deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /asset/land:
    get:
      operationId: listLandAssets
      summary: List land assets
      description: Returns a collection of land assets (fields, beds, paddocks, etc.).
      tags: [Assets]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of land assets
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createLandAsset
      summary: Create a land asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '201':
          description: Land asset created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /asset/land/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getLandAsset
      summary: Get a land asset
      tags: [Assets]
      responses:
        '200':
          description: A land asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateLandAsset
      summary: Update a land asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '200':
          description: Updated land asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteLandAsset
      summary: Delete a land asset
      tags: [Assets]
      responses:
        '204':
          description: Land asset deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /asset/plant:
    get:
      operationId: listPlantAssets
      summary: List plant assets
      tags: [Assets]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of plant assets
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createPlantAsset
      summary: Create a plant asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '201':
          description: Plant asset created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /asset/plant/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getPlantAsset
      summary: Get a plant asset
      tags: [Assets]
      responses:
        '200':
          description: A plant asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updatePlantAsset
      summary: Update a plant asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '200':
          description: Updated plant asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deletePlantAsset
      summary: Delete a plant asset
      tags: [Assets]
      responses:
        '204':
          description: Plant asset deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /asset/equipment:
    get:
      operationId: listEquipmentAssets
      summary: List equipment assets
      tags: [Assets]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of equipment assets
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createEquipmentAsset
      summary: Create an equipment asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '201':
          description: Equipment asset created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /asset/equipment/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getEquipmentAsset
      summary: Get an equipment asset
      tags: [Assets]
      responses:
        '200':
          description: An equipment asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateEquipmentAsset
      summary: Update an equipment asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '200':
          description: Updated equipment asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteEquipmentAsset
      summary: Delete an equipment asset
      tags: [Assets]
      responses:
        '204':
          description: Equipment asset deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /asset/structure:
    get:
      operationId: listStructureAssets
      summary: List structure assets
      tags: [Assets]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of structure assets
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createStructureAsset
      summary: Create a structure asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '201':
          description: Structure asset created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /asset/structure/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getStructureAsset
      summary: Get a structure asset
      tags: [Assets]
      responses:
        '200':
          description: A structure asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateStructureAsset
      summary: Update a structure asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '200':
          description: Updated structure asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteStructureAsset
      summary: Delete a structure asset
      tags: [Assets]
      responses:
        '204':
          description: Structure asset deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /asset/sensor:
    get:
      operationId: listSensorAssets
      summary: List sensor assets
      tags: [Assets]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of sensor assets
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createSensorAsset
      summary: Create a sensor asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '201':
          description: Sensor asset created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /asset/sensor/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getSensorAsset
      summary: Get a sensor asset
      tags: [Assets]
      responses:
        '200':
          description: A sensor asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateSensorAsset
      summary: Update a sensor asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '200':
          description: Updated sensor asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteSensorAsset
      summary: Delete a sensor asset
      tags: [Assets]
      responses:
        '204':
          description: Sensor asset deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /asset/group:
    get:
      operationId: listGroupAssets
      summary: List group assets
      tags: [Assets]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of group assets
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createGroupAsset
      summary: Create a group asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '201':
          description: Group asset created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /asset/group/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getGroupAsset
      summary: Get a group asset
      tags: [Assets]
      responses:
        '200':
          description: A group asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateGroupAsset
      summary: Update a group asset
      tags: [Assets]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/AssetRequest'
      responses:
        '200':
          description: Updated group asset
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/AssetResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteGroupAsset
      summary: Delete a group asset
      tags: [Assets]
      responses:
        '204':
          description: Group asset deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  # ── LOG ENDPOINTS ──────────────────────────────────────────────────────────

  /log/activity:
    get:
      operationId: listActivityLogs
      summary: List activity logs
      description: Returns a collection of activity logs (general catch-all log type).
      tags: [Logs]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of activity logs
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createActivityLog
      summary: Create an activity log
      tags: [Logs]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/LogRequest'
      responses:
        '201':
          description: Activity log created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /log/activity/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getActivityLog
      summary: Get an activity log
      tags: [Logs]
      responses:
        '200':
          description: An activity log
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateActivityLog
      summary: Update an activity log
      tags: [Logs]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/LogRequest'
      responses:
        '200':
          description: Updated activity log
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteActivityLog
      summary: Delete an activity log
      tags: [Logs]
      responses:
        '204':
          description: Activity log deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /log/observation:
    get:
      operationId: listObservationLogs
      summary: List observation logs
      tags: [Logs]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of observation logs
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createObservationLog
      summary: Create an observation log
      tags: [Logs]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/LogRequest'
      responses:
        '201':
          description: Observation log created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /log/observation/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getObservationLog
      summary: Get an observation log
      tags: [Logs]
      responses:
        '200':
          description: An observation log
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateObservationLog
      summary: Update an observation log
      tags: [Logs]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/LogRequest'
      responses:
        '200':
          description: Updated observation log
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteObservationLog
      summary: Delete an observation log
      tags: [Logs]
      responses:
        '204':
          description: Observation log deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /log/input:
    get:
      operationId: listInputLogs
      summary: List input logs
      description: Records of resources put into farm assets (e.g., fertilizer, feed).
      tags: [Logs]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of input logs
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createInputLog
      summary: Create an input log
      tags: [Logs]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/LogRequest'
      responses:
        '201':
          description: Input log created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /log/input/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getInputLog
      summary: Get an input log
      tags: [Logs]
      responses:
        '200':
          description: An input log
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    patch:
      operationId: updateInputLog
      summary: Update an input log
      tags: [Logs]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/LogRequest'
      responses:
        '200':
          description: Updated input log
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'
    delete:
      operationId: deleteInputLog
      summary: Delete an input log
      tags: [Logs]
      responses:
        '204':
          description: Input log deleted
        '401':
          $ref: '#/components/responses/Unauthorized'
        '404':
          $ref: '#/components/responses/NotFound'

  /log/harvest:
    get:
      operationId: listHarvestLogs
      summary: List harvest logs
      tags: [Logs]
      parameters:
        - $ref: '#/components/parameters/PageSize'
        - $ref: '#/components/parameters/PageOffset'
        - $ref: '#/components/parameters/FilterField'
        - $ref: '#/components/parameters/SortField'
        - $ref: '#/components/parameters/IncludeRelated'
      responses:
        '200':
          description: A collection of harvest logs
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogCollection'
        '401':
          $ref: '#/components/responses/Unauthorized'
    post:
      operationId: createHarvestLog
      summary: Create a harvest log
      tags: [Logs]
      requestBody:
        required: true
        content:
          application/vnd.api+json:
            schema:
              $ref: '#/components/schemas/LogRequest'
      responses:
        '201':
          description: Harvest log created
          content:
            application/vnd.api+json:
              schema:
                $ref: '#/components/schemas/LogResponse'
        '401':
          $ref: '#/components/responses/Unauthorized'
        '422':
          $ref: '#/components/responses/UnprocessableEntity'

  /log/harvest/{id}:
    parameters:
      - $ref: '#/components/parameters/ResourceId'
    get:
      operationId: getHarvestLog
      summary: Get a harvest log
      tags: [Logs]
      responses:
        '200':
          description: A harvest log
          c

# --- truncated at 32 KB (76 KB total) ---
# Full source: https://raw.githubusercontent.com/api-evangelist/farmos/refs/heads/main/openapi/farmos-farmos-api-openapi.yml