Corrections and re-delivery on push channels

If you store what a webhook or an MQTT connection delivers, write each reading with an upsert, never a plain insert. The same interval can arrive again with a better quality, and a second copy of a reading that already exists must replace it. This article describes when that happens and the key to use.

Why a reading arrives again

Grid operators improve readings after the fact. A value that first arrives as an unreliable estimate (L3) is replaced by a reliable one (L2 or L1); the grid operator has 60 days to do so. When the replacement arrives, it overwrites the stored reading, and the corrected record is delivered to your connection again. Automatic data retry asks the grid operator for such replacements, which can bring a correction sooner.

A reading can also arrive twice without having changed:

  • A webhook delivery that failed is retried, and your system may already have stored the first attempt.
  • You can resend a period from the delivery logs, see Delivery Logs & Errors.
  • MQTT messages are published with at-least-once delivery, so a broker or network retry can produce a duplicate.

The key to upsert on

A reading is identified by three values:

Part Webhook MQTT
Metering point smart_meter.metering_point_number The topic you configured (EnerChart) or the device you connected (ThingsBoard)
OBIS code obis_code of each record The topic (EnerChart) or the key inside values (ThingsBoard)
Interval start timestamp of each record (UTC) ts of the message

A correction carries the same three values as the original and a different value or data_quality. The example uses illustrative values:

JSON
{ "obis_code": "1-1:1.9.0 P.01", "timestamp": "2025-03-15T23:00:00Z", "timestamp_end": "2025-03-15T23:15:00Z", "value": 0.31, "data_quality": 3, "unit": "kWh" }
JSON
{ "obis_code": "1-1:1.9.0 P.01", "timestamp": "2025-03-15T23:00:00Z", "timestamp_end": "2025-03-15T23:15:00Z", "value": 0.285, "data_quality": 1, "unit": "kWh" }

Both records describe the same quarter-hour. The second one replaces the first.

What to do with each delivery

  1. Look up the reading by the three-part key.
  2. If it does not exist, insert it.
  3. If it exists, replace value and data_quality with the delivered ones.

The platform sends changed records in the order in which they changed, so applying deliveries in the order you receive them leaves the newest version. If your pipeline can process messages out of order, you can add a guard: do not replace a stored reading with one of worse quality, meaning a higher data_quality number. This is the same rule the platform applies to its own data, where a replayed L3 never overwrites a stored L1 or L2.

Because duplicates are possible, make the write idempotent. An upsert already is.

Details per channel

  • Webhook. A correction is a normal delivery. The event stays measurement.created, and nothing in the payload marks a record as corrected, so the key is the only way to recognise it. data_quality is part of every record: 1 measured, 2 estimated, 3 unreliable.
  • MQTT. The ThingsBoard and EnerChart payloads carry only the value and the timestamp. A corrected reading arrives as another message for the same timestamp, and the later message replaces the earlier one. Check how your target system treats a repeated timestamp for the same series.
  • CSV by email and SFTP. These files are built from the same changes, so a file can contain readings you received before, with better values.

Limits

  • A correction is delivered when the stored value or data_quality really changed. A repeated identical reading does not count as a change.
  • Corrections to intervals older than your plan's data retention are not delivered.
  • Deliveries cover the meter's own series. The separate figures per energy community are not part of them.
  • A correction arrives on the schedule of the connection, together with the next batch.

If you prefer to pull, the REST API serves the same revisions through its cursor.