Aktualisiert
Webhooks sind der schnellste Weg, mit Nowistay synchron zu bleiben. Statt die API alle paar Minuten abzufragen, um neue oder geänderte Reservierungen zu erkennen, teilen Sie Nowistay mit, wohin die Ereignisse gesendet werden sollen, und Ihr Dienst erhält sie, sobald sie eintreten. Dieser Artikel zeigt Ihnen, wie Sie einen Webhook erstellen, die Signatur prüfen und Wiederholungen behandeln.
Mit der öffentlichen REST-API von Nowistay können Ihre Tools und Partner Nowistay-Daten über HTTPS lesen und schreiben. Sie authentifizieren sich mit OAuth2 (Authorization Code + PKCE), erhalten ein Access Token und rufen Endpunkte unter /public/v1/* auf. Webhooks sind das Push-Gegenstück: dieselben Daten, dieselbe Struktur wie GET /public/v1/bookings/{id}, aber Nowistay sendet sie Ihnen, wenn sich etwas ändert.
Haben Sie OAuth noch nicht eingerichtet, beginnen Sie mit der Hauptanleitung: Die öffentliche REST-API von Nowistay nutzen. Sie behandelt Registrierung, Zustimmungsablauf, Scopes und das Testen von Aufrufen im Playground der Dokumentation.
booking.created und booking.updated in Echtzeit.GET /public/v1/bookings/{id}, einschließlich Daten, Kanal, Status, Beträgen, für Aufträge relevanten Feldern und Ihren benutzerdefinierten Buchungsparametern.webhooks.write enthalten. POST /public/v1/webhooks erfordert außerdem bookings.read, weil die Nutzdaten ein vollständiges Buchungsdetail sind.2xx-Status antworten.curl -X POST https://api.nowistay.com/public/v1/webhooks \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{
"propertyId": 101,
"url": "https://partner.example.com/nowistay/webhooks",
"events": ["booking.created", "booking.updated"],
"description": "PMS sync"
}'
Antwort:
{
"id": 801,
"propertyId": 101,
"url": "https://partner.example.com/nowistay/webhooks",
"events": ["booking.created", "booking.updated"],
"description": "PMS sync",
"status": "active",
"createdAt": "2026-05-27T16:40:00Z",
"updatedAt": "2026-05-27T16:40:00Z",
"signingSecret": "whsec_9npwH6J8QyZp1L8U3xqG7sN2"
}
Speichern Sie das signingSecret jetzt. Es wird nur einmal bei der Erstellung zurückgegeben. Über die API können Sie es nicht noch einmal abrufen. Wenn Sie es verlieren, löschen Sie den Webhook und erstellen Sie einen neuen.
Jede Zustellung ist ein HTTP-POST an Ihre URL mit diesen Headern:
Content-Type: application/jsonUser-Agent: Nowistay-Webhooks/1.0Nowistay-Webhook-Id: 801Nowistay-Webhook-Event-Id: evt_LkP2sxR9zV8QyW... (eindeutig pro Ereignis)Nowistay-Webhook-Event-Type: booking.updatedNowistay-Webhook-Timestamp: 1779292800 (Unix-Sekunden)Nowistay-Webhook-Signature: v1=3a7b...e1c (HMAC-SHA256 hex)Und einem JSON-Body in dieser Form:
{
"id": "evt_LkP2sxR9zV8QyW...",
"type": "booking.updated",
"createdAt": "2026-05-27T16:40:00Z",
"apiVersion": "2026-05-27",
"propertyId": 101,
"bookingId": 9001,
"data": {
"booking": {
"id": 9001,
"propertyId": 101,
"arrival": "2026-07-14",
"departure": "2026-07-18",
"status": "confirmed",
"channel": "airbnb",
"reservationNumber": "HMABCDE",
"guest": { "firstName": "Maya", "lastName": "M." },
"amounts": { "amount": "620.00", "currency": "EUR" },
"identity": { "status": "verified" }
}
}
}
Ihr Endpunkt sollte mit einem beliebigen 2xx-Status antworten (200 oder 204 sind üblich). Alles andere oder eine Antwort, die länger als 10 Sekunden dauert, gilt als Fehler und löst eine Wiederholung aus.
Prüfen Sie immer die Signatur, bevor Sie dem Body vertrauen. Ohne Prüfung könnte jeder, der Ihre URL errät, gefälschte Ereignisse an Ihren Dienst senden.
Nowistay berechnet die Signatur so:
signature = "v1=" + HMAC_SHA256(
signing_secret,
timestamp + "." + event_id + "." + raw_request_body
).hex()
Berechnen Sie sie auf Ihrer Seite neu, mit den Headern Nowistay-Webhook-Timestamp und Nowistay-Webhook-Event-Id und dem exakten rohen Request-Body (parsen und serialisieren Sie das JSON vor der Prüfung nicht erneut, sonst riskieren Sie Byte-Abweichungen).
import crypto from "node:crypto";
function verify(req, signingSecret) {
const timestamp = req.headers["nowistay-webhook-timestamp"];
const eventId = req.headers["nowistay-webhook-event-id"];
const signature = req.headers["nowistay-webhook-signature"];
const rawBody = req.rawBody; // Buffer of the raw HTTP body
const signed = Buffer.concat([
Buffer.from(`${timestamp}.${eventId}.`, "utf8"),
rawBody,
]);
const expected = "v1=" + crypto
.createHmac("sha256", signingSecret)
.update(signed)
.digest("hex");
const a = Buffer.from(signature);
const b = Buffer.from(expected);
return a.length === b.length && crypto.timingSafeEqual(a, b);
}
import hmac, hashlib
def verify(request, signing_secret: str) -> bool:
timestamp = request.headers["Nowistay-Webhook-Timestamp"]
event_id = request.headers["Nowistay-Webhook-Event-Id"]
signature = request.headers["Nowistay-Webhook-Signature"]
raw_body = request.body # bytes
signed = f"{timestamp}.{event_id}.".encode("utf-8") + raw_body
expected = "v1=" + hmac.new(
signing_secret.encode("utf-8"),
signed,
hashlib.sha256,
).hexdigest()
return hmac.compare_digest(signature, expected)
Prüfen Sie außerdem, dass der Zeitstempel aktuell ist (zum Beispiel innerhalb der letzten 5 Minuten), um sich vor Replay-Angriffen zu schützen.
Das Objekt data.booking entspricht dem, was GET /public/v1/bookings/{id} ohne den Scope bookings.sensitive.read zurückgibt. Das heißt:
Braucht Ihr Tool eines dieser sensiblen Felder, rufen Sie das Buchungsdetail über die API mit einem Token ab, das den Scope bookings.sensitive.read enthält. Die bookingId im Webhook-Umschlag ist die passende Eingabe für diesen Aufruf.
curl https://api.nowistay.com/public/v1/bookings/9001 \
-H "Authorization: Bearer nis_access_token_with_sensitive_scope"
Gibt Ihr Endpunkt einen Nicht-2xx-Status zurück, läuft in ein Timeout oder schlägt aus einem anderen Grund fehl, verwirft Nowistay das Ereignis nicht. Es plant eine Wiederholung, mit exponentiellem Backoff und etwas Jitter:
Das geht weiter, bis Ihr Endpunkt das Ereignis akzeptiert oder bis der Webhook mehr als 72 Stunden am Stück fehlschlägt. Dann setzt Nowistay den Status des Webhooks auf disabled und sendet keine neuen Ereignisse mehr daran. Die Fehlerzähler werden bei jeder erfolgreichen Zustellung zurückgesetzt, ein einzelner Vorfall löst die automatische Deaktivierung also nie aus.
Zustellungsprotokolle werden 30 Tage aufbewahrt und dann gelöscht.
Ein deaktivierter Webhook lässt sich über die API wieder einschalten, sobald Ihr Endpunkt wieder in Ordnung ist. Senden Sie ein PATCH mit status: "active":
curl -X PATCH https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{"status": "active"}'
Nowistay spielt die Ereignisse, die während der Deaktivierung ausgelöst wurden, nicht erneut ab. Haben Sie welche verpasst, führen Sie einmalig einen Nachabruf mit GET /public/v1/bookings und einem Datumsfilter durch und setzen Sie dann Ihren Webhook-gesteuerten Ablauf fort.
Sie können Zustellungen vorübergehend pausieren (zum Beispiel während eines Wartungsfensters), ohne die Webhook-Konfiguration zu verlieren:
# Pause
curl -X PATCH https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{"status": "paused"}'
# Resume
curl -X PATCH https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example" \
-H "Content-Type: application/json" \
-d '{"status": "active"}'
# Delete permanently
curl -X DELETE https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example"
Im selben Aufruf können Sie auch die url, die Liste events oder die description ändern. Das Ändern der URL erneuert das Signing Secret nicht.
# List all webhooks (optionally filtered by property)
curl "https://api.nowistay.com/public/v1/webhooks?propertyId=101" \
-H "Authorization: Bearer nis_access_token_example"
# Read one webhook
curl https://api.nowistay.com/public/v1/webhooks/801 \
-H "Authorization: Bearer nis_access_token_example"
Die Listenantwort zeigt dieselben Felder wie die Antwort beim Erstellen, abzüglich des Signing Secrets (es wird nur bei der Erstellung zurückgegeben).
https://user:pass@... wird abgelehnt).localhost, keine privaten oder reservierten IP-Bereiche. Nowistay löst den Hostnamen außerdem zum Zustellzeitpunkt auf und blockiert Aufrufe, die auf private Adressen zeigen.id aus dem Body und überspringen Sie das Ereignis, wenn Sie es schon verarbeitet haben.2xx und verarbeiten Sie das Ereignis in einem Hintergrundjob, wenn es aufwendig ist.Nowistay-Webhook-Event-Id und die Request-ID in Ihren Logs auf. Das beschleunigt den Support.GET /public/v1/bookings/{id} auf.Ratgeber für Gastgeber: zum Blog.
Bereit, Ihre Ferienunterkunft auf Autopilot zu schalten?