AquaMeter AI can push real-time event notifications to your server. Configure endpoints from the Webhooks page in your dashboard.
Register an endpoint
Add your server URL and choose which events to subscribe to from the dashboard.
Event fires
When a reading completes, a usage threshold is hit, or a subscription changes, AquaMeter creates a delivery.
POST request sent
AquaMeter sends a signed POST request with a JSON payload to your endpoint.
You respond 200
Return HTTP 200 within 15 seconds to acknowledge receipt. Other status codes (including 201/202/204) are treated as failures and trigger a retry.
Retries on failure
Non-200 responses or timeouts are retried up to 3 times with delays of 1 min, 5 min, and 15 min.
reading.completedA meter image was successfully read.reading.failedA reading attempt failed or confidence was too low.usage.threshold_reachedMonthly usage has reached 80% of the plan limit.usage.limit_reachedMonthly request limit has been reached.subscription.createdA new subscription was started.subscription.cancelledA subscription was cancelled.subscription.expiredA subscription has expired.All webhook deliveries share the same envelope structure. The data field contains event-specific information.
{"event": "reading.completed","timestamp": "2026-04-28T14:32:00.000Z","data": {"reference_id": "9c7d3f2a-1e4b-4d5a-9b6c-1f2e3d4c5b6a","reading": "02390.276","confidence": 97,"unobstructed": true,"escalated": false,"reading_id": 142}}
reference_id is always present and matches the value returned in the API ack — use it to correlate the delivery with the request.reading_id is the persisted database row id and is present only when a reading was successfully extracted (omitted on reading.failed).
{"event": "usage.threshold_reached","timestamp": "2026-04-28T09:00:00.000Z","data": {"user_id": 5,"used": 200,"limit": 250}}
Content-Typeapplication/jsonX-AquaMeter-EventThe event name, e.g. reading.completedX-AquaMeter-Signaturesha256=<HMAC-SHA256 signature of the body>Each delivery is signed with your webhook's secret using HMAC-SHA256. Always verify the signature before processing the payload to ensure the request came from AquaMeter AI. Use a timing-safe comparison to prevent timing attacks.
import crypto from "crypto";
function verifySignature(rawBody: string, secret: string, header: string): boolean {
const expected = "sha256=" + crypto
.createHmac("sha256", secret)
.update(rawBody)
.digest("hex");
return crypto.timingSafeEqual(
Buffer.from(expected),
Buffer.from(header),
);
}Your endpoint must respond with HTTP 200 within 15 seconds. Process heavy work asynchronously — acknowledge receipt immediately and handle the payload in a background job. Note that 201/202/204 are currently treated as failures.