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
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
- 1. Empfangsadresse eintragen — ausschließlich HTTPS.
- 2. Die gewünschten Ereignisse auswählen.
- 3. Das einmalig angezeigte Geheimnis (
whsec_…) speichern. Es ist danach nicht mehr abrufbar.
Ereignisse
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 /ihr-endpunkt HTTP/1.1
Content-Type: application/json
User-Agent: RufBusle-Webhooks/1
X-Rufbusle-Signature: t=1786804325,v1=8f3c…{
"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
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.
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
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
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.