WaterTDS Partner API

REST API for accessing customer, device, and alert data within your hierarchy

Implementation vs Specification

This implementation differs from the original API Specification (private):

AspectSpecificationImplementation
URL prefix /api/v1/ /customer/external/v1/ (customers, contacts)
/product/external/v1/ (devices, alerts)
Authentication Authorization: Bearer {key} Authorization: Api-Key {key}

Authentication

All API requests require an API Key in the Authorization header:

Authorization: Api-Key <your-api-key>
Note: Your API key determines which data you can access. You will only see customers, contacts, devices, and alerts within your company hierarchy.

Internal: How to create API keys (private)

API Endpoints

Customer Service

MethodEndpointDescription
GET /customer/external/v1/customers/ List customers
GET /customer/external/v1/customers/{id}/ Get customer details
GET /customer/external/v1/contacts/ List contacts
GET /customer/external/v1/contacts/{id}/ Get contact details

Product Service

MethodEndpointDescription
GET /product/external/v1/devices/ List devices
GET /product/external/v1/devices/{id}/ Get device details
GET /product/external/v1/devices/{id}/cartridges/ Get device cartridges
GET /product/external/v1/alerts/ List alerts
GET /product/external/v1/alerts/{id}/ Get alert details

Filters

Customers

ParameterExampleDescription
customer_type?customer_type=DEALERFilter by type
is_active?is_active=trueFilter by status
associated_with?associated_with=123Filter by parent ID

Contacts

ParameterExampleDescription
customer_id?customer_id=123Filter by customer
is_active?is_active=trueFilter by status

Devices

ParameterExampleDescription
customer_id?customer_id=123Filter by customer
is_installed?is_installed=trueFilter by installation status

Alerts

ParameterExampleDescription
device_id?device_id=123Filter by device
customer_id?customer_id=123Filter by customer
date?date=2024-01-15Filter by specific date
date_from / date_to?date_from=2024-01-01&date_to=2024-01-31Filter by date range
alert_type?alert_type=INPUT_TDSFilter by alert type

Alert Types

TypeDescription
INPUT_TDSInput water TDS exceeded threshold
OUTPUT_TDSOutput water TDS exceeded threshold
TDS_VARIABILITYTDS variability threshold exceeded
TEMPERATURE_HIGHHigh temperature alert
TEMPERATURE_LOWLow temperature alert
FLOW_RATEFlow rate below threshold
RO_REJECTIONRO rejection ratio below threshold
DAILY_VOLUMEDaily volume threshold exceeded
TOTAL_VOLUMETotal volume threshold exceeded
CARTRIDGE_MANUFACTURERManufacturer suggested replacement
CARTRIDGE_CALCULATEDCalculated replacement needed
WIFI_CONNECTIONWiFi connectivity issue

Webhooks (Push Alerts)

Instead of polling the alerts endpoint, you can receive alerts as push notifications. When an alert triggers for one of your devices, WaterTDS sends an HTTP POST to an HTTPS endpoint you configure. It is the same set of alert events you get by email — the event toggles decide what is sent, the webhook switch decides whether it is also pushed to your endpoint.

Configuration

Set up in the WaterTDS B2B admin (Company → Notifications):

Request

POST <your endpoint>
Content-Type: application/json
Authorization: Bearer <your secret>
X-WTDS-Event-Id: <uuid>     # unique per event; use for idempotency
Authentication: verify the Authorization header equals Bearer <your secret> (constant-time compare) before processing; reject others with 401.

Body

{
  "event_types": ["daily_thresholds_alerts"],
  "event_id": "63679b4d-1ac3-426d-8d9e-e3f95888998e",
  "company_id": 94,
  "device_id": 315,
  "timestamp": "2026-06-29T14:35:49.825388+00:00",
  "data": {
    "device_id": 315,
    "user": "Acme Water Co",
    "label": "Kitchen RO",
    "model": "RO-500",
    "manufacturer": "Acme",
    "install_date": "2022-11-02",
    "address_1": "...", "city": "...", "state": "...", "zip_code": "...",
    "alert_messages": [
      "The TDS level of the output is greater than 51 ppm. You had set up this alert."
    ]
  }
}
FieldTypeDescription
event_typesstring[]Which alert types this delivery covers
event_idstring (uuid)Idempotency key (also in X-WTDS-Event-Id)
company_idintYour WaterTDS company id
device_idintDevice that triggered the alert
timestampstring (ISO-8601, UTC)When the alert was generated
data.alert_messagesstring[]Human-readable alert message(s)

event_types values: monthly_quality_report, calculation_based_alerts, manufacturer_suggested_alerts, daily_thresholds_alerts, hourly_thresholds_alerts.

Response & Retries

Idempotency: deliveries may repeat. Deduplicate on event_id — if already processed, return 2xx and ignore.

Example receiver (Flask)

import hmac
from flask import Flask, request, abort

SECRET = "your-secret-from-the-admin"
seen = set()
app = Flask(__name__)

@app.post("/wtds-webhook")
def hook():
    if not hmac.compare_digest(request.headers.get("Authorization", ""), f"Bearer {SECRET}"):
        abort(401)
    event = request.get_json()
    if event["event_id"] in seen:      # idempotency
        return "", 200
    seen.add(event["event_id"])
    for msg in event["data"].get("alert_messages", []):
        print(event["device_id"], event["event_types"], msg)
    return "", 200

Pagination

All list endpoints support pagination:

ParameterDefaultDescription
page1Page number
page_size10Items per page (max: 100)

Response format:

{
  "count": 50,
  "next": "https://api.watertds.com/.../devices/?page=2",
  "previous": null,
  "results": [...]
}

Example Requests

List Customers

curl -X GET "https://api.watertds.com/customer/external/v1/customers/" \
  -H "Authorization: Api-Key <your-api-key>"

List Devices for Customer

curl -X GET "https://api.watertds.com/product/external/v1/devices/?customer_id=123" \
  -H "Authorization: Api-Key <your-api-key>"

Get Alerts for Today

curl -X GET "https://api.watertds.com/product/external/v1/alerts/?date=2024-01-15" \
  -H "Authorization: Api-Key <your-api-key>"

Data Access

Your API key is linked to a customer account. You can only access:

Important: You cannot access data outside your hierarchy.