Device Ingest API#
Self Hosted Cloud Hosted
This page covers the public device-ingest endpoints only — the ones a device firmware author or integrator needs. The full internal API (batches, taps, vessels, devices, auth, admin, etc.) is not repeated here.
On the hosted service, devices post to ingest.brewgraph.com. Use the URL the app shows
when you add a device (for example https://ingest.brewgraph.com/ingest/ispindel); the
/api/ingest/... paths below work there too. HTTPS is the default; plain http:// is
accepted for firmware that cannot do TLS.
Authentication#
Each device is issued its own token at registration time. The token is included in the request payload (field name varies slightly per endpoint — see below), not as a bearer header — this lets devices authenticate without implementing OAuth/JWT in constrained firmware.
Ingest endpoints#
Endpoint |
Device |
Notes |
|---|---|---|
|
iSpindel |
Native iSpindel JSON payload |
|
TiltBridge (Tilt Hydrometer) |
TiltBridge generic JSON payload; Cloud Hosted only. The token goes in the address |
|
GravityMon |
GravityMon-native payload format |
|
PressureMon |
Pressure, temperature, battery, and signal strength; available on Cloud Hosted |
|
KegMon |
Pour detection pulses. Coming soon to Cloud Hosted; not available in the beta |
|
KegMon |
Beer-assignment and pour-report payloads. Coming soon to Cloud Hosted; not available in the beta |
|
Any supported ingest device |
Detects the compatible payload shape and routes it to the appropriate handler |
Request examples#
These gravity device examples work in the Cloud Hosted beta. Replace
YOUR-DEVICE-TOKEN with the token shown when you registered the device, and
use the exact URL the app shows for that device. On the hosted service the URL
starts with https://ingest.brewgraph.com. Every request returns 200 with
no body on success. An unknown token returns 401, a request sent too soon
after the device’s plan interval returns 429, and a value that cannot be
stored returns 422.
Measurements are stored as sent: numeric values are not range-checked or clamped, so negative
pressure is accepted. A request returns 422 when its body cannot be parsed, a required value
is missing, a number is not finite, or a unit is unsupported. Unit names are case-insensitive.
An omitted optional field is shown as empty, not as zero. Negative volume is rejected with the
field name in the ingestion log. On Self Hosted, a KegMon volume above vessel capacity is stored
and raises the vessel capacity to match.
Battery voltage and percentage are stored independently and shown independently when present;
neither is calculated from the other. Reading responses expose them as batteryVoltage and
batteryPercent. When enabled, a native RAPT Pill reports gravity as specific gravity
(SG) and battery as a percentage.
The token can go in the JSON body as token, in ?token=, or in the
path (/ingest/<device>/<token>) for gravity, pressure, and temperature
devices (iSpindel, GravityMon, PressureMon). If the body also has a token, the
body wins. TiltBridge has no token field in its payload, so it takes the token
only as ?token= or in the path. The examples use a placeholder,
never a real token. The device ID is
accepted but can never authenticate a request on the hosted service. Fields not
listed as stored are ignored.
GravityMon#
curl -X POST https://ingest.brewgraph.com/ingest/gravitymon \
-H "Content-Type: application/json" \
-d '{
"name": "Gravitymon_01",
"ID": "12345678",
"token": "YOUR-DEVICE-TOKEN",
"angle": 42.15,
"temperature": 19.5,
"temp_units": "C",
"battery": 4.12,
"gravity": 1.045,
"corr-gravity": 1.044,
"gravity-unit": "G",
"velocity": -1.5,
"interval": 900,
"RSSI": -65,
"run-time": 2.14
}'
gravity-unitmust beG(specific gravity).P(Plato) is rejected with422.temp_unitsmust beCorF; any other value is rejected with422. Fahrenheit is converted to Celsius. If you leave it out, Celsius is assumed.corr-gravityis deliberately ignored: BrewGraph records the raw gravity value.nameandintervalare accepted but not stored.
iSpindel#
curl -X POST https://ingest.brewgraph.com/ingest/ispindel \
-H "Content-Type: application/json" \
-d '{
"name": "[SG] iSpindel",
"ID": 13065051,
"token": "YOUR-DEVICE-TOKEN",
"angle": 66.79,
"temperature": 20.56,
"temp_units": "C",
"battery": 4.13,
"gravity": 1.045,
"interval": 900,
"RSSI": -77
}'
In the iSpindel firmware, set the device name to start with the exact prefix
[SG]. The iSpindel’s calibration must output specific gravity. BrewGraph does not guess the scale from the number.temp_unitsfollows the same rule as for GravityMon.nameandintervalare accepted but not stored.
TiltBridge (Tilt Hydrometer)#
Cloud Hosted only. TiltBridge posts its generic JSON payload. The token is part
of the address, as ?token= or as the last path segment.
curl -X POST https://ingest.brewgraph.com/ingest/tiltbridge/YOUR-DEVICE-TOKEN \
-H "Content-Type: application/json" \
-d '{
"name": "Red",
"temp": "68.5",
"temp_unit": "F",
"gravity": "1.050",
"gravity_unit": "G",
"device_source": "TiltBridge"
}'
gravityis required, as a number or a numeric string.gravity_unitisG(specific gravity) orP(Plato, converted to specific gravity); if you leave it out,Gis assumed.tempis optional.temp_unitisCorF(Fahrenheit is converted to Celsius); if you leave it out, Celsius is assumed.Unit letter case is ignored. Any other unit is rejected with
422.name(the Tilt’s colour) anddevice_sourceare accepted and ignored: the device is the one the token belongs to.A request without a valid token returns
401.
KegMon#
Coming soon to Cloud Hosted; not available in the beta. KegMon sends a pour
event, or a level event after the measured volume is stable, to
/ingest/kegmon. Volumes are in litres.
{
"token": "YOUR-TAP-TOKEN",
"pour": 0.35,
"volume": 14.2,
"maxVolume": 19.0,
"temperature": 4.2
}
temperature(°C) is optional on both the pour and the level event. On Cloud Hosted it is stored as the keg’s temperature and shows in the keg’s temperature chart. It never changes what the event does: the pour and the level are stored whether it is present, missing, or invalid.On Cloud Hosted, a pour or level report for a tap with no keg on it is accepted and ignored: nothing is stored.
On Cloud Hosted, a tap accepts at most 20 pour reports per minute.
See Devices for the full per-device setup guide (calibration for gravity sensors, etc.) — this page is just the wire protocol reference.