Zum Hauptinhalt springen
War diese Seite hilfreich?

Webhook-API

Dies ist die technische Referenz für PrimeCals eingehenden Webhook-Empfänger — den Endpunkt, den ein externes System aufruft, um eine webhook.incoming-Automatisierungsregel auszulösen. Für eine produktseitige Anleitung siehe Webhooks im Benutzerhandbuch.

Anfragen müssen HMAC-signiert sein — es gibt keinen unsignierten Modus

Jeder Aufruf dieses Endpunkts wird mit einer HMAC-SHA256-Signatur verifiziert. Es gibt keine Möglichkeit, dies pro Regel zu deaktivieren, und eine unsignierte Anfrage wird rundweg abgelehnt. Plane von Anfang an mit Signierung; ein einfaches curl -d '{...}'-POST schlägt fehl.

Endpunkt​

POST https://api.primecal.eu/api/automation/webhook/{token}
GET https://api.primecal.eu/api/automation/webhook/{token}

{token} ist eindeutig pro Regel (webhookToken), zu finden im Webhook-Tab der Regel in der App und von dort aus neu generierbar.

  • POST — sende deine Nutzlast als JSON-Body (Content-Type: application/json).
  • GET — für Aufrufer, die keinen POST-Body senden können (IoT-Tasten, browserausgelöste Links). Stattdessen werden Query-String-Parameter zur Nutzlast.

Beide Varianten benötigen dieselbe Signatur.

Dein Signaturgeheimnis erhalten​

Jede Regel hat ein webhookSecret, das bei der Erstellung der Regel automatisch generiert wird. Die Web-App zeigt es derzeit nicht an — der einzige Weg, es abzurufen oder zu rotieren, ist dieser Endpunkt:

POST /api/automation/rules/{id}/webhook/rotate-secret

Authentifiziert als Besitzer der Regel (normale JWT-Auth, nicht das Webhook-Token). Antwort:

{ "webhookSecret": "<neues 128-stelliges Hex-Geheimnis>", "graceUntil": "2026-09-26T12:00:00.000Z" }

Der Aufruf rotiert das Geheimnis — das vorherige Geheimnis funktioniert bis graceUntil (standardmäßig 1 Stunde) weiter, dann stoppt es. Es gibt keinen nur-lesenden Aufruf "aktuelles Geheimnis anzeigen"; wenn du das Geheimnis verloren hast, ist Rotieren die einzige Wiederherstellung.

Eine Anfrage signieren​

  1. Zeitstempel — aktuelle Unix-Zeit in Sekunden, als Zeichenkette.
  2. Signierte Nutzlast — "{timestamp}.{rawRequestBody}" (die exakten Bytes, die du sendest, keine neu serialisierte Version — bei GET-Anfragen verwende eine leere Zeichenkette statt des Bodys).
  3. Signatur — HMAC-SHA256(webhookSecret, signierteNutzlast), hex-kodiert.

Sende beides als Header:

HeaderWert
X-PrimeCal-TimestampDer oben verwendete Unix-Zeitstempel (Sekunden)
X-PrimeCal-SignatureDie Hex-Signatur, optional mit Präfix sha256=

(X-Webhook-Signature/X-Webhook-Timestamp und X-Hub-Signature-256 werden ebenfalls akzeptiert, zur Kompatibilität mit gängigen Webhook-Sender-Konventionen.)

Beispiel (Node.js)​

const crypto = require('crypto');

const secret = 'the webhookSecret from rotate-secret';
const body = JSON.stringify({ event: 'order.completed', data: { order_id: '12345' } });
const timestamp = Math.floor(Date.now() / 1000).toString();
const signature = crypto
.createHmac('sha256', secret)
.update(`${timestamp}.${body}`)
.digest('hex');

await fetch('https://api.primecal.eu/api/automation/webhook/YOUR_TOKEN', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-PrimeCal-Timestamp': timestamp,
'X-PrimeCal-Signature': signature,
},
body,
});

Beispiel (curl, vorberechnet)​

SECRET="the webhookSecret from rotate-secret"
BODY='{"event":"order.completed","data":{"order_id":"12345"}}'
TS=$(date +%s)
SIG=$(printf '%s.%s' "$TS" "$BODY" | openssl dgst -sha256 -hmac "$SECRET" | sed 's/^.* //')

curl -X POST "https://api.primecal.eu/api/automation/webhook/YOUR_TOKEN" \
-H "Content-Type: application/json" \
-H "X-PrimeCal-Timestamp: $TS" \
-H "X-PrimeCal-Signature: $SIG" \
-d "$BODY"

Zeitstempel-Toleranz und Wiederholungsschutz​

  • Der Zeitstempel muss innerhalb von 5 Minuten der Serveruhr liegen (WEBHOOK_TIMESTAMP_TOLERANCE_SECONDS, Standard 300). Außerhalb dieses Fensters wird die Anfrage abgelehnt — das bedeutet auch, dass du eine alte, abgefangene Anfrage nicht mehr wiederholen kannst, nachdem das Fenster geschlossen ist.
  • Jede (token, signature, timestamp)-Kombination kann nur einmal verwendet werden. Ein byte-identischer erneuter Versuch derselben signierten Anfrage wird als Replay abgelehnt.

Rotieren ohne Ausfallzeit​

rotate-secret gibt deinen neuen Anfragen ein neues Geheimnis, während das alte weiterhin bis graceUntil (standardmäßig 1 Stunde) verifiziert wird. Aktualisiere das im externen System gespeicherte Geheimnis innerhalb dieses Fensters; es gibt keine Möglichkeit, es nachträglich zu verlängern — rotiere erneut, wenn du mehr Zeit brauchst.

Ratenlimits​

Webhook-Aufrufe sind pro Regel ratenlimitiert: standardmäßig 60 Anfragen pro 60-Sekunden-Fenster (AUTOMATION_WEBHOOK_MAX_PER_WINDOW / AUTOMATION_WEBHOOK_WINDOW_MS), unabhängig von den allgemeinen API-Ratenlimits in API-Ratenlimits. Überschreitung gibt einen Fehler zurück, der die Wiederholungsverzögerung nennt.

Optional: Einschränkung nach Quell-IP​

Eine Regel kann mit einer IP-Zulassungsliste (triggerConfig) konfiguriert werden, sodass zusätzlich zur Signaturprüfung nur Anfragen von bestimmten Quell-IPs akzeptiert werden. Das wird über die Automatisierungs-API eingestellt, derzeit nicht in der Regel-Builder-Oberfläche verfügbar.

Antworten​

StatusBedeutung
200{ "success": true, "ruleId": <id>, "message": "Webhook processed successfully" }
400Fehlerhaftes Signaturformat, oder die Regel ist keine webhook.incoming-Regel, oder die Regel ist deaktiviert
401Fehlende/ungültige Signatur, Zeitstempel außerhalb der Toleranz, oder eine wiederholte Anfrage
403Die Regel hat überhaupt kein webhookSecret (sollte bei einer normal erstellten Regel nicht vorkommen)
404Token passt zu keiner Regel
429Ratenlimit überschritten

Ein 200 bedeutet, dass die Anfrage akzeptiert und ausgewertet wurde — nicht, dass die Bedingungen der Regel zutrafen. Prüfe das Audit-Protokoll der Regel (Automatisierungs-API), um zu sehen, ob die Aktion tatsächlich ausgeführt wurde.