Entwickler

Webhooks

Ereignisse in Echtzeit empfangen und die Signatur prüfen.

Webhooks schicken bei jeder Änderung an einer Buchung einen POST-Request an deine URL. Du richtest sie unter Integrationen → Webhooks oder über die API ein. Webhooks sind im Pro-Tarif enthalten.

Ereignisse

Ereignis Auslöser
booking.created Neue Buchung oder Anfrage, egal über welchen Kanal
booking.confirmed Eine Anfrage wurde bestätigt
booking.rescheduled Neuer Zeitpunkt; enthält zusätzlich previousStartAt
booking.cancelled Absage durch Kunde, dich oder die API
booking.completed Als erledigt markiert
booking.no_show Als nicht erschienen markiert

Aufbau

POST /dein-endpunkt HTTP/1.1
Content-Type: application/json
User-Agent: BookBase-Webhooks/1.0
BookBase-Event: booking.created
BookBase-Delivery: 2f6c…
BookBase-Signature: t=1791072000,v1=5d41402abc4b2a76b9719d911017c592…
{
  "id": "9b1c…",
  "type": "booking.created",
  "createdAt": "2026-10-04T09:12:44.120Z",
  "data": {
    "booking": {
      "id": "…",
      "reference": "BB-7K3D9Q",
      "status": "confirmed",
      "service": { "id": "…", "name": "Erstberatung" },
      "startAt": "2026-10-05T07:00:00.000Z",
      "endAt": "2026-10-05T07:30:00.000Z",
      "customer": { "name": "Anna Weber", "email": "anna@example.com", "phone": null }
    }
  }
}

Das Objekt booking hat dasselbe Format wie in der API-Referenz.

Signatur prüfen

Jeder Request ist mit deinem Signatur-Secret signiert (HMAC-SHA256 über Zeitstempel.Rohinhalt). Prüfe die Signatur, bevor du den Inhalt verarbeitest, und lehne alte Zeitstempel ab.

import { createHmac, timingSafeEqual } from "node:crypto";

export function verifyBookBaseSignature(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(header.split(",").map((part) => part.split("=")));
  const timestamp = Number(parts.t);
  if (!timestamp || Math.abs(Date.now() / 1000 - timestamp) > toleranceSeconds) {
    return false;
  }
  const expected = createHmac("sha256", secret).update(`${timestamp}.${rawBody}`).digest("hex");
  const received = Buffer.from(parts.v1 ?? "", "hex");
  const computed = Buffer.from(expected, "hex");
  return received.length === computed.length && timingSafeEqual(received, computed);
}

Wichtig: Verwende den unveränderten Request-Body als Text, nicht das bereits geparste JSON.

Antworten und Wiederholungen

Antworte innerhalb von 10 Sekunden mit einem Status zwischen 200 und 299. Andernfalls wiederholt BookBase die Zustellung nach 1, 5, 30, 120, 360 und 1440 Minuten. Weiterleitungen werden nicht verfolgt. Nach 15 aufeinanderfolgenden Fehlschlägen wird der Endpunkt deaktiviert; du aktivierst ihn im Dashboard wieder. Dort siehst du auch die letzten Zustellungen und kannst fehlgeschlagene erneut senden.

Ereignisse können in seltenen Fällen doppelt ankommen. Nutze BookBase-Delivery oder die id im Body, um Duplikate zu erkennen.

Testen

Mit Testen im Dashboard schickst du ein Ereignis vom Typ ping an den Endpunkt und siehst sofort den HTTP-Status.

Anforderungen an die URL

Die URL muss https:// verwenden und öffentlich erreichbar sein. Adressen in privaten Netzen, localhost und Zugangsdaten in der URL sind aus Sicherheitsgründen nicht erlaubt.