Integration of PoD, booking confirmation and other real time events
SWAT API support ability to dispatch notifications to the client about changes in bookings and vehicle assignment allowing for smooth integration with ERP
, OMS or CRM systems.Use cases include:
- Sending proof of delivery to the ERP once a bookings has been completed
- Sending confirmation of pickup
- Sending confirmation of booking assignment
- Sending a notification about booking rejection
- Sending notification of pickup or drop off failure
Explore webhooks Postman collection
Approach to integration
At the moment, webhooks do not support authentication and require open HTTPS access to the consuming endpoint. Security can be achieved through whitelisting SWAT server IP address.
Webhooks should be used for such use cases. Please review webhook documentation for details. Integration steps include:
- Configuring webhooks for a simulation
- Setting up filters for messages
- Testing that the messages arrive as expected
Logical diagram is provided below:
Driver application, a 3rd-party system or Postman (for testing) can be used to trigger notification that the order (booking
) status has changed using web request. Once a node status within the booking has changed, a preconfigured webhook will be triggered.Configuration of simulation can happen either at the level of a simulation, or simulation templates. In case of using simulation templates, each new simulation created based on that template will include inherited webhook configuration and therefore the configuration needs to be done only once for a project at a template level. This is often done by SWAT team at a project setup stage.
Lifecycle of events (if SWAT Driver App is used)
Assuming that relevant message_type has been subscribed
- On Booking/Order assignment to a vehicle (automatic after the optimization has been completed, or through manual adjustment) an event of
assignment. An event per each assigned order will be generated.
Example
{
"simulation_id": 165838,
"agent_type": "vehicle_group",
"message_type": "assignment",
"tracking_url": "https://<some_url>"
"data": {
"vehicle_id": 1886660,
"vehicle_agent_id": "e8de0fa7-6196-4b29-87de-8768ca804b04",
"polyline5": "....",
"nodes": [
{
"id": 12911051,
"created_at": "2025-05-08T22:47:17.655090+00:00",
"modified_at": "2025-05-08T22:47:26.755836+00:00",
"uid": "dc701f0a-d3ab-4ca2-b7f6-517f238c5926",
"lat": 1.3786144,
"lon": 103.9420438,
"h3": "0040062446533035102040",
"location_name": "Central Street",
"location_code": "",
"display_name": "Central Street",
"booking_uid": "fc3abbab-d463-49e9-9927-de4c88681306",
"booking_id": 6602801,
"customer_id": null,
"open_time_ts": "2025-05-09T12:30:00+00:00",
"close_time_ts": "2025-05-09T12:45:00+00:00",
"close_time_ts_dynamic": "2025-05-09T12:45:00+00:00",
"service_time": 300.0,
"demand": {
"sample": 1
},
"status": "assigned",
"node_type": "pickup",
"assigned_vehicle_id": 1886660,
"simulation_id": 165838,
"assignment_order": 0,
"scheduled_ts": "2025-05-09T12:30:00+00:00",
"visited_at_ts": null,
"completed_service_at": null,
"started_service_at_ts": null,
"walking_time_to_node": 0.0,
"walking_distance_to_node": 0.0,
"min_trip_duration": null,
"max_trip_duration": 30540.0,
"fixed_route_walk_time": null,
"fixed_route_ride_time": null,
"fixed_route_wait_time": null,
"fixed_route_journey_time": null,
"fixed_route_is_unreachable": false,
"cancelled_at_ts": null,
"penalty": 100000000,
"lifo_order_check": false,
"lifo_order_penalty": null,
"groups": [],
"matrix_timestamp": "2025-05-09T12:30:00+00:00",
"geofence_ids": [],
"geofence_id": null,
"transit_stop_id": null,
"transit_stop_street": null,
"transit_stop_type": null,
"transfer_type": "depart_at",
"weight": null,
"trip_cost": 0.0,
"initial_open_time_ts": null,
"initial_max_trip_duration": null,
"initial_close_time_ts": null,
"initial_close_time_ts_dynamic": null,
"max_slack": null,
"slack": 0.0,
"data": {
"phone": null,
"remarks": null,
"username": null,
"external_id": "1627132_1",
"pickup_city": "Singapore",
"dropoff_city": "Singapore",
"instructions": null,
"customer_name": null,
"pickup_region": "Singapore",
"customer_name2": null,
"customer_phone": null,
"dropoff_region": "Singapore",
"order_identity": {
"external_id": "1627132_1",
"simulation_id": 165838
},
"pickup_address": "Central Street",
"pickup_country": "SG",
"dropoff_address": "Ube street",
"dropoff_country": "SG",
"raw_order_record": {
"date": "2025-05-09",
"demand": {
"sample": "1"
},
"external_id": "1627132_1",
"demand_load_1": "1",
"demand_type_1": "sample",
"label_operator": "OR",
"multipleDemand": {
"demand_type_1": {
"sample": "1"
}
},
"pickup_address": "Central Street",
"vehicle_labels": {
"or": [
"somelabel"
]
},
"dropoff_address": "Ube street",
"pickup_zip_code": "",
"dropoff_zip_code": "",
"pickup_location_lat": "1.3786144",
"pickup_location_lon": "103.9420438",
"pickup_open_time_ts": "20:30",
"pickup_service_time": "300",
"dropoff_location_lat": "1.3245751",
"dropoff_location_lon": "103.8926381",
"dropoff_open_time_ts": "20:30",
"dropoff_service_time": "0",
"pickup_close_time_ts": "20:45",
"dropoff_close_time_ts": "23:59",
"vehicle_characteristics": {}
},
"pickup_postal_code": null,
"pickup_unit_number": null,
"dropoff_postal_code": null,
"dropoff_unit_number": null,
"pickup_location_lat": 1.3786144,
"pickup_location_lon": 103.9420438,
"pickup_customer_name": null,
"pickup_location_name": "Central Street",
"dropoff_customer_name": null,
"is_pickup_end_of_trip": null,
"pickup_customer_name2": null,
"pickup_customer_phone": null,
"dropoff_customer_name2": null,
"dropoff_customer_phone": null,
"geofence_definition_strategy": null
},
"boarding_pass": "973",
"partial_route_index": null,
"finalization_type": "min",
"allow_jump": false,
"estimated_earliest_arrival_ts": null,
"estimated_scheduled_ts": null,
"vehicle_characteristics": {},
"offer_should_be_auto_accepted": null,
"dynamic_break": null,
"user_accepted_offer_at": null,
"is_invalidated": null,
"time_windows": null,
"booking_shipment_external_id": null
},
{
"id": 12911052,
"created_at": "2025-05-08T22:47:17.655350+00:00",
"modified_at": "2025-05-08T22:47:26.755836+00:00",
"uid": "cdae9fd7-f2b3-4f90-a1ab-48c143f0a5da",
"lat": 1.3245751,
"lon": 103.8926381,
"h3": "0040062446531120132442",
"location_name": "Ube street",
"location_code": "",
"display_name": "Ube street",
"booking_uid": "fc3abbab-d463-49e9-9927-de4c88681306",
"booking_id": 6602801,
"customer_id": null,
"open_time_ts": "2025-05-09T12:30:00+00:00",
"close_time_ts": "2025-05-09T15:59:00+00:00",
"close_time_ts_dynamic": "2025-05-09T15:59:00+00:00",
"service_time": 0.0,
"demand": {
"sample": -1
},
"status": "assigned",
"node_type": "dropoff",
"assigned_vehicle_id": 1886660,
"simulation_id": 165838,
"assignment_order": 1,
"scheduled_ts": "2025-05-09T12:48:26.640000+00:00",
"visited_at_ts": null,
"completed_service_at": null,
"started_service_at_ts": null,
"walking_time_to_node": 0.0,
"walking_distance_to_node": 0.0,
"min_trip_duration": null,
"max_trip_duration": 30540.0,
"fixed_route_walk_time": null,
"fixed_route_ride_time": null,
"fixed_route_wait_time": null,
"fixed_route_journey_time": null,
"fixed_route_is_unreachable": false,
"cancelled_at_ts": null,
"penalty": 100000000,
"lifo_order_check": false,
"lifo_order_penalty": null,
"groups": [],
"matrix_timestamp": "2025-05-09T15:59:00+00:00",
"geofence_ids": [],
"geofence_id": null,
"transit_stop_id": null,
"transit_stop_street": null,
"transit_stop_type": null,
"transfer_type": "depart_at",
"weight": null,
"trip_cost": 0.0,
"initial_open_time_ts": null,
"initial_max_trip_duration": null,
"initial_close_time_ts": null,
"initial_close_time_ts_dynamic": null,
"max_slack": null,
"slack": 0.0,
"data": {
"phone": null,
"remarks": null,
"username": null,
"external_id": "1627132_1",
"pickup_city": "Singapore",
"dropoff_city": "Singapore",
"instructions": null,
"customer_name": null,
"pickup_region": "Singapore",
"customer_name2": null,
"customer_phone": null,
"dropoff_region": "Singapore",
"order_identity": {
"external_id": "1627132_1",
"simulation_id": 165838
},
"pickup_address": "Central Street",
"pickup_country": "SG",
"dropoff_address": "Ube street",
"dropoff_country": "SG",
"raw_order_record": {
"date": "2025-05-09",
"demand": {
"sample": "1"
},
"external_id": "1627132_1",
"demand_load_1": "1",
"demand_type_1": "sample",
"label_operator": "OR",
"multipleDemand": {
"demand_type_1": {
"sample": "1"
}
},
"pickup_address": "Central Street",
"vehicle_labels": {
"or": [
"somelabels"
]
},
"dropoff_address": "Ube street",
"pickup_zip_code": "",
"dropoff_zip_code": "",
"pickup_location_lat": "1.3786144",
"pickup_location_lon": "103.9420438",
"pickup_open_time_ts": "20:30",
"pickup_service_time": "300",
"dropoff_location_lat": "1.3245751",
"dropoff_location_lon": "103.8926381",
"dropoff_open_time_ts": "20:30",
"dropoff_service_time": "0",
"pickup_close_time_ts": "20:45",
"dropoff_close_time_ts": "23:59",
"vehicle_characteristics": {}
},
"pickup_postal_code": null,
"pickup_unit_number": null,
"dropoff_postal_code": null,
"dropoff_unit_number": null,
"pickup_location_lat": 1.3786144,
"pickup_location_lon": 103.9420438,
"pickup_customer_name": null,
"pickup_location_name": "Central Street",
"dropoff_customer_name": null,
"is_pickup_end_of_trip": null,
"pickup_customer_name2": null,
"pickup_customer_phone": null,
"dropoff_customer_name2": null,
"dropoff_customer_phone": null,
"geofence_definition_strategy": null
},
"boarding_pass": "572",
"partial_route_index": null,
"finalization_type": "min",
"allow_jump": false,
"estimated_earliest_arrival_ts": null,
"estimated_scheduled_ts": null,
"vehicle_characteristics": {},
"offer_should_be_auto_accepted": null,
"dynamic_break": null,
"user_accepted_offer_at": null,
"is_invalidated": null,
"time_windows": null,
"booking_shipment_external_id": null
}
],
"edges": [
{
"from_node_id": 12911051,
"to_node_id": 12911052,
"polyline5": "...",
"edge_type": "between_nodes"
}
]
},
"current_sim_ts": "2025-05-08T22:47:26.157793+00:00",
"server_ts": "2025-05-08T22:48:23.719827+00:00",
"transmit_to_websocket": true,
"agent_id": null,
"user_id": null
}
- On Boooking/Order rejection (as a result of optimization a booking is rejected and can not be assigned to a vehicle) an event of type
no_offerwill be issued. There will be a single event for one optimization and it may include multiple bookings that wouldn't be optimized and assigned to a vehicle.
Example
{
"simulation_id": 165837,
"agent_type": "scheduler",
"message_type": "no_offer",
"data": {
"booking_ids": [
6602761,
6602779
],
"booking_uids": [
"526f8cfd-4814-4365-98a1-e2333c6bc9f3",
"23040721-0b5c-4d42-9dd6-46d561e4a573"
]
},
"current_sim_ts": "2025-05-08T22:31:50.871386+00:00",
"server_ts": "2025-05-08T22:32:31.930735+00:00",
"transmit_to_websocket": true,
"agent_id": null,
"user_id": null
}
- Once a vehicle can go live (i.e. for current time falling within the simulation start ane end time boundaries, and is between a vehicle's start and end time), an event of
vehicle_arrivaltype will be generated each few minutes for each vehicle. This is useful for getting live ETA of the vehicle.
Example
{
"simulation_id": 165837,
"agent_type": "vehicle",
"message_type": "vehicle_arrival",
"data": {
"booking_id": 6602769,
"booking_uid": "095796ae-d630-4b1c-875b-d311cc376ccc",
"node_id": 12910987,
"node_uid": "299c60e3-ed3e-4aac-8933-0635ec594504",
"node_type": "pickup",
"estimated_earliest_arrival_ts": "2025-05-08T22:40:01.251570+00:00",
"estimated_scheduled_ts": "2025-05-09T01:30:00+00:00",
"scheduled_ts": "2025-05-09T01:30:00+00:00",
"vehicle_id": 1886604,
"vehicle_agent_id": "08785064-406a-44d0-9e17-1ebaccb5d79d"
},
"current_sim_ts": "2025-05-08T22:40:01.251570+00:00",
"server_ts": "2025-05-08T22:40:01.251570+00:00",
"transmit_to_websocket": false,
"agent_id": null,
"user_id": null
}
- On a successful pickup, a
node_statusevent will be issued. This event will be generated for each successful pickup event.
Example
{
"simulation_id": 165838,
"agent_type": "vehicle",
"message_type": "node_status",
"data": {
"node_uid": "f749a1f3-3ef4-493f-aff4-b9e25a23cdd0",
"status": "completed",
"vehicle_id": 1886760,
"node_id": 12911043,
"node_type": "pickup",
"booking_uid": "03550997-1ee0-4f5e-9cfa-267075b612ae",
"booking_id": 6602797,
"action_data": {
"action_type": "pickup_success",
"lat": -43.5481285,
"lon": 172.6854415,
"driver_uid": null,
"image_urls": [
"https://sgerp-stage.d.gcdev.swatrider.com/api/v2/microservices/image/c330dd78-f4b0-4bab-a6ef-23faf3597fe3"
],
"data": {
"driver_note": {
"pickup_items": {
"Samples": 50
}
}
}
},
"is_confirmation": true
},
"current_sim_ts": "2025-05-09T10:53:18.976000+12:00",
"server_ts": "2025-05-08T22:53:19.218878+00:00",
"transmit_to_websocket": false,
"agent_id": "467e618f-84ed-4b91-bfa9-e79020e394bf",
"user_id": 13529
}
- On a failed pickup, a
fail_to_boardevent will be issued. This event will be generated for each failed to pickup event.
Example
{
"simulation_id": 165987,
"agent_type": null,
"message_type": "fail_to_board_confirmation",
"data": {
"booking_ids": [
6605341
],
"booking_uids": []
},
"current_sim_ts": "2025-05-09T20:42:59.003000+12:00",
"server_ts": "2025-05-09T08:42:59.648019+00:00",
"transmit_to_websocket": false,
"agent_id": null,
"user_id": null
}
- On a successful delivery (drop off) a
node_statusevent will be issued. This event wil be generated for each successful drop off event.
Example
{
"simulation_id": 165839,
"agent_type": "vehicle",
"message_type": "node_status",
"data": {
"node_uid": "4f554055-5f6f-400b-9c14-b404fa7c4ee5",
"status": "completed",
"vehicle_id": 1886918,
"node_id": 12911150,
"node_type": "dropoff",
"booking_uid": "b1fa1f17-efbe-4504-a220-bc517c1c6d32",
"booking_id": 6602850,
"action_data": {
"action_type": "proof_of_delivery",
"lat": -43.5481273,
"lon": 172.6854356,
"driver_uid": null,
"image_urls": [
"https://sgerp-stage.d.gcdev.swatrider.com/api/v2/microservices/image/8f8cb90f-b75f-4f50-b768-d52b011b269f"
],
"data": {
"driver_note": {}
}
},
"is_confirmation": true
},
"current_sim_ts": "2025-05-09T11:29:41.323000+12:00",
"server_ts": "2025-05-08T23:29:41.579335+00:00",
"transmit_to_websocket": false,
"agent_id": "5839cf90-fafc-4d0e-94f4-b87be50a4a1e",
"user_id": 13529
}
- On a failed delivery (drop off) a
node_statusevent will be issued. This event wil be generated for each successful drop off event.
Example
{
"simulation_id": 165839,
"agent_type": "vehicle",
"message_type": "node_status",
"data": {
"node_uid": "6816e777-d510-43d7-acd7-a3ccd28968b2",
"status": "fail_to_deliver",
"vehicle_id": 1886918,
"node_id": 12911106,
"node_type": "dropoff",
"booking_uid": "f0d9e122-181a-4b06-8de7-aed7aafca879",
"booking_id": 6602828,
"action_data": {
"action_type": "failure_of_delivery",
"lat": -43.5481273,
"lon": 172.6854356,
"driver_uid": null,
"image_urls": [],
"data": {
"comment": "n99ne here",
"driver_note": {}
}
},
"is_confirmation": true
},
"current_sim_ts": "2025-05-09T11:29:41.323000+12:00",
"server_ts": "2025-05-08T23:29:41.583098+00:00",
"transmit_to_websocket": false,
"agent_id": "5839cf90-fafc-4d0e-94f4-b87be50a4a1e",
"user_id": 13529
}
Setting up relevant configuration
PATCH https://<base_url>/api/v2/simulation/<simulation_id>
{
"data": {
...
"messaging_webhook_url" : "https://<webhook_url>",
"messaging_webhook_message_types" : ["node_status"]
...
}
}
It's crucial to follow the recommended approach to retain the existing configuration. This involves retrieving the data object first using GET https://<base_url>/api/v2/simulation/<simulation_id>, adding the webhook configuration to the data field, and then executing PATCH with the complete data object. This method ensures that the current settings are preserved.
If node_status is selected in the message filter, then webhook will be triggered when a status of any node
Optionally, assignment message can be added to the list of messages in the messaging_webhook_message_types list if the consuming application needs to be notified when a booking gets assigned (or scheduled for delivery) with a vehicle. Typically, this happens during route optimization run, or when ad-hoc bookings are added to the simulation for execution (for example, in the middle of the working shift).
Notifying the system that drop off has happened
Each booking
contains at least two nodes representing pickup and drop off location. This is the reason why a node should be used to trigger a webhook (either for drop off or pickup within the same booking). To find out which nodes belong to the booking,GET <base_url>/api/v2/node?booking=<booking_id> can be used.This step is necessary only if the consuming application needs to manage booking states in SWAT backend, for example, a booking state can be changed in ERP, or is a customer driver application. If SWAT Driver Application is used, this step can be skipped since the driver workflow will be used to change the states of the booking automatically.
For example, to confirm drop off of a booking, this request can be used:
POST https://<base_url>/api/v2/microservices/node_status
{
"simulation_id": 172571, //Simulation id to update the data for
"data": {
"booking_id": 22151625, //Booking integer identifier to update th value for
"status": "completed", //New status of the node. Supported node statuses:
"vehicle_id": 17590317,
"booking_uid": "e438ab3d-b33a-572d-a114-0a5490e07f40",
"node_type": "dropoff",
"node_id": 48332514,
"node_uid": "a1d1a6ae-9a0d-40c1-a633-3d6ef05cf7b9"
},
"current_sim_ts": "2024-11-16T18:26:22Z"
}
To inform the system of an unsuccessful pickup, send the following example payload:
POST https://<base_url>/api/v2/microservices/node_status
{
"simulation_id": 172571, //Simulation id to update the data for
"data": {
"booking_id": 22151625, //Booking integer identifier to update th value for
"status": "fail_to_board", //New status of the node. Supported node statuses:
"vehicle_id": 17590317,
"booking_uid": "e438ab3d-b33a-572d-a114-0a5490e07f40",
"node_type": "pickup",
"node_id": 48332514,
"node_uid": "a1d1a6ae-9a0d-40c1-a633-3d6ef05cf7b9",
"action_data": {
"lat":0,
"lon":0,
"action_type": "cancelled",
"data":
{
"comment": "cancelled"
}
}
},
"current_sim_ts": "2024-11-16T18:26:22Z"
}
In addition, there is an option to add some specific information about the change of the node including driver comments, actual location of the delivery, and images of the documents. The following example demonstrates this:
POST https://<base_url>/api/v2/microservices/node_status
{
"data": {
"status": "completed",
"node_id": 2349069,
"node_uid": "32b0ef45-6baa-44aa-8203-ce9312ab645b",
"node_type": "dropoff",
"booking_id": 1122584,
"vehicle_id": 182389,
"action_data": {
"lat": 1.3,
"lon": 103.8,
"data": {},
"image_urls": [
"https://firebasestorage.googleapis.com:443/v0/b/<some_url>"
],
"action_type": "proof_of_delivery",
"action_subtype": "photo"
},
"booking_uid": "efbbe0f6-a80c-520b-81fa-5f1621cfd90b"
},
"simulation_id": 19138,
"current_sim_ts": "2022-05-16T18:30:57Z"
}
Also, if multiple nodes needed to be updated, bulk mode update API can be used:
POST https://<base_url>/api/v2/microservices/node_status_list
{
"simulation_id": 123,
"current_sim_ts": "string",
"data": {
"vehicle_id": 123,
"node_updates": [
{
"node_id": 123,
"status": "new",
"action_data": {}
}
]
}
}
In case of consumer using SWAT Driver App, notifications will be automatically generated with all required data by the mobile application. These node_status requests are only needed if a third-party field application is used, or, alternatively, confirmation of delivery comes from an external system such as ERP or OMS.
Receiving notification messages by the consumer through webhooks
Once the simulation settings are configured, expect messages about changes in node_status to arrive to the set endpoint via POST method. Example payload:
{
"simulation_id": 172571,
"agent_type": "vehicle",
"message_type": "node_status",
"data": {
"node_uid": "a1d1a6ae-9a0d-40c1-a633-3d6ef05cf7b9",
"status": "completed",
"vehicle_id": 17590317,
"node_id": 48332514,
"node_type": "dropoff",
"booking_uid": "e438ab3d-b33a-572d-a114-0a5490e07f40",
"booking_id": 22151625,
"action_data": null,
"is_confirmation": true
},
"current_sim_ts": "2024-11-16T18:26:22+00:00",
"server_ts": "2024-09-10T04:33:23.364180",
"transmit_to_websocket": false,
"agent_id": "daae025f-f21d-4c65-b901-45e139283667",
"user_id": 57638
}
For possible configuration of the fields please refer the reference documentation examples for POST https://<base_url>/api/v2/microservices/node_status endpoint.
Retrieving node and booking status after the webhook has been received
In case the webhook message doesn't include information required by the consumer (for example, mapping with some customer identifiers used by the consumer), an additional request may be needed to retrieve all data for a relevant node
(and booking).Example of the request can look like this where node_id is a node identifier from the webhook message:
GET https://<base_url>/api/v2/node/{node_id}
This request will return all data associated with that node including node_type such as dropoff or pickup, as well it's current status
Since a booking references at least 2 nodes (such as pick up and drop off), and webhook is triggered for only one node update, each booking is fully completed when all nodes in the booking are completed.
Supported data in the notification
Notification can include optional fields in action_data object, such as images for proof of delivery, driver notes, actual location where the drop off occurred.
For other relevant statuses including POD, please refer to POST https://<base_url>/api/v2/microservices/node_status examples that include responses for failed drop off, pickup and pick up with POD.
{
"action_data": {
"type": "object",
"description": "Optional data associated with the event (for example, a link to PoD image)",
"properties": {
"lat": {
"type": "number",
"description": "Latitude of the vehicle when the action happened"
},
"lon": {
"type": "number",
"description": "Longtitude of the vehicle when the action happened"
},
"action_type": {
"type": "string",
"description": "Type of action"
},
"data": {
"type": "object",
"properties": {
"comment": {
"type": "string",
"description": "optional comment that a driver can leave"
}
}
},
"image_urls": {
"type": "array",
"description": "URLs of uploaded attachments (such as photos of POD)",
"items": {
"type": "string",
"format": "uri"
}
}
}
}
}
Retrieving image(s) for proof of delivery
As discussed in webhook message the message may contain an optional field action_data.image_urls[] which includes a list of images attached to the notification and the node. To retrieve an image two steps need to be executed:
An image can be attached to either drop off or pick up point depending on the scenario (for milkruns for example, it could be both). While normally for delivery applications proof of delivery is available for drop off nodes. In this case, request the images only for the messages including data.node_type=dropoff.
Obtaining a list of images for a node
To retrieve a list of available images for a node use
GET https://<base_url>/api/v2/imagestoreitem?node=<node_id>
where node_id should be taken from the webhook message data.node_id field. Result will include of images available for that node. In the example below a node has two images attached to it (a signature and a photo of the delivered goods). If SWAT Driver app is used, the image filename in the response field objects[].image can be used to differentiate between the signature and the delivery\pickup photos.
See JSON payload
{
"meta": {
"has_more": false,
"limit": 20,
"next": null,
"offset": 0,
"previous": null,
"total_count": 2
},
"objects": [
{
"booking": "/api/v2/booking/5888352",
"created_at": "2024-09-30T09:04:40.780442+00:00",
"description": "None",
"driver": null,
"h3": null,
"id": "005afc5d-66d8-45f5-a8f8-2f6397f09758",
"image": "http://mot-stage-dev.s3.amazonaws.com/sgerp/sgerp-stage/image_store/swat_delivery_test_DO.jpg",
"lat": 0,
"lon": 0,
"modified_at": "2024-09-30T09:04:40.780466+00:00",
"name": "swat delivery 253_PU_1",
"node": "/api/v2/node/11452232",
"project": "/api/v2/project/550",
"resource_uri": "/api/v2/imagestoreitem/005afc5d-66d8-45f5-a8f8-2f6397f09758",
"simulation": "/api/v2/simulation/122093",
"user": "/api/v2/user/4014",
"vehicle": "/api/v2/vehicle/1726343"
},
{
"booking": "/api/v2/booking/5888352",
"created_at": "2024-09-30T09:04:41.297751+00:00",
"description": "None",
"driver": null,
"h3": null,
"id": "ba9a077f-806b-4ccb-8761-e80f29b8e092",
"image": "http://mot-stage-dev.s3.amazonaws.com/sgerp/sgerp-stage/image_store/swat_delivery_test_signature.jpeg",
"lat": 0,
"lon": 0,
"modified_at": "2024-09-30T09:04:41.297774+00:00",
"name": "swat_delivery_253_PU_signature",
"node": "/api/v2/node/11452232",
"project": "/api/v2/project/550",
"resource_uri": "/api/v2/imagestoreitem/ba9a077f-806b-4ccb-8761-e80f29b8e092",
"simulation": "/api/v2/simulation/122093",
"user": "/api/v2/user/4014",
"vehicle": "/api/v2/vehicle/1726343"
}
]
}
Downloading an image
To download an image use
GET https://<base_url>/api/v2/microservices/image/<image_uid>
where image_uid is th value of objects[].id field.
This request will return image/png binary stream containing the actual image. Repeat this request for other images if needed.
Drop off or pick up failure
The API client (or SWAT Driver App) is responsible for preparing and sending a message to the backend regarding failed drop-offs and pick-ups. Different workflows are implemented for handling failed drop-offs and pick-ups because, in the event of a failed pick-up, there is no need to perform a drop-off for that booking.
To start receiving message about failed drop offs and pick ups, the consumer needs to subscribe to two message types: node_status and fail_to_board.
Failed drop-off
The SWAT backend is notified about a failed drop-off by updating the corresponding node for that drop-off using the following request:
POST /api/v2/microservices/node_status
{
"simulation_id": 19138,
"current_sim_ts": "2022-05-16T18:34:00Z",
"data": {
"booking_uid": "367ce4d5-7f97-5fff-b8b7-65b3ed991ea7",
"node_id": 2349059,
"booking_id": 1122579,
"vehicle_id": 182389,
"status": "fail_to_deliver",
"node_type": "dropoff",
"action_data": {
"lat": 1.3,
"data": {
"comment": "Recipient not home"
},
"action_type": "failure_of_delivery",
"lon": 103.8,
"image_urls": []
},
"node_uid": "404a9948-df7c-4535-8c5a-ebd9ae5c40dc"
}
}
As a result of this request, a webhook message of the type node_status will be triggered. It will include the information from the action_data field and mark a corresponding booking as failed_to_deliver. While the node will remain assigned to a vehicle (which can be used to schedule redelivery of the booking), the node will also remain in the assigned state.
Webhook message will look like this:
{
"simulation_id": 124551,
"agent_type": "vehicle",
"message_type": "node_status",
"data": {
"node_uid": "02eb7d5c-0a92-4604-8181-0f663f4f9212",
"status": "fail_to_deliver",
"vehicle_id": 1737453,
"node_id": 11564954,
"node_type": "dropoff",
"booking_uid": "2bf03eec-e439-4dd6-afd3-ed9dca5286d7",
"booking_id": 5950159,
"action_data": {
"action_type": "failure_of_delivery",
"lat": 1.3,
"lon": 103.8,
"driver_uid": "",
"image_urls": [],
"data": {
"comment": "Recipient not home"
}
},
"is_confirmation": true
},
"current_sim_ts": "2024-10-16T18:34:00+00:00",
"server_ts": "2024-10-24T06:07:23.699668",
"transmit_to_websocket": false,
"agent_id": "3d3d1b35-0010-434d-ac2d-a8c99722f1c3",
"user_id": 13529
}
Failed pick-up
The SWAT backend receives notification of a failed drop-off by updating the corresponding node for that pick-up via the following request:
POST /api/v2/microservices/fail_to_board
{
"simulation_id": 124551,
"current_sim_ts": "2024-10-31T17:00:00.192934+00:00",
"data": {
"booking_ids": [
5950160
]
}
}
As a result of this request, a webhook message of type fail_to_board will be generated. The booking status will be updated to failed_to_board, nodes within the booking will be marked as failed_to_board, and a vehicle assigned to the node will be removed. Consequently, the booking will not be executable and will no longer participate in optimization processes.
Webhook message will have the following format:
{
"simulation_id": 124551,
"agent_type": "vehicle",
"message_type": "fail_to_board",
"data": {
"booking_ids": [
5950160
]
},
"current_sim_ts": "2024-10-31T17:00:00.192934+00:00",
"server_ts": "2024-10-24T05:44:39.713834",
"transmit_to_websocket": false,
"agent_id": "3d3d1b35-0010-434d-ac2d-a8c99722f1c3",
"user_id": 13529
}