Funktionen
Warte-Alarme
Waity ruft deinen Webhook auf, wenn die Live-Wartezeit eines Orts unter deinen Schwellenwert fällt, damit ein Agent nicht ständig nachfragen muss. Jeder Plan enthält sie, auch Free.
So funktioniert es
Erstelle einen Alarm für einen Ort mit einem Schwellenwert in Minuten und einem https-Webhook. Nach jedem minütlichen Einlesen prüft Waity die Orte, die gerade neue Messwerte bekommen haben, und sendet per POST einen signierten JSON-Body an deinen Webhook, wenn die Wartezeit am oder unter dem Schwellenwert liegt.
Ein Alarm liest dieselbe Live-Antwort wie GET /v1/places/{id}, widerspricht der API also nie. Er löst nur aus, wenn now.usable true ist, die Einheit Minuten ist und now.value höchstens under beträgt. Eine Untergrenze („über 60“), ein veralteter oder pausierter Wert, ein geschlossener Ort oder fehlende Daten lösen nie aus.
Einen Alarm erstellen
POST /v1/alerts mit einem API-Key und einem JSON-Body. Die Antwort ist der Alarm, mit seiner ID und dem Signatur-Secret. Das Secret wird nur einmal angezeigt: Speichere es dort, wo dein Webhook es lesen kann.
| Feld | Was es erwartet |
|---|---|
place_id | Ein Ort, eine Spur oder eine Abteilung. Ein Flughafen, ein Grenzübergang oder ein Klinikgelände hat keine einzelne Wartezeit, daher wird seine ID abgelehnt, mit den IDs seiner Spuren oder Abteilungen. |
under | Ganze Minuten, von 1 bis 600. |
webhook_url | Wohin Waity per POST sendet. Nur https; siehe die Regeln unten. |
repeat | false (Standard) löst einmal aus, danach steht der Alarm auf fired. true löst erneut aus, nachdem die Wartezeit über den Schwellenwert plus 5 Minuten gestiegen ist, höchstens einmal alle 30 Minuten. |
expires_at | Optional, ISO 8601. Standard sind 24 Stunden ab jetzt, höchstens 30 Tage. |
curl -X POST "https://api.waity.ai/v1/alerts" \
-H "X-Api-Key: $WAITY_API_KEY" \
-H "Content-Type: application/json" \
-d '{"place_id":"pl_nvk0wkb3ps","under":30,"webhook_url":"https://example.com/waity/webhook"}'
201Antwort
{
"id": "al_3k9qx2m7t4p8w1za",
"place": {
"id": "pl_nvk0wkb3ps",
"name": "Ysleta Passenger Vehicles, Standard",
"category": "border"
},
"under": 30,
"unit": "min",
"repeat": false,
"webhook_url": "https://example.com/waity/webhook",
"status": "armed",
"created_at": "2026-10-31T19:02:11Z",
"expires_at": "2026-11-01T19:02:11Z",
Regeln für Webhook-URLs
Damit Alarme keine privaten Netzwerke erreichen, lehnt Waity eine Webhook-URL ab, die:
- kein https auf dem Standardport (443) nutzt oder einen Benutzernamen oder ein Passwort enthält;
- eine IP-Adresse statt eines Hostnamens nutzt, sodass private, Loopback-, Link-Local- und Cloud-Metadaten-Adressen alle abgelehnt werden;
- localhost, einen einteiligen Namen oder einen privaten oder reservierten Namen wie .local, .internal, .lan oder .home.arpa nutzt;
- auf Waity selbst zeigt.
Waity löst selbst keine Namen auf und folgt nie einer Weiterleitung: Eine 3xx-Antwort zählt als fehlgeschlagene Zustellung.
Auflisten, abrufen und löschen
GET /v1/alerts liefert deine Alarme, die neuesten zuerst, mit Status und letzter Zustellung. Die Keys eines Kontos teilen sich eine Liste; ein Key ohne Konto hat seine eigene. GET /v1/alerts/{id} ruft einen ab, und DELETE /v1/alerts/{id} löscht ihn und beendet seine Zustellungen.
curl
curl "https://api.waity.ai/v1/alerts" \
-H "X-Api-Key: $WAITY_API_KEY"
curl -X DELETE "https://api.waity.ai/v1/alerts/al_3k9qx2m7t4p8w1za" \
-H "X-Api-Key: $WAITY_API_KEY"
| Status | Was es erwartet |
|---|---|
armed | Wartet darauf, dass die Wartezeit unter den Schwellenwert fällt. |
fired | Ein einmaliger Alarm, der ausgelöst hat. |
expired | Sein expires_at ist verstrichen, ohne dass er ausgelöst hat. |
failing | Der letzte Zustellversuch ist fehlgeschlagen; siehe last_delivery. Weitere Versuche folgen, solange welche übrig sind. |
disabled | 20 fehlgeschlagene Zustellversuche in Folge. Erstelle einen neuen Alarm, sobald dein Webhook funktioniert. |
Der Webhook
Jede Zustellung ist ein POST mit einem JSON-Body. Lies dem Nutzer zuerst warnings vor, dann summary. now.value gilt bis now.usable_until; frag danach erneut GET /v1/places/{id} ab.
POST
{
"type": "wait.under",
"alert": {
"id": "al_3k9qx2m7t4p8w1za",
"under": 30
},
"place": {
"id": "pl_nvk0wkb3ps",
"name": "Ysleta Passenger Vehicles, Standard",
"category": "border",
"url": "https://waity.ai/places/ysleta-passenger-vehicles-standard-kb3ps"
},
"now": {
"value": 25,
"unit": "min",
"measured_at": "2026-10-31T13:58:00-06:00",
"usable_until": "2026-10-31T15:28:00-06:00",
"basis": "estimate"
},
"summary": "About 25 min to enter the US, estimated by the border agency, updated 2 min ago.",
"warnings": [],
"links": {
"place": "https://api.waity.ai/v1/places/pl_nvk0wkb3ps",
"page": "https://waity.ai/places/ysleta-passenger-vehicles-standard-kb3ps",
"alert": "https://api.waity.ai/v1/alerts/al_3k9qx2m7t4p8w1za",
"docs": "https://waity.ai/docs/alerts"
}
}
Jede Anfrage trägt diese Header:
Waity-Signature: t=<unix>,v1=<hex>:tist der Zeitpunkt der Signatur in unix-Sekunden;v1ist der HMAC-SHA256 der Zeichenkette aust, einem Punkt und dem Roh-Body, mit dem ganzen Secret des Alarms als Schlüssel.Waity-Alert: die ID des Alarms.Waity-Delivery: die ID der Zustellung, bei jedem neuen Versuch dieselbe, damit du Duplikate verwerfen kannst.
Die Signatur prüfen
Prüfe die Signatur über die Rohbytes, bevor du das JSON parst, vergleiche in konstanter Zeit und lehne ein t ab, das älter als 5 Minuten ist.
import crypto from "node:crypto";
import express from "express";
const app = express();
const secret = process.env.WAITY_ALERT_SECRET; // whsec_…
// The raw body: the signature covers the exact bytes Waity sent.
app.post("/waity/webhook", express.raw({ type: "application/json" }), (req, res) => {
const parts = Object.fromEntries(
(req.get("Waity-Signature") ?? "").split(",").map((p) => p.split("=", 2)),
);
const expected = crypto
.createHmac("sha256", secret)
.update(`${parts.t}.${req.body}`)
.digest("hex");
const fresh = Math.abs(Date.now() / 1000 - Number(parts.t)) <= 300;
const ok =
fresh &&
typeof parts.v1 === "string" &&
parts.v1.length === expected.length &&
crypto.timingSafeEqual(Buffer.from(parts.v1), Buffer.from(expected));
if (!ok) return res.status(400).end();
const event = JSON.parse(req.body);
// Read event.warnings first, then event.summary.
res.status(204).end();
});
app.listen(3000);
Wiederholungen
Antworte innerhalb von 10 Sekunden mit einem beliebigen 2xx. Alles andere ist ein fehlgeschlagener Versuch, der etwa 1, 5, 25 Minuten später wiederholt wird. Nach 20 fehlgeschlagenen Versuchen in Folge wird der Alarm deaktiviert.
Limits pro Plan
Jeder Plan erlaubt eine bestimmte Zahl aktiver Alarme gleichzeitig. Einer mehr wird mit 409 alert_limit beantwortet, mit einer Meldung, die das Limit deines Plans nennt. Jede Alarm-Anfrage zählt als ein Aufruf; Zustellungen zählen nie. Ein Key ohne Konto zählt als Free.
| Plan | Aktive Alarme |
|---|---|
| Free | 1 |
| Plus | 10 |
| Pro | 100 |
| Team | 1.000 |
Notaufnahme und Urgent Care
Bei Alarmen für Notaufnahmen und Urgent Care ist warnings[0] jeder Zustellung die 911-Zeile, einmal gesagt, wie bei jeder Notaufnahme-Antwort.
Siehe auch
Später sagt anhand des Verlaufs, wann eine Wartezeit fallen sollte. Eine Antwort lesen erklärt jedes Feld, und jedes Feld steht in der API-Referenz.