Zum Inhalt springen

Grundlagen

Webhooks

STRYK sendet einen HTTPS-POST an deinen Endpunkt, wenn sich Buchungen, Gäste, Verfügbarkeit, Preise oder Zahlungen ändern. Für Rechnungen gibt es in v1 kein Ereignis; gleiche GET /invoices per updated_since ab. Jede Zustellung ist signiert, wird bei Fehlern wiederholt und steht im Zustellprotokoll.

Endpunkt einrichten

  1. Endpunkt anlegen

    Öffne in STRYK Kanäle → API, Reiter Webhooks, wähle Webhook anlegen, trage eine HTTPS-URL ein und wähle die Ereignisse.

  2. Signiergeheimnis sichern

    STRYK zeigt das Signiergeheimnis (whsec_…) ein einziges Mal. Bewahre es wie einen API-Schlüssel auf deinem Server auf.

  3. Testereignis senden

    Mit Testereignis senden stellt STRYK ein webhook.test-Ereignis zu. So prüfst du deine Signaturprüfung.

Die URL muss HTTPS verwenden und eine öffentliche Adresse erreichen. STRYK folgt keinen Weiterleitungen und lehnt private oder lokale Ziele ab, beim Speichern und bei jeder Zustellung.

Ereignisse

EreignisWird gesendet, wenn
booking.createdeine neue Buchung in STRYK besteht.
booking.updatedsich eine Buchung ändert: Status, Daten, Zimmer, Gastzuordnung, Notizen. data.changes nennt die Bereiche (status, rooms, guest, details, deleted).
booking.cancelledeine Buchung storniert wurde.
guest.updatedsich Gastkontaktdaten geändert haben.
availability.changedsich freie Einheiten oder Restriktionen für Kategorien und einen Zeitraum geändert haben. Änderungen werden je Kategorie und Zeitraum zusammengefasst.
rate.changedsich Tagespreise für Kategorien und einen Zeitraum geändert haben, zusammengefasst wie bei der Verfügbarkeit.
payment.updatedsich der bezahlte Betrag einer Buchung geändert hat; data.bookingId nennt die Buchung.
webhook.testDu in STRYK eine Testzustellung angefordert hast.
unit.updatedunit.updated

GET /webhook-event-types liefert die aktuelle Liste mit Beschreibungen.

Payload

Ereignisse sind schlank: du enthältst Typ, betroffenes Objekt und dessen ID, aber nicht das ganze Objekt. Den aktuellen Stand liest du über die API. So bleiben personenbezogene Daten aus Logs und Queues heraus, und du handelst nie auf einer veralteten Kopie.

{
  "id": "evt_1f6c9e2a-3b4d-4e5f-8a7b-6c5d4e3f2a1b",
  "type": "booking.updated",
  "apiVersion": "v1",
  "createdAt": "2026-11-04T08:20:31.000Z",
  "hotelId": "hotel-alpenblick",
  "data": { "object": "booking", "id": "9d3c1b2a-7e6f-4a5b-8c9d-0e1f2a3b4c5d", "changes": ["status"] }
}

Header

HTTP
POST /webhooks/stryk HTTP/1.1
Content-Type: application/json
User-Agent: STRYK-Webhooks/1.0
STRYK-Event-Id: evt_1f6c9e2a-3b4d-4e5f-8a7b-6c5d4e3f2a1b
STRYK-Event-Type: booking.updated
STRYK-Delivery-Id: 2b1a0f9e-8d7c-4b6a-a594-837261504f3e
STRYK-Delivery-Attempt: 1
STRYK-Signature: t=1793780431,v1=5f2c8a1e9b0d…
HeaderInhalt
STRYK-Event-IdEreignis-ID, identisch mit id im Body. Dasselbe Ereignis behält seine ID bei jedem Versuch.
STRYK-Event-TypeEreignistyp, z. B. booking.updated.
STRYK-Delivery-IdID dieser Zustellung an diesen Endpunkt; steht im Zustellprotokoll.
STRYK-Delivery-AttemptNummer des Versuchs, beginnend mit 1.
STRYK-Signaturet=<Unix-Sekunden>,v1=<HMAC-SHA256 hex>; während einer Secret-Rotation zwei v1-Werte.

Signatur prüfen

STRYK berechnet HMAC-SHA256(secret, "<t>.<rawBody>") mit deinem Signiergeheimnis als Schlüssel, dem vollständigen angezeigten Wert inklusive whsec_, als UTF-8-Bytes, und sendet das Ergebnis hexadezimal als v1. Prüfe jede Anfrage, bevor du sie verwendest:

  1. Roh-Body lesen

    Verwende genau die empfangenen Bytes. Wer JSON parst und neu serialisiert, ändert Leerzeichen und Reihenfolge, die Signatur passt dann nicht mehr.

  2. Zeitstempel prüfen

    Lehne Anfragen ab, deren t mehr als 300 Sekunden von deiner Uhr abweicht. Das verhindert das Wiedereinspielen aufgezeichneter Anfragen.

  3. In konstanter Zeit vergleichen

    Berechne den HMAC über t, einen Punkt und den Roh-Body und vergleiche ihn mit jedem v1-Wert in konstanter Zeit.

  4. Ein Treffer genügt

    Nach einer Secret-Rotation signiert STRYK 24 Stunden lang mit altem und neuem Secret. Der Header enthält dann zwei v1-Werte; ein gültiger Treffer reicht.

webhook.js
import crypto from 'node:crypto';
import express from 'express';

export function verifyStrykSignature(rawBody, header, secret, toleranceSeconds = 300) {
  if (!header) return false;
  let timestamp = null;
  const signatures = [];
  for (const part of header.split(',')) {
    const [key, value] = part.trim().split('=', 2);
    if (key === 't') timestamp = Number(value);
    if (key === 'v1' && value) signatures.push(value);
  }
  if (!Number.isInteger(timestamp) || signatures.length === 0) return false;
  if (Math.abs(Math.floor(Date.now() / 1000) - timestamp) > toleranceSeconds) return false;

  const expected = crypto.createHmac('sha256', secret).update(`${timestamp}.`).update(rawBody).digest();
  // During a secret rotation the header carries two v1 values; one match is enough.
  return signatures.some((signature) => {
    const received = Buffer.from(signature, 'hex');
    return received.length === expected.length && crypto.timingSafeEqual(received, expected);
  });
}

const app = express();

// express.raw keeps the exact bytes. Parsing JSON first would break the signature.
app.post('/webhooks/stryk', express.raw({ type: 'application/json', limit: '1mb' }), (req, res) => {
  if (!verifyStrykSignature(req.body, req.get('STRYK-Signature'), process.env.STRYK_WEBHOOK_SECRET)) {
    return res.status(400).send('Invalid signature');
  }
  const event = JSON.parse(req.body.toString('utf8'));
  res.sendStatus(204);   // acknowledge within seconds …
  queue.add(event);      // … and process asynchronously, deduplicated by event.id
});

Antworten und verarbeiten

  • Antworte innerhalb von 10 Sekunden mit einem beliebigen 2xx-Status. STRYK verwirft den Antwort-Body.
  • Erst bestätigen, dann in einer Queue oder einem Hintergrundjob verarbeiten. Langsame Handler führen zu Timeouts und doppelten Zustellungen.
  • Verarbeite idempotent je Ereignis-id: Speicher verarbeitete IDs und überspringe Wiederholungen.
  • Verlasse dich nicht auf die Reihenfolge. Vergleiche updatedAt des gelesenen Objekts mit deinem Stand.

Wiederholungen und automatische Deaktivierung

Eine Zustellung schlägt bei Timeout, Netzwerkfehler oder jedem Status außer 2xx fehl. STRYK wiederholt mit wachsendem Abstand:

VersuchAbstand zum vorigen Versuch
1sofort
21 Minute
35 Minuten
430 Minuten
52 Stunden
66 Stunden
712 Stunden
824 Stunden

Nach dem achten Fehlversuch gilt die Zustellung endgültig als fehlgeschlagen. Scheitert ein Endpunkt 20-mal in Folge über mindestens 24 Stunden ohne einen einzigen Erfolg, deaktiviert STRYK ihn automatisch. Behebe den Fehler und aktiviere den Endpunkt in STRYK wieder.

Zustellprotokoll und manuelle Wiederholung

Unter Kanäle → API → Webhooks zeigt der Bereich Zustellungen eines Webhooks jede Zustellung mit Zeitpunkt, Ereignis, Status, Versuchen, HTTP-Status, nächstem Versuch und Zustellzeit. Mit Erneut senden wiederholst du eine einzelne Zustellung, etwa nach einer Korrektur. Mit Geheimnis erneuern rotierst du dort auch das Signiergeheimnis.