Webhook spedizione / giro
Per informare proattivamente i sistemi dei clienti sulle modifiche agli ordini di trasporto/spedizioni e ai giri, è possibile configurare webhook in X4Fleet per queste due entità.
Per ogni entità esiste un elenco di eventi che possono attivare un webhook.
I webhook possono essere configurati dagli utenti amministratori in X4Fleet sotto Impostazioni > Impostazioni > "Notifiche di stato (Webhook)".

Per l'autenticazione della richiesta POST è possibile memorizzare una coppia nome utente/password o un certificato x509.
Se è necessario un metodo diverso o X4Fleet non deve inviare richieste al sistema del cliente, queste possono essere recuperate proattivamente (p.es. ogni 5 minuti) anche dal sistema del cliente. (Attivare la casella di controllo "Usa solo archivio webhook" per questo.)
Anche se il payload è molto esteso, si consiglia di considerare il webhook solo come trigger per "Hey, è successo qualcosa alla spedizione X. Vai a controllare!" — cioè come conseguenza viene attivato un GET Shipment o GET Tour dal sistema del cliente per ottenere ulteriori dettagli. Questo perché il payload webhook deve diventare più snello nel lungo periodo e le nuove strutture dati verranno integrate solo negli endpoint corrispondenti.
Endpoint:
GET /x4gateway/v1/export/webhookShipmentMessages
GET /x4gateway/v1/export/webhookTourMessages
Trigger spedizione / ordine di trasporto
- In elaborazione - La spedizione è stata creata ma è ancora in elaborazione o mancano informazioni
- Rilasciata - La spedizione è stata rilasciata manualmente o tramite impostazione per la pianificazione su un giro
- Pianificata - La spedizione è stata assegnata a un giro
- Ritiro completato
- Consegna completata
- Frazionamento quantità - La spedizione è stata suddivisa in N spedizioni aggiuntive perché la quantità non può essere gestita in un unico viaggio
- Frazionamento percorso - La spedizione è stata suddivisa in N spedizioni aggiuntive perché le merci vengono spostate attraverso N depositi prima di raggiungere la destinazione
- Completata
- Completata con riserva - Ci sono discrepanze tra l'esecuzione e la pianificazione (p.es. è stato caricato meno di quanto pianificato)
- Riaperta - Qualcosa nella spedizione deve essere corretto
Trigger giro
- In pianificazione - È stata assegnata una prima spedizione al giro (di solito non rilevante per il sistema del cliente)
- Pianificato - Il giro è stato calcolato o ottimizzato (di solito non rilevante per il sistema del cliente)
- Rilasciato - Il giro è stato rilasciato per l'esecuzione (a seconda del processo, possono trascorrere diversi giorni tra il rilascio e l'esecuzione)
- Nuovamente rilasciato - Il giro è stato richiamato, eventualmente modificato e nuovamente rilasciato per l'esecuzione
- In revisione - Il giro era rilasciato ma è stato richiamato per una correzione
- Revisionato - Dopo "In revisione" quando ricalcolato/ottimizzato
- In esecuzione - Il conducente ha avviato il giro rilasciato
- Completamente terminato - Tutti i punti di trasporto e le spedizioni completati secondo la pianificazione
- Incompletamente terminato - Discrepanze tra l'esecuzione completata e la pianificazione del dispatcher
- Non iniziato
- In pausa - p.es. durante la pausa del conducente o quando il veicolo è stato precaricato il giorno precedente e il giro attende la ripresa dell'esecuzione
- * (A) - Questo suffisso significa che il giro era in stato "In esecuzione" prima di passare al nuovo stato
- * (P) - Questo suffisso significa che il giro era in stato "In pausa" prima di passare al nuovo stato
Un webhook del giro viene inviato solo se lo stato del giro cambia effettivamente. Se un'azione viene ripetuta nello stesso stato (p.es. vengono assegnate ulteriori spedizioni a un giro già "In pianificazione"), non viene inviato alcun ulteriore webhook del giro. Eccezione: se il modulo "Revisione della spedizione" è attivo, i webhook del giro a partire dall'inizio dell'esecuzione (dallo stato "In esecuzione") vengono inviati solo quando tutte le spedizioni del giro sono state revisionate; il webhook del giro viene quindi inviato con lo stato attuale del giro, anche senza cambio di stato, a condizione che il webhook sia configurato per questo stato. I cambi di stato intermedi non vengono inviati a posteriori. Questa limitazione non si applica ai webhook delle spedizioni.
Schema JSON per i webhook ricevuti
{
"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": "ora UTC" },
"scheduledDeparture": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"startActual": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"endActual": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"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": "ora LOCALE, serializzata come solo data tramite WebhookDateConverter" },
"tillDate": { "type": ["string", "null"], "format": "date", "description": "ora LOCALE, serializzata come solo data tramite WebhookDateConverter" },
"fixStartTime": { "type": ["string", "null"], "pattern": "^-?\\d+\\.?\\d{2}:\\d{2}:\\d{2}(\\.\\d+)?$", "description": "TimeSpan serializzato come stringa (p.es. '08:30:00')" },
"scheduledStart": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"scheduledEnd": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"start": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"end": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"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": "ora UTC" },
"scheduledDeparture": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"startActual": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"endActual": { "type": ["string", "null"], "format": "date-time", "description": "ora UTC" },
"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"
}
}
}
Rete & sicurezza
Protocollo e porta
I webhook vengono inviati esclusivamente tramite HTTPS sulla porta 443. L'URL del webhook deve sempre iniziare con https:// nella configurazione di x4fleet. Un redirect HTTP lato destinatario è possibile, ma si consiglia di configurare direttamente l'URL con https://.
Indirizzi IP sorgente
I webhook vengono inviati dall'infrastruttura API di x4fleet (Azure App Service). Gli indirizzi IP in uscita sono gestiti da Azure e possono cambiare in caso di modifiche all'infrastruttura. La produzione e lo staging/testing operano su ambienti Azure separati con indirizzi IP in uscita diversi. Gli indirizzi IP attuali possono essere richiesti al supporto x4fleet.
Nota: gateway.x4fleet.com e gateway-staging.x4fleet.com sono gli endpoint API in entrata per i client x4fleet — non la fonte dei webhook in uscita. Questi nomi DNS non sono quindi adatti alle regole del firewall lato destinatario.
Raccomandazioni per la sicurezza
Il filtraggio per IP è tecnicamente possibile, ma non raccomandato, poiché gli IP in uscita di Azure non sono esclusivi e possono cambiare. X4fleet supporta i seguenti metodi di autenticazione, crittograficamente sicuri e indipendenti dagli indirizzi IP:
- Basic Auth — Nome utente e password nell'intestazione
Authorization - Certificato client (mTLS) — Certificato x509 tramite Azure Key Vault