Dokumentation

Webhooks

Statt regelmäßig zu fragen, ob sich etwas geändert hat, meldet sich RufBusle bei Ihnen — signiert, mit Wiederholungen und ohne personenbezogene Daten.

Wann Webhooks der bessere Weg sind

Und wann nicht.

Nehmen Sie Webhooks, wenn Ihr System zeitnah reagieren soll: eine Disposition, die eine neue Buchung sofort sehen will, oder ein Auskunftssystem, das seinen Fahrplan nach jeder Änderung neu einliest.

Nehmen Sie die API, wenn Sie ohnehin einen vollständigen Abgleich brauchen — etwa einen Nachtlauf über den kommenden Zeitraum. Beides zusammen ist die robusteste Kombination: Webhooks für die schnelle Reaktion, ein regelmäßiger Abgleich als Netz darunter, falls eine Zustellung dauerhaft scheitert.

Einrichten

Geschieht im Stadt-Admin unter „Schnittstellen“.
  1. 1. Empfangsadresse eintragen — ausschließlich HTTPS.
  2. 2. Die gewünschten Ereignisse auswählen.
  3. 3. Das einmalig angezeigte Geheimnis (whsec_…) speichern. Es ist danach nicht mehr abrufbar.

Ereignisse

Jeder Endpoint abonniert einzeln; nicht abonnierte Ereignisse werden gar nicht erst eingestellt.
booking.createdBuchung erstellt
Eine neue Buchung wurde angelegt — der Kern des Bedarfssignals.
booking.canceledBuchung storniert
Eine Buchung wurde storniert.
booking.completedFahrt abgeschlossen
Eine Fahrt wurde vom Fahrpersonal als abgeschlossen gemeldet.
booking.noshowFahrgast nicht erschienen
Der Fahrgast ist nicht erschienen.
feed.updatedFahrplan-Feed geändert
Die Fahrplandaten haben sich geändert; ein erneuter Feed-Abruf lohnt sich.

So sieht eine Zustellung aus

POST mit JSON-Körper, immer nach demselben Muster.
HeaderHTTP
POST /ihr-endpunkt HTTP/1.1
Content-Type: application/json
User-Agent: RufBusle-Webhooks/1
X-Rufbusle-Signature: t=1786804325,v1=8f3c…
KörperJSON
{
  "type": "booking.created",
  "occurredAt": "2026-08-10T14:32:05.000Z",
  "data": {
    "id": "bkg_5Rt8wY",
    "tripId": "trp_9Vc4mQ",
    "rideDate": "2026-08-12",
    "boardingStopId": "stp_7Kq2vX",
    "alightingStopId": "stp_1Ax9bN",
    "seats": 2,
    "wheelchairUsers": 0,
    "status": "SCHEDULED",
    "canceled": false,
    "transportMode": "BUS",
    "source": "WEB",
    "sourcePluginSlug": null
  }
}
type
Der Ereignistyp — dieselbe Zeichenkette wie in der Liste oben.
occurredAt
Zeitpunkt des Ereignisses, nicht der Zustellung. Bleibt über Wiederholungen hinweg gleich.
data
Die Nutzlast. Ihr Aufbau hängt am Ereignistyp; bei Buchungsereignissen ist es die Buchung ohne personenbezogene Angaben.

Signatur prüfen

Der einzige Beleg dafür, dass eine Zustellung wirklich von uns stammt.

Jede Zustellung trägt den Header X-Rufbusle-Signature im Format t=<unix>,v1=<hex>. Signiert wird die Zeichenkette "<t>.<roher Body>" per HMAC-SHA256 mit Ihrem Endpoint-Geheimnis.

Prüfung (Node)JavaScript
import { createHmac, timingSafeEqual } from 'node:crypto';

function verify(rawBody, header, secret, toleranceSeconds = 300) {
  const parts = Object.fromEntries(header.split(',').map((p) => p.split('=')));
  const age = Math.abs(Math.floor(Date.now() / 1000) - Number(parts.t));
  if (!Number.isFinite(age) || age > toleranceSeconds) return false;

  const expected = createHmac('sha256', secret)
    .update(`${parts.t}.${rawBody}`)
    .digest('hex');

  const a = Buffer.from(expected);
  const b = Buffer.from(parts.v1 ?? '');
  return a.length === b.length && timingSafeEqual(a, b);
}

Der Zeitstempel t ist mitsigniert und lässt sich deshalb nicht nachträglich ändern. Prüfen Sie ihn trotzdem gegen ein Zeitfenster (Vorschlag: 300 Sekunden) — sonst bleibt eine einmal abgefangene Zustellung beliebig oft wiederholbar.

Wiederholungen

Was passiert, wenn Ihr System gerade nicht erreichbar ist.

Wir erwarten innerhalb von 10 Sekunden eine 2xx-Antwort. Alles andere — Fehlerstatus, Zeitüberschreitung, Verbindungsabbruch — gilt als Fehlschlag und wird mit wachsendem Abstand wiederholt: nach etwa 2, 4, 8, 16, 32 und dann 60 Minuten, insgesamt bis zu acht Versuche. Danach gilt die Zustellung als endgültig gescheitert und wird nicht mehr angefasst.

Was Ihr Empfänger dafür können muss

Schnell quittieren
Erst mit 2xx antworten, dann verarbeiten. Wer die Verarbeitung vor der Antwort erledigt, läuft in die 10-Sekunden-Grenze und bekommt Wiederholungen für Ereignisse, die längst angekommen sind.
Doppelte vertragen
Eine Zustellung kann mehrfach ankommen — etwa wenn Ihre Antwort unterwegs verloren geht. Erkennen Sie Wiederholungen an type, data.id und occurredAt; diese Angaben bleiben über alle Versuche gleich.
Reihenfolge nicht voraussetzen
Ereignisse können sich überholen, wenn eines wiederholt wird. Entscheiden Sie über occurredAt, nicht über die Ankunftsreihenfolge.

Wenn nichts ankommt

Die Ursachen in der Reihenfolge, in der sie in der Praxis auftreten.
Adresse nicht öffentlich erreichbar
Wir stellen aus unserem Cluster zu. Eine Adresse hinter VPN, Firewall oder in einem privaten Netz erreichen wir nicht.
Ereignis nicht abonniert
Nicht abonnierte Ereignisse werden gar nicht erst eingestellt — es gibt dann auch keinen fehlgeschlagenen Versuch, den man sehen könnte.
Endpoint deaktiviert
Ein deaktivierter Endpoint bekommt nichts mehr; bereits eingestellte Zustellungen werden verworfen statt zugestellt.
Kein HTTPS
Adressen ohne TLS werden abgelehnt.

Die Stadt sieht im Admin unter „Schnittstellen“ Zustand und letzten Fehler je Endpoint. Bleibt die Ursache unklar, melden Sie sich über Support & Kontakt.

Keine personenbezogenen Daten

Bewusst, nicht aus Versehen.