Event model
Every event is delivered as a single JSON payload, with no wrapper around it, to every destination you have subscribed to its topic.
Envelope
Section titled “Envelope”Every payload shares one structure: a common envelope, an event-specific data block, a subject block identifying the farm, and a delivery block.
| Field | Type | Meaning |
|---|---|---|
schema_version |
string | Version of the payload schema. "1.0" today. |
type |
string | The event type. Same value as the topic, e.g. levno.milking.finished. |
date_time |
string | When the event occurred, ISO 8601 with the farm’s local UTC offset — e.g. 2026-02-02T15:30:00+12:00. |
id |
string | Unique id of the event: <type>/<entity id>/<timestamp>. Stable across retries — deduplicate on this. |
data |
object | Attributes specific to the event type. See the two sections below. |
subject |
object | Context identifying the farm the event is about. |
delivery.id |
string | Unique id of this payload. Identical on every retry of it. |
Subject fields
Section titled “Subject fields”| Field | Type | Meaning |
|---|---|---|
levno_farm_id |
number | Levno’s unique id for the farm, as returned by the Levno for Partners REST API. |
supply_number |
string or null | The farm’s supply number. Can be null. |
partner_defined_id |
string or null | Your own id for the farm, set by you in the Levno for Partners app. Can be null. |
partner_defined_name |
string or null | Your own name for the farm, set by you in the Levno for Partners app. Can be null. |
Levno may add new fields within schema_version "1.0", so ignore anything you do not recognise rather than rejecting the payload. A change that breaks existing consumers will come with a new schema_version and advance notice.
Event types
Section titled “Event types”levno.farm.milk.volume.updated
Section titled “levno.farm.milk.volume.updated”Sent alongside a milking or collection finished event, describing the farm as a whole rather than the single vat that changed.
| Data field | Type | Meaning |
|---|---|---|
reason |
string | Why the total changed — milking_finished or collection_finished. |
total_volume_litres |
number | The farm’s total milk volume, in litres, summed across all its vats. |
vats |
array | Every vat on the farm and its own current volume. |
vats[].levno_id |
number | Levno’s unique id for the vat. |
vats[].volume_litres |
number | The vat’s own current volume, in litres. |
{ "schema_version": "1.0", "type": "levno.farm.milk.volume.updated", "date_time": "2026-02-02T15:30:00+12:00", "id": "levno.farm.milk.volume.updated/123/1770003000", "data": { "reason": "milking_finished", "total_volume_litres": 7200, "vats": [ { "levno_id": 456, "volume_litres": 3500 }, { "levno_id": 457, "volume_litres": 3700 } ] }, "delivery": { "id": "9c1b9e2a-df22-4b8b-9b52-9a1f6e2f9d31" }, "subject": { "levno_farm_id": 123, "supply_number": "1234", "partner_defined_id": "1", "partner_defined_name": "Farm 1" }}levno.milking.finished
Section titled “levno.milking.finished”| Data field | Type | Meaning |
|---|---|---|
volume_milked_litres |
number | The amount of milk, in litres, detected during the milking. |
volume_remaining_litres |
number | The amount of milk, in litres, left in the vat once the milking had completed. |
{ "schema_version": "1.0", "type": "levno.milking.finished", "date_time": "2026-02-02T15:30:00+12:00", "id": "levno.milking.finished/123/1770003000", "data": { "volume_milked_litres": 3000, "volume_remaining_litres": 3500 }, "delivery": { "id": "45f63709-817f-4323-9077-91974e7e66a7" }, "subject": { "levno_farm_id": 123, "supply_number": "1234", "partner_defined_id": "1", "partner_defined_name": "Farm 1" }}levno.collection.finished
Section titled “levno.collection.finished”| Data field | Type | Meaning |
|---|---|---|
volume_collected_litres |
number | The amount of milk, in litres, detected during the collection. |
volume_remaining_litres |
number | The amount of milk, in litres, left in the vat once the collection had completed. |
{ "schema_version": "1.0", "type": "levno.collection.finished", "date_time": "2026-02-03T06:00:00+12:00", "id": "levno.collection.finished/123/1770055200", "data": { "volume_collected_litres": 3500, "volume_remaining_litres": 0 }, "delivery": { "id": "e66f8440-3336-4eae-96e0-b53a6185955a" }, "subject": { "levno_farm_id": 123, "supply_number": "1234", "partner_defined_id": "1", "partner_defined_name": "Farm 1" }}Correlation and deduplication
Section titled “Correlation and deduplication”Use the payload’s id as the event’s stable identity — it is identical across every retry of that event, so deduplicate business processing on it. delivery.id identifies one generated delivery attempt and changes when Levno rebuilds the payload; do not use it for business deduplication.
For processing guidance, continue to delivery, retries, and idempotency.