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.
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
- Zeitstempel — aktuelle Unix-Zeit in Sekunden, als Zeichenkette.
- Signierte Nutzlast —
"{timestamp}.{rawRequestBody}"(die exakten Bytes, die du sendest, keine neu serialisierte Version — bei GET-Anfragen verwende eine leere Zeichenkette statt des Bodys). - Signatur —
HMAC-SHA256(webhookSecret, signierteNutzlast), hex-kodiert.
Sende beides als Header:
| Header | Wert |
|---|---|
X-PrimeCal-Timestamp | Der oben verwendete Unix-Zeitstempel (Sekunden) |
X-PrimeCal-Signature | Die 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
| Status | Bedeutung |
|---|---|
| 200 | { "success": true, "ruleId": <id>, "message": "Webhook processed successfully" } |
| 400 | Fehlerhaftes Signaturformat, oder die Regel ist keine webhook.incoming-Regel, oder die Regel ist deaktiviert |
| 401 | Fehlende/ungültige Signatur, Zeitstempel außerhalb der Toleranz, oder eine wiederholte Anfrage |
| 403 | Die Regel hat überhaupt kein webhookSecret (sollte bei einer normal erstellten Regel nicht vorkommen) |
| 404 | Token passt zu keiner Regel |
| 429 | Ratenlimit ü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.
Verwandte Themen
- Webhooks (Benutzerhandbuch) — Nutzlastform, Bedingungen, praktische Beispiele
- Automatisierungs-API — Regel-CRUD, Audit-Protokolle, Token-Regenerierung
- API-Ratenlimits