TRANXACT.AI Help

IoT meters: registering a device and how it signs its reads

IoT Devices: register an AMI or IoT endpoint, copy its secret (shown once), rotate it with New secret, and how the device signs each request to /api/public/utilities/iot/reads — with an example request, the limits and every answer it can get.

An AMI or IoT meter posts its own reads to TRANXACT over HTTPS. Each device has a key made by the server (utd_ followed by 24 letters and digits) and a secret. The device proves who it is on every request, so nobody else can post reads for that meter.

Registering a device

  1. Open CRM › Utilities › Utility Meters & Reads › IoT Devices and press New.
  2. Enter a Label, choose the Meter it reads, and choose Signs with: hmac (an HMAC-SHA256 signature of each request — recommended), bearer (the key and secret sent as a token) or both.
  3. Set Reads per minute at most for this device, and the Firmware if you know it.
  4. Save. The answer shows the key and the secret: “Copy the secret now — it is not shown again.” Put both into the device’s configuration.

The secret is shown once. It is never listed afterwards, not even to an administrator; the list shows only its last four characters (Secret ends). If it is lost, issue a new one.

Rotating the secret

On the device’s row press New secret and confirm. The new secret is shown once and the old one stops working at that moment, so give the device the new one straight away. Set Status to disabled to stop a device without rotating, or retired when it is taken out of service.

How a device signs a reading

  1. Build the JSON body: a list of reads, each with read_at (ISO 8601 time) and reading. Battery, signal, firmware and alarms are optional.
  2. Take the current Unix time in seconds as the timestamp.
  3. Compute HMAC-SHA256, under the device secret, of the timestamp, a full stop, and the exact bytes of the body: “<timestamp>.<body>”. Write it as 64 lower-case hex characters.
  4. POST the body to /api/public/utilities/iot/reads with the headers X-Utility-Device (the key), X-Utility-Timestamp and X-Utility-Signature (the hex, optionally prefixed sha256=).
POST https://<your-tranxact-host>/api/public/utilities/iot/reads
Content-Type: application/json
X-Utility-Device: <utd_DEVICE_KEY>
X-Utility-Timestamp: <1792252800>
X-Utility-Signature: sha256=<64 hex characters>

{"reads":[{"read_at":"<2026-10-17T09:30:00Z>","reading":<48213.4>}],
 "battery_pct":<87>,"signal_dbm":<-71>,"firmware":"<2.4.1>",
 "alarms":[{"type":"<leak>","detail":"<continuous flow 6 h>"}]}

The same signature worked out in a shell, to test a device before it is installed:

BODY='{"reads":[{"read_at":"<2026-10-17T09:30:00Z>","reading":<48213.4>}]}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "<DEVICE_SECRET>" | sed 's/^.* //')
curl -X POST "https://<your-tranxact-host>/api/public/utilities/iot/reads" \
  -H "Content-Type: application/json" \
  -H "X-Utility-Device: <utd_DEVICE_KEY>" \
  -H "X-Utility-Timestamp: $TS" \
  -H "X-Utility-Signature: sha256=$SIG" \
  --data-binary "$BODY"

Sign the exact bytes you send. Re-formatting the JSON after signing, or sending it with a different line ending, changes the bytes and the signature no longer matches.

A device set to bearer (or both) may instead send Authorization: Bearer <utd_DEVICE_KEY>.<DEVICE_SECRET> and no signature headers. HMAC is the safer choice: the secret never travels and a captured request cannot be replayed.

Limits

  • The timestamp must be within 5 minutes of the server’s clock: keep the device’s clock set by NTP.
  • The same signed request twice is refused as a replay. A read already on file is counted as a duplicate and stored once.
  • At most 64 KB and 500 reads a request, the device’s own Reads per minute at most, and 600 requests a minute from one address.
  • The device must be active and attached to a meter.

What the device gets back

AnswerMeaning
201 or 200 with accepted, duplicates, exceptions, rejected, alarms and problemsThe request was taken. Each read is counted; problems names any read that was not valid by its index.
401 device_authUnknown or inactive key, wrong mode, or a signature that does not match. The device’s Refused count goes up.
401 stale_timestampThe timestamp is more than 5 minutes off.
409 replayThis signed request was already received.
413 too_many_readsMore than 500 reads in one request.
422 no_meterThe device is not attached to a meter.
429 rate_limitedSending faster than its limit. Wait and send again.
400 bad_jsonThe body is not JSON.
403 utilities_offUtilities is switched off for the company.

Health and alarms

  • Each request updates the device’s Last seen, Battery % and Signal dBm. A battery under 15% raises a battery_low alarm.
  • Alarm types a device may send: battery_low, tamper, leak, reverse_flow, no_flow, offline and other. One open alarm of each kind per device.
  • Device Alarms lists them; Clear closes one with a note. A leak raises a high-priority leak investigation service order by itself; a tamper or reverse_flow alarm raises a service order too.
  • The dashboard’s IoT meters reporting (24h) figure counts the active devices heard from in the last day.