Sendungs- / Tourwebhooks
Um Kundensysteme proaktiv über Änderungen an Transportaufträgen/Sendungen und Touren zu informieren, können in X4fleet für diese beiden Entitäten Webhooks konfiguriert werden.
Je Entität gibt es eine Liste an Ereignissen, welche einen Webhook auslösen können.
Webhooks können via Admin-Benutzer in X4fleet unter Einstellungen > Einstellungen > “Statusmeldungen (Webhooks)“ konfiguriert werden.

Für die Authentifizierung des POST-Requests kann entweder ein Paar aus Benutzername und Passwort oder ein x509-Zertifikat hinterlegt werden.
Falls eine andere Methode benötigt wird oder X4fleet selber keine Requests an das Kundensystem senden soll, können diese auch proaktiv (z.B. im 5min Intervall) vom Kundensystem abgeholt werden. (Dazu die Checkbox Nur Webhook Speicher verwenden aktivieren).
Auch wenn der Payload sehr umfangreich ist, empfiehlt es sich den Webhook nur als Auslöser für “Hei, an Sendung X ist etwas passiert. Geh mal nachschauen!“ zu verstehen. Also das als Konsequenz ein GET Shipment oder GET Tour vom Kundensystem ausgelöst wird, um weitere Details zu erhalten. Dies da der Webhook-Payload langfristig schlanker werden soll und neue Datenstrukturen nur in den dazugehörigen Endpoints eingebaut werden.
Endpunkte:
GET /x4gateway/v1/export/webhookShipmentMessages
GET /x4gateway/v1/export/webhookTourMessages
Auslöser Sendung / Transportauftrag
- In Bearbeitung - Die Sendung wurde angelegt, ist aber noch in Bearbeitung bzw. es fehlen Informationen
- Freigegeben - Die Sendung wurde manuell oder via Einstellung für die Planung auf eine Tour freigegeben
- Verplant - Sendung wurde auf eine Tour geplant
- Abholung abgeschlossen
- Zustellung abgeschlossen
- Mengensplitt - Sendung wurde auf N weitere Sendungen aufgeteilt, da die Menge nicht mit einer Fahrt erledigt werden kann
- Wegsplitt - Sendung wurde auch N weitere Sendungen aufgeteilt, da die Waren über N Depots verschoben werden, bevor sie ihr Ziel erreichen
- Abgeschlossen
- Abgeschlossen mit Vorbehalt - Zwischen der Aufführung und der Planung gibt es Abweichungen (z.B. wurde weniger Geladen als geplant)
- Wieder geöffnet - An der Sendung muss etwas korrigiert werden
Auslöser Tour
- In Planung - Der Tour wurde eine erste Sendung zugeteilt (meist nicht relevant für Kundensystem)
- Geplant - Die Tour wurde berechnet bzw. optimiert (meist nicht relevant für Kundensystem)
- Freigegeben - Die Tour wurde für die Ausführung freigegeben (je nach Prozess, können zwischen Freigabe und Ausführung einige Tage liegen)
- Erneut Freigegeben - Die Tour wurde zurückgenommen, ggf. verändert und erneut zur Ausführung freigegeben
- In Anpassung - Tour war mal freigegeben, wurde dann aber für eine Korrektur zurückgenommen
- Überarbeitet - Nach “In Anpassung“ wenn erneut berechnet/optimiert
- In Ausführung - Fahrer hat die freigegebene Tour gestartet
- Komplett erledigt - Alle Transportpunkte und Sendungen gemäss Disposition erledigt
- Unvollständig abgeschlossen - Abweichungen zwischen abgeschlossener Ausführung und Planung der Disposition
- Nicht begonnen
- Pausiert - z.B. bei Pause des Fahrers oder wenn am Vortag das Fahrzeug vorgeladen wurde und die Tour nun auf die weitere Ausführung wartet
- * (A) - Der Suffix heisst, dass die Tour mal im Status “In Ausführung“ war bevor sie in den neuen Status gewechselt hat
- * (P) - Der Suffix heisst, dass die Tour mal im Status “Pausiert“ war bevor sie in den neuen Status gewechselt hat
Ein Tourwebhook wird grundsätzlich nur versendet, wenn sich der Status der Tour tatsächlich ändert. Wird eine Aktion im selben Status wiederholt (z.B. werden einer Tour, die bereits “In Planung“ ist, weitere Sendungen zugeteilt), wird kein weiterer Tourwebhook versendet. Ausnahme: Ist das Modul für die Sendungsprüfung aktiv, werden Tourwebhooks ab Beginn der Ausführung (ab Status “In Ausführung“) erst versendet, wenn alle Sendungen der Tour geprüft sind; der Tourwebhook wird dann mit dem aktuellen Status der Tour versendet, auch ohne Statuswechsel, sofern der Webhook für diesen Status konfiguriert ist. Zwischenzeitliche Statuswechsel werden nicht nachträglich versendet. Für Sendungswebhooks gilt diese Einschränkung nicht.
JSON Schema für erhaltene Webhooks
{
"title": "WebhookShipmentDto",
"type": "object",
"properties": {
"id": { "type": "integer" },
"groupId": { "type": "integer" },
"refId": { "type": ["string", "null"] },
"source": { "type": ["string", "null"] },
"salesmanCode": { "type": ["string", "null"] },
"orderNumber": { "type": ["string", "null"] },
"note": { "type": ["string", "null"] },
"timeStamp": { "type": "string", "format": "date-time" },
"status": { "type": ["string", "null"] },
"fiscalStatus": { "type": ["string", "null"] },
"shipmentType": { "type": ["string", "null"] },
"customField1": { "type": ["string", "null"] },
"customField2": { "type": ["string", "null"] },
"customField3": { "type": ["string", "null"] },
"customField4": { "type": ["string", "null"] },
"customField5": { "type": ["string", "null"] },
"customField6": { "type": ["string", "null"] },
"customField7": { "type": ["string", "null"] },
"customField8": { "type": ["string", "null"] },
"customField9": { "type": ["string", "null"] },
"customField10": { "type": ["string", "null"] },
"precombinedTourNumber": { "type": ["string", "null"] },
"extSortOrderA": { "type": ["integer", "null"] },
"extSortOrderB": { "type": ["integer", "null"] },
"calculatedSortOrderA": { "type": ["integer", "null"] },
"calculatedSortOrderB": { "type": ["integer", "null"] },
"transportPoints": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookTransportPointDto" }
},
"shipmentReports": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookShipmentReportDto" }
},
"parentShipmentReports": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookShipmentReportDto" },
"description": "Reports stored on the split parent shipment (e.g. the parent delivery note); empty for shipments without a split parent"
},
"splitParentId": { "type": ["integer", "null"] },
"parentShipmentType": {
"oneOf": [
{ "type": "null" },
{ "$ref": "#/$defs/ShipmentTypeEnum" }
]
},
"splits": { "type": ["integer", "null"] },
"splitSortOrder": { "type": ["integer", "null"] },
"pickupLocationRefId": { "type": ["string", "null"] },
"dropoffLocationRefId": { "type": ["string", "null"] },
"isReadyForCommissioning": { "type": "boolean" }
},
"$defs": {
"WebhookTransportPointDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"dropoffStop": { "type": "boolean" },
"sortOrder": { "type": "integer" },
"precombinedTourNumber": { "type": ["string", "null"] },
"scheduledArrival": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"scheduledDeparture": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"startActual": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"endActual": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"images": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookTransportPointImageDto" }
},
"status": {
"oneOf": [
{ "type": "null" },
{ "$ref": "#/$defs/StopStatusEnum" }
]
},
"driverTasks": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookDriverTaskDto" }
}
}
},
"WebhookTransportPointImageDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"transportPointId": { "type": "integer" },
"url": { "type": ["string", "null"] },
"lat": { "type": ["number", "null"] },
"lng": { "type": ["number", "null"] }
}
},
"WebhookShipmentReportDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"reportId": { "type": ["integer", "null"] },
"reportUrl": { "type": ["string", "null"] },
"timeStamp": { "type": ["string", "null"], "format": "date-time" },
"reportType": {
"oneOf": [
{ "type": "null" },
{ "$ref": "#/$defs/ReportTypeEnum" }
]
}
}
},
"WebhookDriverTaskDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"type": { "$ref": "#/$defs/DriverTaskType" },
"status": { "$ref": "#/$defs/DriverTaskStatusEnum" },
"barCode": { "type": ["string", "null"] },
"scannerLat": { "type": ["number", "null"] },
"scannerLng": { "type": ["number", "null"] },
"quantityRequired": { "type": ["number", "null"] },
"quantityActual": { "type": ["number", "null"] },
"quantityEdited": { "type": ["number", "null"] }
}
},
"ShipmentTypeEnum": {
"type": "integer",
"enum": [0, 1, 2, 3, 4],
"description": "0 = InitialLeg, 1 = MainLeg, 2 = FinalLeg, 3 = Direct, 4 = Undefined"
},
"StopStatusEnum": {
"type": "integer",
"enum": [0, 1, 2, 3, 9, 10, 11],
"description": "0 = NotStarted, 1 = Success, 2 = Fail, 3 = Warning, 9 = InProgress, 10 = WaitingAfterArrival, 11 = WaitingBeforeDeparture"
},
"DriverTaskType": {
"type": "integer",
"enum": [1, 2, 3],
"description": "1 = Pickup, 2 = Dropoff, 3 = Flushing"
},
"DriverTaskStatusEnum": {
"type": "integer",
"enum": [0, 1, 2, 3],
"description": "0 = NotStarted, 1 = Completed, 2 = Failed, 3 = InProgress"
},
"ReportTypeEnum": {
"type": "integer",
"enum": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],
"description": "0=EmptyReport, 1=TourListReport, 2=DeliveryNoteReport, 3=SpecialEventReport, 4=SimulationManipulationReport, 5=ShipmentViewReport, 6=PoiDocumentReport, 7=ContainerLabelReport, 8=KpiTourReport, 9=KpiVehicleReport, 10=KpiDriverReport, 11=KpiQualityReport, 12=TradingOffersReport, 13=TradingDemandsReport, 14=KpiResourcePlanningReport, 15=KpiPositionReport, 16=KpiGroupReport, 17=PickupNoteReport, 18=KpiTsg, 19=KpiExamGroupReport, 21=BarcodeHistory, 26=TourListActualArrivalsReport, 27=TransportPointReport, 28=ShipmentListReport, 29=WeeklyPrecombinedTourReport, 30=InvoicingOrderReport, 31=InvoicingPositionsReport, 32=TourDriverTaskReport, 33=RecurringOrdersReport, 34=WaySplitReport, 35=ScaleNoteReport, 36=PickupQuantityReport, 37=FlushingReport, 38=ProposalReport, 39=LoadUnitReport, 40=ParentShipmentReport"
}
}
}
{
"title": "WebhookTourDto",
"type": "object",
"properties": {
"id": { "type": "integer" },
"groupId": { "type": ["integer", "null"] },
"refId": { "type": ["string", "null"] },
"name": { "type": ["string", "null"] },
"note": { "type": ["string", "null"] },
"version": { "type": ["string", "null"] },
"timeStamp": { "type": ["string", "null"], "format": "date-time" },
"tourStatus": { "type": ["string", "null"] },
"vehicleId": { "type": ["integer", "null"] },
"vehicleRefId": { "type": ["string", "null"] },
"vehicleTSGRefId": { "type": ["string", "null"] },
"trailerid": { "type": ["integer", "null"] },
"trailerRefId": { "type": ["string", "null"] },
"trailerTSGRefId": { "type": ["string", "null"] },
"driverId": { "type": ["integer", "null"] },
"driverRefId": { "type": ["string", "null"] },
"customField1": { "type": ["string", "null"] },
"customField2": { "type": ["string", "null"] },
"customField3": { "type": ["string", "null"] },
"customField4": { "type": ["string", "null"] },
"customField5": { "type": ["string", "null"] },
"customField6": { "type": ["string", "null"] },
"date": { "type": ["string", "null"], "format": "date", "description": "LOCAL time, serialized as date-only via WebhookDateConverter" },
"tillDate": { "type": ["string", "null"], "format": "date", "description": "LOCAL time, serialized as date-only via WebhookDateConverter" },
"fixStartTime": { "type": ["string", "null"], "pattern": "^-?\\d+\\.?\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$", "description": "TimeSpan serialized as string (e.g. '08:30:00')" },
"scheduledStart": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"scheduledEnd": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"start": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"end": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"distance": { "type": ["integer", "null"] },
"actualDistance": { "type": ["integer", "null"] },
"plannedDrivingTime": { "type": ["integer", "null"] },
"actualDrivingTime": { "type": ["integer", "null"] },
"plannedTourTime": { "type": ["integer", "null"] },
"actualTourTime": { "type": ["integer", "null"] },
"precombinedTourNumber": { "type": ["string", "null"] },
"shipments": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookShipmentDto" }
}
},
"$defs": {
"WebhookShipmentDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"groupId": { "type": "integer" },
"refId": { "type": ["string", "null"] },
"source": { "type": ["string", "null"] },
"salesmanCode": { "type": ["string", "null"] },
"orderNumber": { "type": ["string", "null"] },
"note": { "type": ["string", "null"] },
"timeStamp": { "type": "string", "format": "date-time" },
"status": { "type": ["string", "null"] },
"fiscalStatus": { "type": ["string", "null"] },
"shipmentType": { "type": ["string", "null"] },
"customField1": { "type": ["string", "null"] },
"customField2": { "type": ["string", "null"] },
"customField3": { "type": ["string", "null"] },
"customField4": { "type": ["string", "null"] },
"customField5": { "type": ["string", "null"] },
"customField6": { "type": ["string", "null"] },
"customField7": { "type": ["string", "null"] },
"customField8": { "type": ["string", "null"] },
"customField9": { "type": ["string", "null"] },
"customField10": { "type": ["string", "null"] },
"precombinedTourNumber": { "type": ["string", "null"] },
"extSortOrderA": { "type": ["integer", "null"] },
"extSortOrderB": { "type": ["integer", "null"] },
"calculatedSortOrderA": { "type": ["integer", "null"] },
"calculatedSortOrderB": { "type": ["integer", "null"] },
"transportPoints": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookTransportPointDto" }
},
"shipmentReports": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookShipmentReportDto" }
},
"parentShipmentReports": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookShipmentReportDto" },
"description": "Reports stored on the split parent shipment (e.g. the parent delivery note); empty for shipments without a split parent"
},
"splitParentId": { "type": ["integer", "null"] },
"parentShipmentType": {
"oneOf": [
{ "type": "null" },
{ "$ref": "#/$defs/ShipmentTypeEnum" }
]
},
"splits": { "type": ["integer", "null"] },
"splitSortOrder": { "type": ["integer", "null"] },
"pickupLocationRefId": { "type": ["string", "null"] },
"dropoffLocationRefId": { "type": ["string", "null"] },
"isReadyForCommissioning": { "type": "boolean" }
}
},
"WebhookTransportPointDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"dropoffStop": { "type": "boolean" },
"sortOrder": { "type": "integer" },
"precombinedTourNumber": { "type": ["string", "null"] },
"scheduledArrival": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"scheduledDeparture": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"startActual": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"endActual": { "type": ["string", "null"], "format": "date-time", "description": "UTC time" },
"images": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookTransportPointImageDto" }
},
"status": {
"oneOf": [
{ "type": "null" },
{ "$ref": "#/$defs/StopStatusEnum" }
]
},
"driverTasks": {
"type": ["array", "null"],
"items": { "$ref": "#/$defs/WebhookDriverTaskDto" }
}
}
},
"WebhookTransportPointImageDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"transportPointId": { "type": "integer" },
"url": { "type": ["string", "null"] },
"lat": { "type": ["number", "null"] },
"lng": { "type": ["number", "null"] }
}
},
"WebhookShipmentReportDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"reportId": { "type": ["integer", "null"] },
"reportUrl": { "type": ["string", "null"] },
"timeStamp": { "type": ["string", "null"], "format": "date-time" },
"reportType": {
"oneOf": [
{ "type": "null" },
{ "$ref": "#/$defs/ReportTypeEnum" }
]
}
}
},
"WebhookDriverTaskDto": {
"type": "object",
"properties": {
"id": { "type": "integer" },
"type": { "$ref": "#/$defs/DriverTaskType" },
"status": { "$ref": "#/$defs/DriverTaskStatusEnum" },
"barCode": { "type": ["string", "null"] },
"scannerLat": { "type": ["number", "null"] },
"scannerLng": { "type": ["number", "null"] },
"quantityRequired": { "type": ["number", "null"] },
"quantityActual": { "type": ["number", "null"] },
"quantityEdited": { "type": ["number", "null"] }
}
},
"ShipmentTypeEnum": {
"type": "integer",
"enum": [0, 1, 2, 3, 4],
"description": "0=InitialLeg, 1=MainLeg, 2=FinalLeg, 3=Direct, 4=Undefined"
},
"StopStatusEnum": {
"type": "integer",
"enum": [0, 1, 2, 3, 9, 10, 11],
"description": "0=NotStarted, 1=Success, 2=Fail, 3=Warning, 9=InProgress, 10=WaitingAfterArrival, 11=WaitingBeforeDeparture"
},
"DriverTaskType": {
"type": "integer",
"enum": [1, 2, 3],
"description": "1=Pickup, 2=Dropoff, 3=Flushing"
},
"DriverTaskStatusEnum": {
"type": "integer",
"enum": [0, 1, 2, 3],
"description": "0=NotStarted, 1=Completed, 2=Failed, 3=InProgress"
},
"ReportTypeEnum": {
"type": "integer",
"enum": [0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,21,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40],
"description": "0=EmptyReport, 1=TourListReport, 2=DeliveryNoteReport, 3=SpecialEventReport, 4=SimulationManipulationReport, 5=ShipmentViewReport, 6=PoiDocumentReport, 7=ContainerLabelReport, 8=KpiTourReport, 9=KpiVehicleReport, 10=KpiDriverReport, 11=KpiQualityReport, 12=TradingOffersReport, 13=TradingDemandsReport, 14=KpiResourcePlanningReport, 15=KpiPositionReport, 16=KpiGroupReport, 17=PickupNoteReport, 18=KpiTsg, 19=KpiExamGroupReport, 21=BarcodeHistory, 26=TourListActualArrivalsReport, 27=TransportPointReport, 28=ShipmentListReport, 29=WeeklyPrecombinedTourReport, 30=InvoicingOrderReport, 31=InvoicingPositionsReport, 32=TourDriverTaskReport, 33=RecurringOrdersReport, 34=WaySplitReport, 35=ScaleNoteReport, 36=PickupQuantityReport, 37=FlushingReport, 38=ProposalReport, 39=LoadUnitReport, 40=ParentShipmentReport"
}
}
}
Netzwerk & Sicherheit
Protokoll und Port
Webhooks werden ausschliesslich via HTTPS auf Port 443 versandt. Die Webhook-URL muss in der x4fleet-Konfiguration mit https:// beginnen. Ein HTTP-Redirect auf Empfängerseite ist möglich, wird aber nicht empfohlen — die URL sollte direkt mit https:// konfiguriert werden.
Quell-IP-Adressen
Webhooks werden von der x4fleet-API-Infrastruktur (Azure App Service) versendet. Die ausgehenden IP-Adressen werden von Azure verwaltet und können sich bei Infrastrukturänderungen ändern. Produktion und Staging/Testing laufen auf separaten Azure-Umgebungen mit unterschiedlichen Outbound-IPs. Die aktuellen IP-Adressen können auf Anfrage beim x4fleet-Support erfragt werden.
Hinweis: gateway.x4fleet.com und gateway-staging.x4fleet.com sind die eingehenden API-Endpunkte für x4fleet-Clients — nicht die Quelle der ausgehenden Webhooks. Diese DNS-Namen eignen sich daher nicht für Firewall-Regeln auf Empfängerseite.
Empfehlung zur Absicherung
IP-Whitelisting ist technisch möglich, wird aber nicht empfohlen: Azure-Outbound-IPs sind nicht exklusiv und können sich ändern. X4fleet unterstützt folgende kryptografisch gesicherte Authentifizierungsmethoden, die unabhängig von IP-Adressen funktionieren:
- Basic Auth — Benutzername und Passwort im
Authorization-Header - Client-Zertifikat (mTLS) — x509-Zertifikat via Azure Key Vault