5.5.2.1 Sources
The Sources domain of farm. 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. It is one API, with its own contract and its own version.
5.5.2.1.1 Versions¶
| Version | Status | Prod URL | Contract |
|---|---|---|---|
v1 |
Proposed | https://farm.moonitoring.com/sources/v1 |
sources/v1/openapi.yaml |
The resources follow the data model. Adds ProducerLineage, which resolves a source_producer to origin, channel, feed and versions in one read, and FeedCredentialInput, whose secret goes to Secret Manager and is never returned.
The integrations of a farm are set up in the farm sync client (decided 2026-11-10): a person who holds farm.sources.manage on the farm, signed in to the client at most five minutes before, picks the software, tests the connection on the computer, and the client calls Connect a feed with the person's token and its own sync_client; Disconnect a feed follows the removal of the integration in the client. The credentials of software read on the farm never reach us: they stay in the client's Windows Credential Manager, as the hand-over bundle of the legacy move leaves them. Set a feed's vendor credential is only for a vendor cloud that farm itself calls, such as the milk recording of AIA; that integration is set up in the client too (decided 2026-11-10), which creates the feed without a sync_client and sends the credential once, keeping no copy. Every write that checks farm.sources.manage asks a person for a sign-in at most five minutes old, otherwise 403 reauthentication-required, as every write under an admin capability does; a read never asks (decided 2026-11-11). The Organization Dashboard and the Console show feeds, coverage and integration gaps and offer no set-up; the Dashboard pauses an integration through its schedule.
5.5.2.1.2 Operations¶
Every operation names who calls it and the capability it checks (x-moonitoring-audience, x-moonitoring-capability in the contract); every capability is in the catalog of the data model (req 1002, 1006). Lists are paged by cursor, writes that create something carry an Idempotency-Key, errors are Problem Details.
| Operation | Request | Who | Capability |
|---|---|---|---|
| List a farm's feeds | GET /organizations/{organization_id}/feeds |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Connect a feed | POST /organizations/{organization_id}/feeds |
Organization users | farm.sources.manage |
| List every feed | GET /feeds |
Staff | farm.ingestion.read_all |
| Read a feed | GET /feeds/{feed_id} |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Update a feed | PATCH /feeds/{feed_id} |
Organization users | farm.sources.manage |
| Disconnect a feed | POST /feeds/{feed_id}/disconnect |
Organization users | farm.sources.manage |
| Set a feed's vendor credential | PUT /feeds/{feed_id}/credential |
Organization users | farm.sources.manage |
| Read a feed's coverage | GET /feeds/{feed_id}/coverage |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| List a farm's devices | GET /organizations/{organization_id}/devices |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Register a device | POST /organizations/{organization_id}/devices |
Organization users | farm.sources.manage |
| Read a device | GET /devices/{device_id} |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Update a device | PATCH /devices/{device_id} |
Organization users | farm.sources.manage |
| List who wore a device | GET /devices/{device_id}/assignments |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| Assign a device to an animal | POST /devices/{device_id}/assignments |
Organization users | farm.sources.manage |
| End a device assignment | POST /device-assignments/{assignment_id}/close |
Organization users | farm.sources.manage |
| List channels | GET /channels |
Organization users, staff or clients | none: any member of the Organization |
| Create a global channel | POST /channels |
Staff | farm.source_origins.manage |
| Create an Organization's channel | POST /organizations/{organization_id}/channels |
Organization users | farm.sources.manage |
| List a channel's versions | GET /channels/{channel_id}/versions |
Organization users, staff or clients | none: any member of the Organization |
| Register a channel version | POST /channels/{channel_id}/versions |
Staff | farm.source_origins.manage |
| List origins | GET /origins |
Organization users, staff or clients | none: any member of the Organization |
| Create a global origin | POST /origins |
Staff | farm.source_origins.manage |
| Create an Organization's origin | POST /organizations/{organization_id}/origins |
Organization users | farm.sources.manage |
| Update an origin | PATCH /origins/{origin_id} |
Staff | farm.source_origins.manage |
| List an origin's versions | GET /origins/{origin_id}/versions |
Organization users, staff or clients | none: any member of the Organization |
| Register an origin version | POST /origins/{origin_id}/versions |
Staff | farm.source_origins.manage |
| Read a producer's lineage | GET /producers/{producer_id} |
Organization users, staff or clients | farm.ingestion.read or farm.ingestion.read_all |
| List source adapters | GET /source-adapters |
Staff | farm.ingestion.read_all |
| Register a source adapter | POST /source-adapters |
Staff | farm.source_adapters.manage |
| Deprecate or withdraw a source adapter | POST /source-adapters/{adapter_id}/status |
Staff | farm.source_adapters.manage |
| List adapter mappings | GET /adapter-mappings |
Staff | farm.ingestion.read_all |
| Map a detected version to an adapter | POST /adapter-mappings |
Staff | farm.adapter_mappings.manage |
| Retire an adapter mapping | POST /adapter-mappings/{mapping_id}/retire |
Staff | farm.adapter_mappings.manage |
| Resolve the adapter for a detection | GET /adapter-mappings/resolve |
Staff | farm.ingestion.read_all |
| List integration gaps | GET /integration-gaps |
Staff | farm.integration_gaps.read |
| Get an integration gap | GET /integration-gaps/{gap_id} |
Staff | farm.integration_gaps.read |
| Assign or resolve an integration gap | PATCH /integration-gaps/{gap_id} |
Staff | farm.integration_gaps.manage |
| List the occurrences of a gap | GET /integration-gaps/{gap_id}/occurrences |
Staff | farm.integration_gaps.read |
| Get a download link for a sample | POST /integration-gaps/{gap_id}/occurrences/{occurrence_id}/sample-url |
Staff | farm.integration_gaps.read |
5.5.2.1.3 Contract v1¶
Proposed version
v1 is a proposal for review: its endpoints, errors and capabilities were designed from the requirements and the flows and are not confirmed. It leaves proposal with its first release; from then on it changes only as described in Every API Is Versioned.
5.5.2.1.4 Rules Confirmed with the Implementation¶
Decided on 2026-11-05, from the choices made while building farm:
- A mapping of scope
feedalso carries itsorganizationin answers, the farm of the feed, and the feed must read the mapping's product. - Resolving without
sideresolves the client side. - A parse job without a detected version gets the parser of a mapping of every version (
*), ornoneand waits queued for one;parser_versionisnoneuntil then. - The adapters a sync-client build carries are registered from
release.activated.v1, the first time a release of that build becomes active; staff register other adapters by hand.