This guide explains how to send normalized external monitoring data into LumeLevel using the External Monitoring HTTP endpoint. It is intended for gateway developers, partner integrators, and advanced installers.
This integration allows an outside monitoring system, site gateway, or partner bridge to send normalized tank updates into LumeLevel over HTTP.
Distance: the source is reporting the distance from the sensor to the product or water surface.
Level: the source is reporting the liquid depth or level. LumeLevel converts that to distance using the configured sensor height.
Method: POST
Endpoint: /external-monitoring/report
Content-Type: application/json
Headers required:
X-Integration-KeyX-Integration-SecretThe payload uses five top-level sections: source, target, event, readings, and discrete/health.
{
"source": {
"vendor": "PartnerGateway",
"siteId": "SITE-123",
"deviceId": "EXT-001",
"messageId": "reserve-level-001",
"sentAt": "2026-04-18T03:52:00Z"
},
"target": {
"deviceSerialNumber": "0E001146"
},
"event": {
"eventType": "periodic"
},
"readings": {
"main": {
"value": 932.1038,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
},
"reserve": {
"value": 450.0,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
}
},
"discrete": {
"tankTopState": "closed",
"valid": true
},
"health": {
"sourceFault": false,
"sourceStale": false
}
}
| Field | Meaning | Notes |
|---|---|---|
source.vendor |
Partner or gateway name | Used as part of duplicate detection |
source.siteId |
Partner site identifier | Used as part of duplicate detection |
source.deviceId |
Partner source device identifier | Used as part of duplicate detection |
source.messageId |
Unique message identifier | Required for idempotency |
target.deviceSerialNumber |
LumeLevel target device | Must already exist in the platform |
readings.*.value |
Reading value | v1 partner support is mm only |
readings.*.units |
Units code | mm |
readings.*.kind |
distance or level |
Controls how LumeLevel normalizes the reading |
readings.*.valid |
Reading validity | If false, the reading will not be persisted |
readings.*.ageSec |
Reading age in seconds | Used with stale acceptance rules |
discrete.tankTopState |
open or closed |
Logged as event state |
health.sourceFault |
Source fault flag | If true, readings are status-only |
health.sourceStale |
Source stale flag | If true, readings are status-only |
periodicreading_changetank_opentank_closedfaultstalerecoveredstartupReserve readings are only persisted when the target device is configured to use reserve / second sensor. If a reserve value is supplied for a non-reserve device, it will not be persisted.
LumeLevel uses the combination of vendor, site ID, device ID, and message ID as the idempotency key.
| Code | Meaning | Typical use |
|---|---|---|
1101 |
Accepted and processed | At least one accepted reading was persisted |
1100 |
Accepted as status-only event | Fault, stale, invalid, or otherwise not accepted for persistence |
1102 |
Duplicate ignored | The same idempotency key was already processed |
1001 |
POST required | Wrong HTTP method |
1002 |
Invalid JSON payload | Malformed body |
1003 |
Missing target device | target.deviceSerialNumber not supplied |
1004 |
Target device not found | Serial not found in the system |
1005 |
Device metadata not found | Associated metadata missing |
1006 |
Processing error | Internal failure during processing |
LumeLevel uses the device timezone when storing device-local dates and times. This is intentional because the physical device may be installed in a different timezone than the user account.
Partner sentAt timestamps should be supplied in UTC.
Accepted and status-only events are written to ExternalIntegrationEvent.
Duplicate requests are ignored and do not create a second event row in v1.
{
"source": {
"vendor": "PartnerGateway",
"siteId": "SITE-123",
"deviceId": "EXT-001",
"messageId": "main-distance-001",
"sentAt": "2026-04-18T03:50:00Z"
},
"target": {
"deviceSerialNumber": "7602CA7E41"
},
"event": {
"eventType": "periodic"
},
"readings": {
"main": {
"value": 932.1038,
"units": "mm",
"kind": "distance",
"valid": true,
"ageSec": 10
}
},
"discrete": {
"tankTopState": "closed",
"valid": true
},
"health": {
"sourceFault": false,
"sourceStale": false
}
}
{
"source": {
"vendor": "PartnerGateway",
"siteId": "SITE-123",
"deviceId": "EXT-001",
"messageId": "reserve-level-001",
"sentAt": "2026-04-18T03:52:00Z"
},
"target": {
"deviceSerialNumber": "0E001146"
},
"event": {
"eventType": "periodic"
},
"readings": {
"main": {
"value": 932.1038,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
},
"reserve": {
"value": 450.0,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
}
},
"discrete": {
"tankTopState": "closed",
"valid": true
},
"health": {
"sourceFault": false,
"sourceStale": false
}
}
{
"source": {
"vendor": "PartnerGateway",
"siteId": "SITE-123",
"deviceId": "EXT-001",
"messageId": "tank-open-001",
"sentAt": "2026-04-18T03:55:00Z"
},
"target": {
"deviceSerialNumber": "0E001146"
},
"event": {
"eventType": "tank_open"
},
"readings": {
"main": {
"value": 932.1038,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
},
"reserve": {
"value": 450.0,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
}
},
"discrete": {
"tankTopState": "open",
"valid": true
},
"health": {
"sourceFault": false,
"sourceStale": false
}
}
{
"source": {
"vendor": "PartnerGateway",
"siteId": "SITE-123",
"deviceId": "EXT-001",
"messageId": "stale-001",
"sentAt": "2026-04-18T03:57:00Z"
},
"target": {
"deviceSerialNumber": "0E001146"
},
"event": {
"eventType": "stale"
},
"readings": {
"main": {
"value": 932.1038,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
},
"reserve": {
"value": 450.0,
"units": "mm",
"kind": "level",
"valid": true,
"ageSec": 10
}
},
"discrete": {
"tankTopState": "closed",
"valid": true
},
"health": {
"sourceFault": false,
"sourceStale": true
}
}