Webhook duplicate handling — what's idempotent and what isn't
The webhook endpoint is idempotent for genuine retries: if your gateway sends the exact same request twice (same timestamp header, same body bytes), the second request returns 200 with a "deduplicated: true" marker and no data is double-counted. This makes "retry on network error" safe to implement on the gateway side.
What dedup catches
- Network blip → gateway retries the same POST a few seconds later. Same timestamp, same body, recognized as duplicate, no double-insert.
- Gateway buffering a payload, then sending it twice on reconnect. Same outcome.
What dedup does NOT catch (by design)
- The same meter reporting the same kWh value across two different cycles (e.g. zero-consumption hours on a cumulative meter, or a meter stuck at the same value because nothing's been consumed). The timestamp header differs between cycles, so the platform treats them as separate legitimate deliveries — which is correct, because they ARE separate deliveries.
- A captured payload replayed by an attacker. The signed timestamp must be within 5 minutes of server time, so older captures are rejected.
What gateways should do
- Always generate a fresh X-Webhook-Timestamp per delivery (Unix seconds at send time).
- Retry on transient network errors with the same timestamp and body for ~30 seconds, then generate a fresh delivery if still failing.
- Do not pre-sign payloads minutes or hours in advance — they will fail the 5-minute freshness window.
If you're investigating a "duplicate readings" complaint: dashboard double-counting is more often caused by two data sources feeding the same point_id (e.g. a CSV import and a webhook for the same meter) than by webhook dedup failing. Check whether the meter has multiple connected sources.