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.
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..."
}
| Feld | Wert |
|---|---|
action | "open", bei einem Objekt „Öffnen / schließen“ auch "close" |
object_id | die Objekt-ID in Ihrem Konto |
timestamp | Unix-Sendezeit in Sekunden |
nonce | 16 Hex-Zeichen (8 zufällige Bytes), einmalig |
signature | HMAC-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)
- Bauen Sie dieselbe Zeichenkette
base = timestamp.nonce.action.object_idaus den empfangenen Feldern. - Berechnen Sie
HMAC-SHA256(webhook_secret, base)und vergleichen Sie es mitsignaturemit einem zeitkonstanten Vergleich (hash_equals/hmac.compare_digest). - Replay-Schutz: weisen Sie die Anfrage zurück, wenn
|now − timestamp| > 300Sekunden beträgt. Optional können Sie die letztennonceWerte speichern und Wiederholungen ablehnen. - Stimmt die Signatur und ist die Anfrage frisch — führen Sie die Öffnung 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}
| Feld | Wert |
|---|---|
level | success, warning, danger oder info: wie die App das Ergebnis kennzeichnet |
message | der Text, den die App neben dem Tastendruck anzeigt |
position | für ein Objekt „Öffnen / schließen“: open, closed oder unknown |
close_in | Sekunden, 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.
- Von Ihrem Telefon: Einer Weiterleitung auf denselben Host wird gefolgt, etwa von http auf https oder auf die Adresse mit abschließendem Schrägstrich.
- Vom Entrixy-Server: Weiterleitungen wird nicht gefolgt, und Adressen in privaten und internen Netzen werden abgelehnt.
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.