{"openapi":"3.1.0","info":{"title":"Alarmierung — Agenten-API","version":"1.0.0","description":"Alarme auslösen und deren Zustellung verfolgen.\n\nAuthentifizierung: API-Schlüssel im Header `X-Api-Key` (alternativ `?key=` für Aufrufer, die keine Header setzen können).\n\nSchlüssel haben zwei Stufen: `trigger` darf nur auslösen, `read` darf zusätzlich lesen. Die Stufe wird beim Anlegen in der App gewählt und kann später nicht geändert werden."},"servers":[{"url":"https://alarm.indigoblue.at"}],"components":{"securitySchemes":{"apiKey":{"type":"apiKey","in":"header","name":"X-Api-Key"}}},"security":[{"apiKey":{}}],"paths":{"/alarm":{"post":{"operationId":"alarmAusloesen","summary":"Alarm an alle aktiven Geräte des Kontos senden","description":"Lässt alle gekoppelten Geräte klingeln, bis ein Mensch quittiert. Nur für echte Ereignisse verwenden. Erforderliche Stufe: trigger.","requestBody":{"required":true,"content":{"application/json":{"schema":{"type":"object","required":["title"],"properties":{"title":{"type":"string","maxLength":200,"description":"Kurze Überschrift, erscheint groß auf dem Alarmschirm"},"message":{"type":"string","maxLength":2000,"description":"Zusatztext, etwa Ort und Ursache"},"group":{"type":"string","description":"Name oder Kennung einer Alarmgruppe; ohne Angabe geht der Alarm an alle Geräte des Kontos"},"level":{"type":"string","enum":["voll","leise","vibration"],"default":"voll","description":"Wie laut alarmiert wird: voll durchbricht Lautlos, leise spielt gedämpft und respektiert den Stummschalter, vibration lässt das Gerät nur vibrieren."}}}}}},"responses":{"200":{"description":"Alarm angenommen","content":{"application/json":{"schema":{"type":"object","properties":{"alarmId":{"type":"string"},"sent":{"type":"integer","description":"Erreichte Geräte"},"failed":{"type":"array","description":"Geräte, deren Push abgelehnt wurde","items":{"type":"object","properties":{"deviceId":{"type":"string"},"error":{"type":"string"}}}}}}}}},"401":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"429":{"description":"Zu viele Alarme (10 pro Minute je Konto)"}}},"get":{"operationId":"alarmAusloesenPerLink","summary":"Alarm über einen einfachen Link auslösen","description":"Gleiche Wirkung wie POST /alarm, für Aufrufer ohne JSON-Unterstützung. Achtung: Der Schlüssel steht dabei in der URL. Erforderliche Stufe: trigger.","parameters":[{"name":"key","in":"query","schema":{"type":"string"},"description":"API-Schlüssel, falls kein Header gesetzt werden kann"},{"name":"title","in":"query","schema":{"type":"string"}},{"name":"message","in":"query","schema":{"type":"string"}},{"name":"group","in":"query","schema":{"type":"string"},"description":"Alarmgruppe (Name oder Kennung); ohne Angabe an alle Geräte"},{"name":"level","in":"query","schema":{"type":"string","enum":["voll","leise","vibration"],"default":"voll"},"description":"Lautstärke-Stufe des Alarms"}],"responses":{"200":{"description":"Alarm angenommen"},"401":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/alarm/{id}/cancel":{"post":{"operationId":"alarmEntwarnen","summary":"Alarm entwarnen (zurückziehen)","description":"Beendet das Klingeln auf allen Geräten; die Empfänger bekommen eine kurze, leise Mitteilung „Entwarnung\". Idempotent. Erforderliche Stufe: trigger.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Alarm-ID aus der Antwort von POST /alarm"}],"responses":{"200":{"description":"Entwarnt","content":{"application/json":{"schema":{"type":"object","properties":{"ok":{"type":"boolean"},"cancelled":{"type":"boolean"},"notified":{"type":"integer","description":"Geräte, die die Entwarnung erreicht hat"}}}}}},"401":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}},"404":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/alarm/status":{"get":{"operationId":"alarmeAuflisten","summary":"Die letzten 20 Alarme des Kontos","description":"Neueste zuerst, mit Zählern für zugestellt und bestätigt. Erforderliche Stufe: read.","responses":{"200":{"description":"Liste","content":{"application/json":{"schema":{"type":"object","properties":{"alarms":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"message":{"type":"string"},"source":{"type":"string","enum":["app","api"],"description":"Ausgelöst aus der App oder über die API"},"triggered_by":{"type":"string","nullable":true},"created_at":{"type":"string","description":"UTC, Format YYYY-MM-DD HH:MM:SS"},"cancelled_at":{"type":"string","nullable":true,"description":"Gesetzt, wenn der Alarm entwarnt wurde"},"targets":{"type":"integer","description":"Angeschriebene Geräte"},"sent":{"type":"integer"},"delivered":{"type":"integer"},"confirmed":{"type":"integer","description":"Geräte, an denen ein Mensch übernommen hat"},"declined":{"type":"integer","description":"Geräte, an denen jemand „Kann nicht\" gedrückt hat"}}}}}}}}},"403":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/alarm/status/{id}":{"get":{"operationId":"alarmStatus","summary":"Zustellstatus eines Alarms je Gerät","description":"Zeigt für jedes Gerät, ob der Alarm angekommen ist und ob quittiert wurde. Damit lässt sich nachverfolgen, ob jemand reagiert hat. Erforderliche Stufe: read.","parameters":[{"name":"id","in":"path","required":true,"schema":{"type":"string"},"description":"Alarm-ID aus der Antwort von POST /alarm"}],"responses":{"200":{"description":"Status","content":{"application/json":{"schema":{"type":"object","properties":{"id":{"type":"string"},"title":{"type":"string"},"message":{"type":"string"},"createdAt":{"type":"string"},"cancelledAt":{"type":"string","nullable":true,"description":"Gesetzt, wenn der Alarm entwarnt wurde"},"triggeredBy":{"type":"string","nullable":true},"confirmedCount":{"type":"integer"},"declinedCount":{"type":"integer"},"deviceCount":{"type":"integer"},"deliveries":{"type":"array","items":{"type":"object","properties":{"device_name":{"type":"string"},"sent_at":{"type":"string","nullable":true},"fcm_error":{"type":"string","nullable":true,"description":"Gesetzt, wenn der Push nicht angenommen wurde"},"delivered_at":{"type":"string","nullable":true,"description":"Gerät hat den Alarm empfangen"},"confirmed_at":{"type":"string","nullable":true,"description":"Nutzer hat übernommen"},"declined_at":{"type":"string","nullable":true,"description":"Nutzer hat „Kann nicht\" gedrückt"}}}}}}}}},"404":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/alarm/devices":{"get":{"operationId":"geraeteAuflisten","summary":"Gekoppelte Geräte des Kontos","description":"Stillgelegte Geräte haben disabled = 1 und bekommen keine Alarme; disabledReason nennt den Grund. Koppeln bleibt über der Tarifgrenze erlaubt — die überzähligen Geräte kommen stillgelegt herein (disabledReason = limit). Erforderliche Stufe: read.","responses":{"200":{"description":"Geräteliste","content":{"application/json":{"schema":{"type":"object","properties":{"devices":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"platform":{"type":"string","enum":["android","ios"]},"joined_via":{"type":"string","enum":["login","join_code"]},"disabled":{"type":"integer","enum":[0,1]},"disabledReason":{"type":"string","nullable":true,"enum":["limit","manual","unreachable",null],"description":"limit = über der Tarifgrenze, manual = vom Verwalter stillgelegt, unreachable = App abgemeldet; null = aktiv"},"last_seen_at":{"type":"string","nullable":true},"created_at":{"type":"string"}}}},"deviceLimit":{"type":"integer","description":"0 = unbegrenzt"},"activeCount":{"type":"integer"}}}}}},"403":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/alarm/groups":{"get":{"operationId":"gruppenAuflisten","summary":"Alarmgruppen des Kontos","description":"Name oder Kennung lassen sich beim Auslösen als group angeben. Erforderliche Stufe: read.","responses":{"200":{"description":"Gruppenliste","content":{"application/json":{"schema":{"type":"object","properties":{"groups":{"type":"array","items":{"type":"object","properties":{"id":{"type":"string"},"name":{"type":"string"},"sound":{"type":"string","description":"Alarmton der Gruppe"},"deviceCount":{"type":"integer","description":"Zahl der zugeordneten Geräte"}}}}}}}}},"403":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/alarm/account":{"get":{"operationId":"kontoLesen","summary":"Tarif, Gerätelimit und Verschlüsselung des Kontos","description":"deviceLimit = 0 bedeutet unbegrenzt. Erforderliche Stufe: read.","responses":{"200":{"description":"Konto","content":{"application/json":{"schema":{"type":"object","properties":{"accountId":{"type":"string"},"name":{"type":"string"},"plan":{"type":"string","enum":["free","devices_5","devices_10","devices_unlimited"]},"deviceLimit":{"type":"integer"},"deviceCount":{"type":"integer"},"activeDeviceCount":{"type":"integer"},"encryptionEnabled":{"type":"boolean"}}}}}},"403":{"description":"Fehler","content":{"application/json":{"schema":{"type":"object","properties":{"error":{"type":"string"}}}}}}}}},"/health":{"get":{"operationId":"dienstPruefen","summary":"Erreichbarkeit des Dienstes prüfen","security":[],"responses":{"200":{"description":"Dienst läuft"}}}}}}