Devices and ingest
Every Roost house, tracker and sensor is a device with its own key. Device keys start with rd_ and can only report data and read their own commands.
Pair a device
roots devices add type=bolus name="Bolus 118" animal_id=ani_…
POST /v1/farms/{farm}/devices
{ "type": "bolus", "name": "Bolus 118", "animal_id": "ani_…" }
The response includes device_key once. Rotate it with POST /v1/devices/{id}/key.
Types: roost, bolus, tag, band, guardian, water, weather, reader, other.
Report
POST https://ingest.roots.sh/ingest
Authorization: Bearer rd_…
{
"readings": [
{ "metric": "climate.nh3_ppm", "value": 11 },
{ "metric": "feed.bin_pct", "value": 64, "at": "2026-10-18T06:00:00Z" }
],
"state": { "floor": "retracted" },
"events": [{ "type": "predator.detected", "data": { "kind": "a coyote", "door": 5 } }],
"battery": 81,
"firmware": "1.0.3"
}
https://api.roots.sh/v1/ingest takes the same request. Send up to 1,000 readings per report. at defaults to now. state merges into the device’s stored state.
The response carries any commands waiting for the device:
{ "ok": true, "accepted": 2, "commands": [{ "id": "cmd_…", "command": "doors.close", "params": { "doors": "all" } }] }
Report the result when it’s done:
POST /v1/device/commands/{id}
{ "status": "done", "result": { "closed": 14 } }
A device that reports rarely can poll GET /v1/device/commands instead.
Try it without hardware:
roots simulate rd_… --count 5
Metrics
| Metric | Unit | What |
|---|---|---|
feed.bin_pct |
% | Feed left in the bin on the hitch platform. |
feed.dispensed_kg |
kg | Feed the augers delivered since the last report. |
water.tank_pct |
% | Header tank or trough level. |
water.used_l |
L | Water used since the last report. |
climate.temp_c |
°C | Air temperature at bird height (highest pod) or at the station. |
climate.humidity_pct |
% | Relative humidity. |
climate.nh3_ppm |
ppm | Ammonia at bird height (highest pod). |
climate.co2_ppm |
ppm | Carbon dioxide at bird height (highest pod). |
power.battery_pct |
% | House battery state of charge. |
power.solar_w |
W | Solar input from the roof. |
power.load_w |
W | Total electrical load. |
move.distance_m |
m | Distance moved since the last report. |
birds.inside |
birds | Birds counted inside by the door vision pods. |
body.temp_c |
°C | Body or rumen temperature. |
rumination.min |
min | Rumination minutes in the last report window. |
activity.index |
index | Activity relative to the animal’s own baseline (100 = normal). |
weight.kg |
kg | Weight from a scale head, matched to the animal by EID. |
water.flow_lpm |
L/min | Flow through the line or pump. |
rain.mm |
mm | Rain since the last report. |
wind.kph |
km/h | Wind speed. |
device.battery_pct |
% | Tracker or sensor battery. |
Send any other metric name too. Roots stores it; only the ones above have default alert rules.