❮  Integrationen

Webhook-Spezifikation

Entrixy sendet einen Befehl zum Öffnen oder Schließen an Ihre Adresse und signiert ihn. Hier finden Sie das Anfrageformat und die Prüfung der Signatur, damit Sie den Befehl in Ihrem eigenen Dienst, Smart Home oder auf Ihrer Platine annehmen können.

Ein Webhook ist der Modus, in dem nicht unser Controller öffnet, sondern Ihr eigenes System: Home Assistant, ein Relais im lokalen Netz, Ihr eigener Server. Ein Webhook-Objekt sendet in beiden Modi dieselbe signierte Anfrage. Von Ihrem Telefon: Das Telefon des Besitzers sendet sie, Adresse und Geheimnis verlassen das Telefon nie. Vom Entrixy-Server: Unser Server sendet sie und speichert deshalb Adresse und Geheimnis. Fertige Empfänger: curl, Flask, Home Assistant.

Die Anfrage

Bei einem Tippen sendet Entrixy einen POST an Ihre webhook_url mit einem JSON-Body:

POST <your webhook_url>
Content-Type: application/json

{
  "action":    "open",
  "object_id": 42,
  "timestamp": 1750000000,
  "nonce":     "0011223344556677",
  "signature": "9d7b58066094fa88..."
}
FeldWert
action"open", bei einem Objekt „Öffnen / schließen“ auch "close"
object_iddie Objekt-ID in Ihrem Konto
timestampUnix-Sendezeit in Sekunden
nonce16 Hex-Zeichen (8 zufällige Bytes), einmalig
signatureHMAC-SHA256, siehe unten

Ein Objekt „Öffnen / schließen“ wechselt nach der zuletzt bekannten Stellung ab: close wenn es offen ist, sonst open. Im Server-Modus entscheidet der Server, im Telefon-Modus das Telefon des Besitzers.

Die Signatur

Signiert wird eine kanonische Zeichenkette aus vier durch Punkte getrennten Feldern, nicht der JSON-Body selbst — Sie müssen unsere Serialisierung also nicht Byte für Byte nachbauen:

base = "<timestamp>.<nonce>.<action>.<object_id>"
signature = HMAC-SHA256(webhook_secret, base)   // hex

Die App erzeugt webhook_secret selbst, wenn Sie ein Webhook-Objekt anlegen: 32 zufällige Hex-Zeichen. Kopieren Sie es mit der Schaltfläche neben dem Feld in die Einstellungen Ihres Empfängers. Sie können es durch ein eigenes ersetzen. Ein Webhook ohne Geheimnis lässt sich in keinem der beiden Modi speichern, daher ist jede Anfrage signiert.

Gäste erhalten das Geheimnis nie: Ihre Tipps signiert das Telefon des Besitzers oder der Server – je nachdem, wer die Anfrage sendet.

So prüfen Sie sie (auf Ihrer Seite)

  1. Bauen Sie dieselbe Zeichenkette base = timestamp.nonce.action.object_id aus den empfangenen Feldern.
  2. Berechnen Sie HMAC-SHA256(webhook_secret, base) und vergleichen Sie es mit signature mit einem zeitkonstanten Vergleich (hash_equals / hmac.compare_digest).
  3. Replay-Schutz: weisen Sie die Anfrage zurück, wenn |now − timestamp| > 300 Sekunden beträgt. Optional können Sie die letzten nonce Werte speichern und Wiederholungen ablehnen.
  4. Stimmt die Signatur und ist die Anfrage frisch — führen Sie die Öffnung aus.
Eine Webhook-Adresse ist meist ohne Authentifizierung offen, deshalb ist die Prüfung der Signatur zwingend: Ohne sie kann jeder öffnen, der die Adresse kennt. Wenn Sie das Geheimnis ersetzen, verwenden Sie mindestens 16 Zeichen, zum Beispiel aus openssl rand -hex 32. Schreiben Sie das Geheimnis nie in die Adresse selbst.

Prüfcode

Jedes Beispiel prüft Signatur und Zeit. Bewahren Sie das Geheimnis in den Einstellungen Ihres Empfängers oder in einer Umgebungsvariable auf.

PHP

$secret = getenv('ENTRIXY_WEBHOOK_SECRET');
$b = json_decode(file_get_contents('php://input'), true);
$base = $b['timestamp'] . '.' . $b['nonce'] . '.' . $b['action'] . '.' . $b['object_id'];
$ok = hash_equals(hash_hmac('sha256', $base, $secret), (string)($b['signature'] ?? ''))
   && abs(time() - (int)$b['timestamp']) <= 300;
if (!$ok) { http_response_code(401); exit; }
// $b['action'] is "open" or "close"

Python

import hashlib, hmac, os, time

def verify(b: dict) -> bool:
    secret = os.environ["ENTRIXY_WEBHOOK_SECRET"].encode()
    base = f'{b["timestamp"]}.{b["nonce"]}.{b["action"]}.{b["object_id"]}'
    mac = hmac.new(secret, base.encode(), hashlib.sha256).hexdigest()
    return (hmac.compare_digest(mac, str(b.get("signature", "")))
            and abs(time.time() - int(b["timestamp"])) <= 300)

Node.js

const crypto = require('crypto');

function verify(b, secret) {
  const base = `${b.timestamp}.${b.nonce}.${b.action}.${b.object_id}`;
  const mac = crypto.createHmac('sha256', secret).update(base).digest('hex');
  const sig = String(b.signature || '');
  return sig.length === mac.length
    && crypto.timingSafeEqual(Buffer.from(mac), Buffer.from(sig))
    && Math.abs(Date.now() / 1000 - b.timestamp) <= 300;
}

Um auch eine Wiederholung innerhalb der fünf Minuten abzulehnen, merken Sie sich die nonce so lange, bis ihr timestamp älter als 300 Sekunden ist, und lehnen Sie Wiederholungen ab.

Testvektor

Lassen Sie Ihre Prüfung über diese Werte laufen und kontrollieren Sie die Signatur:

webhook_secret = webhook_secret_example_key
timestamp      = 1750000000
nonce          = 0011223344556677
action         = open
object_id      = 42

base       = 1750000000.0011223344556677.open.42
signature  = 9d7b58066094fa88acc0afa7aa805fc5f0d008d33cb11b8aa2366102da8e20f1
  = HMAC-SHA256(webhook_secret, base)

Die Antwort

Damit die App ein Ergebnis anzeigt, antworten Sie mit JSON:

{"level":"success","message":"Opened","position":"open","close_in":30}
FeldWert
levelsuccess, warning, danger oder info: wie die App das Ergebnis kennzeichnet
messageder Text, den die App neben dem Tastendruck anzeigt
positionfür ein Objekt „Öffnen / schließen“: open, closed oder unknown
close_inSekunden, bis der Empfänger selbst schließt, höchstens 3600: Danach zeigt die App das Objekt als geschlossen

Die ältere Antwort mit dem Feld status (ok oder error) wird ebenfalls verstanden. Fehlen beide Felder, entscheidet der HTTP-Code: Jede 2xx-Antwort ist ein Erfolg, alles andere ein Fehlschlag. Ein leeres 200 OK genügt also.

Ohne close_in wird die Stellung zwei Sekunden nach der Antwort angezeigt und ist danach unbekannt: Das nächste Tippen öffnet.

Zustellung

Die Anfrage ist immer ein POST mit JSON-Body, niemals ein einfaches GET.

Ein Empfänger, der nur im Heimnetz erreichbar ist, funktioniert daher nur, wenn das Telefon des Eigentümers die Anfrage sendet, und nur solange das Telefon in diesem Netz ist. Für einen aus dem Internet erreichbaren Empfänger verwenden Sie https.

Ohne eigenen Empfänger ausprobieren

Öffnen Sie die Demo-Schranke: sie gibt Ihnen eine persönliche Testadresse. Tragen Sie sie als Adresse des Objekts ein und fügen Sie das Geheimnis des Objekts in das Feld auf dieser Seite ein — die Signatur jedes Drucks wird direkt in Ihrem Browser geprüft, und das Geheimnis wird nirgendwohin gesendet.

Fertige Empfänger

curl sendet eine Testanfrage mit korrekter Signatur. Flask ist ein Empfänger, der die Signatur prüft und Wiederholungen ablehnt. Home Assistant nimmt den Befehl über diesen Empfänger an oder über einen eigenen Webhook-Trigger ohne Signaturprüfung.

Shelly- und Tasmota-Relais sowie openHAB prüfen die Signatur nicht. Sie werden angebunden über den Node.js-Client: Er hält selbst die Verbindung zu Entrixy und gibt den Befehl in Ihrem Netz weiter.