# Planned Trip Push ## Introduction Simacan continously gets planning data from various parties to update the state in the Simacan Control Tower. This planning data can be shared automatically so you can integrate this information as soon as possible in your own systems. Planning data and all its updates can be pushed via HTTP PUT or POST methods to your platforms HTTPS endpoint. We call this the planningshub push service. Using this service you can process our data into your own, or partner platform. Updates are real-time. Once you've set up this push service, no further manual action required. The goal of this page is to explain the structure of the OTM5 messages that are shared using the planning-push. For further information on how to initiate a connection see [the overview page](/docs/data-export/overview). ## What is not included Planning data that is enriched along the way, such as the eCMR status, vehicle location update metadata, realised or estimated times, operationally made comments as can be seen in Control Tower. Our updates will always contain the complete state of the planning. ## What updates can I expect You will receive all updates to the planning for each trip on which your organization has a role which in practice means you are either the shipper, the carrier, or a subcontractor. For each trip you will receive a full trip planning when it is mutated. Examples of mutations are vehicle couplings, added remarks, or stop mutations, so this can result in tens of updates. As some of these updates can occur post-trip it is possible that updates are sent when the trip is already been finished. ### Filtering out your own updates When you are the carrier or subcontractor of a trip you are also allowed to mutate the trip, for instance using the carrier enrichment endpoint. By default we will not send you the updates that are triggered by your own mutations though we can configure to send them if you do need these updates. ### What happens if a trip is re-assigned When you are the carrier or subcontractor of a trip and either the shipper or carrier re-assigns the trip to a different organization, we will send you a cancellation message. This allows you to remove the trip from your own systems such as the transport management system or driver application. There is one last case to consider: if your logistic role on the trip changes, for instance from carrier to subcontractor or vice-versa, we will only send you the updated trip, so no intermediate cancel message. ## Message Structure The messages in the planning push follow the **[OTM5 Trip Profile](/docs/otm5/otm5-trip-profile)**. The exact OpenAPI specification can be found [here](https://planned-trip-to-otm-service.services.simacan.com/api/v5) ### General structure See also the [general Trip Profile page](/docs/otm5/otm5-trip-profile) for more information about the general structure. ```md trip name externalAttributes status (only there when cancelled, actions are then empty) actors (shipper, carrier, subcontractor, driver) vehicle actions stop location start and end times actions wait/break load/unload consignment goods move from (location reference) to (location reference) actions wait/break move (first/last mile) stop ... ``` ### Trip The trip has the following properties: - The trip has a unique UUID that is used to identify this particular trip. This UUID is thus also used whenever the trip needs updates. Since not all planning systems work with UUIDs, it is optional. When not present the `tripId` in the external attributes will be used to deterministically generate a UUID. - A trip has an optional `name` (display name), which is to easily recognize it in the Control Tower. Note though that is doesn't have to be unique but usually is *for a single day* to differentiate trips on that day. - A trip has `externalAttributes`. * `tripId`: the ID of the trip as shown in the Simacan Control Tower, originates from the party providing the planning. * `shift` (optional): the 'shift' in which the trip belongs, used for grouping and filtering in the Simacan Control Tower. * `remark` (optional): remark on the trip. * All other values in the external attributes come from the planning system & the Simacan Control Tower just passes it through. Therefore we cannot guarantee whether they will always be present, consistency in usage, and what it stands for. - A trip at *some point* needs to be coupled to a vehicle for effective monitoring, but this does not need to happen when the planning is inserted. So the vehicle might be empty when receiving planning updates. - A trip is required to have `actions`. At least two stops are necessary. The one notably exception is when the trip is `cancelled`. No actions are present for cancelled trips. - A trip has `actors`, usually a shipper and a carrier, but also a driver and subcontractor are possible. An example could look like: ```json { "id": "2a8af6c6-e4d5-5dfb-9532-e8b17c3ffd88", "name": "2021-32-2-ABC", "externalAttributes": { "tripId": "2021-32-2-ABC-something-longer-for-uniqueness", "shift": "Morning shift", "customDataField": "the TMS send it's regards", "anotherCustomDataField": "<5 hours to declare>" }, "vehicle": {}, "actors": [], "actions": [] } ``` ### Actors Actors are organisations or individuals that have a role in the logistic operation. Within Simacan they can appear on the trip (shipper, carrier, subcontractor, driver), or on the consignment (consignee, consignor). The shipper and carrier are always on the trip level. The driver and subcontractor are optional. Also the consignor and consignee are optional on the consignment. Actors have the following properties: - An actor has a unique Simacan identifier (`externalId`). - An actor has one or multiple `roles`. ```json "actors": [ { "entity": { "id": "9ade6709-d76a-5406-883a-85c7df10fded", "externalAttributes": { "externalId": "unique_id_carrier" } }, "roles": [ "carrier" ], "associationType": "inline" }, { "entity": { "id": "56385b9c-704f-4520-8268-c1fa0e03840f", "externalAttributes": { "externalId": "unique_id_shipper" } }, "roles": [ "shipper" ], "associationType": "inline" }, ] ``` ### Vehicle At some point the trip will be coupled to a vehicle so actual location updates can be compared with the planned trip. However a vehicle is not required when inserting planning data. As a result the vehicle is also optionally present in the planned data push. Note that OTM distinguishes *towing* and *towed* 'vehicles' by modelling the latter as `transportEquipment` and not vehicles, so the `vehicle` field only contains information about the former. A vehicle thus contains the following properties: - A vehicle is either a true *vehicle*, a physical machine with cargo space able to transport goods. Or a device coupled to such a machine. - The vehicle can contain properties such as `fuel` (type), `licensePlate` and `vehicleType`. - The vehicle might contain a unique identifier in the external attributes. - The vehicle does **not** contain any information about trailers. This information is (optionally) present in the actions of the trip. ```json "vehicle": { "entity": { "id": "3de444dd-81cf-4e69-b27b-82e92e0dbda3", "externalAttributes": { "vehicleId": "my-external-id" }, "vehicleType": "truck", "fuel": "Euro95", "licensePlate": "AA-12-BB" }, "associationType": "inline" } ``` ### Actions The most interesting information of the trip is present in the actions. These contain the *locations* that need to be visited, when, and what happens on those locations. Actions consists of *stops* and *moves*. Stops contain the information of visiting a location between certain time intervals and doing other actions on that locations such as loading and unloading consignments. Moves contain the information of moving between the locations of a stop. On these moves other actions can be done as well, such as having a break, or following a specific route (first/last miles). Naturally, the actions of a trip thus always start and end with a stop, with moves in between. However, depending on the use case, moves are left out since they do not contain any relevant information. #### Stop A stop indicates visiting a location within a time interval and doing actions on that location. It consists of the following properties: - A stop has a `location`, `startTime` and an `endTime`. - A stop can have multiple `load` and `unload` actions; these actions have a `consignment`. - A stop optionally has a display `name`, `remark` and `sequenceNr`. - A stop optionally has a `stopId` within an `externalAttribute`, this identifier can be used for updating this stop. If none is present the UUID of the stop will be used. - A cancelled stop will not be present in subsequent messages. - A stop can have `externalAttributes`: * `stopId`: the ID of the stop as shown in the Simacan Control Tower, originates from the party providing the planning. * `returnFlowAllowed` (optional): Whether or not it is allowed to give back load carriers in the vehicle. * `monitoring` (optional): if present it will always have the value `administrative`, indicating that the stop is only there for administrative purposes and not actually visited. * All other values in the external attributes come from the planning system & the Simacan Control Tower just passes it through. Therefore we cannot guarantee whether they will always be present, consistency in usage, and what it stands for. - A stop optionally has time constraints, wich in code looks like: ```json { "id": "48c484f7-54ad-4209-b251-44abef26f6b0", "value": { "startTime": "2021-03-12T10:00:00Z", "endTime": "2021-03-12T11:00:00Z", "type": "timeWindowsConstraint" } } ``` A stop (with omitted location and consignment) could look like: ```json { "entity": { "id": "cd5be9b4-eb2e-50c1-bac9-d78d159c9d8e", "lifecycle": "planned", "externalAttributes": { "stopId": "stop123" }, "location": {}, "startTime": "2021-02-24T08:00:00Z", "endTime": "2021-02-24T08:20:00Z", "actions": [{ "entity": { "id": "85a48825-0d59-328b-b571-e3283a1f7fe7", "lifecycle": "planned", "consignment": {}, "startTime": "2021-02-24T08:00:00Z", "endTime": "2021-02-24T08:15:00Z", "actionType": "unload" }, "associationType": "inline" }, { "entity": { "id": "b7a632a2-4f2b-4efb-b75c-17132436cf39", "lifecycle": "planned", "consignment": {}, "startTime": "2021-02-24T08:15:00Z", "endTime": "2021-02-24T08:20:00Z", "actionType": "load" }, "associationType": "inline" } ], "sequenceNumber": 0, "constraint": { "entity": { "id": "10877d0c-ca94-459b-84aa-0cf10de35af6", "value": { "startTime": "2021-02-24T07:30:00Z", "endTime": "2021-02-24T09:30:00Z", "type": "timeWindowConstraint" }, "associationType": "inline" }, "actionType": "stop" } } } ``` ### Location Locations are the actual physical places visited during stops where actions - such as loading and unloading consignments - are being executed. The location follows the exact format in the [trip profile location](/docs/otm5/otm5-trip-profile#location). Note that the location is always inline on the stop and referenced on the moves. Also note that location georefence always is of type `latLonPointGeoReference`. Locations have the following properties: * The location contains a `name` used for display purposes. * The location optionally contains coordinates. * The location contains address information such as the `street`, `houseNumber`, `postalCode`, `city` and `country`. * The location contains a type. The `customer` is used for one-off (unmanaged) locations and are treated as sensitive data. They also do not appear in Master Data. The types `operationalBase` and `warehouse` are used for managed locations and appear in Master Data. * The location has optional contact details. This option can be used in case there is a contact at the location but it is neither the consignee nor the consignor. For example, to reach an administration desk or a security warden. Currently, we support the fields `phone, email, name, lastName, firstName`. * The location has `externalAttributes`: * `locationId`: the ID of the location as shown in the Simacan Control Tower, used to uniquely identify the location within Simacan. Doesn't necessarily have to be what was provided by the planning system. * `groupingAddressId` (optional): the location ID where the location belongs to. For example if this is a store location the `groupingAddressId` could be the distribution centre that delivers to goods for the store. * `customerLocationIdentifier` (optional): custom location identifier, used in the planning system. ### Consignment A consignment is the administrative label put on a set of goods that are shipped together. A consigment does not physically exist and serves only to group goods together, provide some additional information like consignor and consignee and have somethign that be tracked during the lifetime of shpping the goods. The consignment is present in the trip by being the subject of the `load`, `unload` and `handOver` actions. Within the Simacan platform the consignment has the following properties: - A consignment has a `type` (free text), this is what is known in the SCT as the *goodsFlowType*. - A consignment optionally has `goods`. Though goods are the *meat* of what is being transported, Simacan specializes in *monitoring* and thus is less concerned with what is actually shipped. A good has a quantity and optionally a productType, barCode en remark. Goods are always of the type `transportEquipment`. - Consignments can contain actors for the consignor and consignee. This can be the same actor. - Consignments can contain `externalAttributes`: * `orderId` (optional): The ID of the actual consignment in external systems. * `userId` (optional): The ID of the user receiving the consignment. * `trackTraceCode` (optional): the ID used for track & trace purposes, potentially in other systems. ```json { "id": "a556da93-46f3-4df5-8269-263bb337fde4", "actors": [ { "associationType": "inline", "entity": { "name": "some consignor" }, "roles": [ "consignor" ] }, { "associationType": "inline", "entity": { "name": "some consignee" }, "roles": [ "consignee" ] } ], "externalAttributes": { "orderId": "", "userId": "", "trackTraceCode": "" }, "type": "Frozen goods", "goods": [ { "entity": { "id": "b74d1b1a-905a-42dd-91be-1fe77f443467", "remark": "Be careful not to melt it!", "barCode": "123456789", "quantity": 3, "productType": "Ice cream", "type": "items" }, "associationType": "inline" } ] } ``` ### Move Moves indicate moving from one location to another. In principle they can be implicitely inferred from the stops before and after the move. However stops can also contain route guidance information. Helping drivers take the smartest route from or to certain locations. A route guidance is modelled as an action on the `move` and can appear twice on each move. One going from the source location, and one towards the destination. Moves contain: * A `from` and `to` location. * Optionally actions, containing inner `move` actions. These moves will have a `route` field (unlike the top-level `move`). And a description explaining the type of guidance. * Moves can have an `externalAttribute` `monitoring`, see also `monitoring` on stops. Indicates whether or not this `move` action is actually done, or just there for administrative purposes. ## Full Message Example ```json { "id": "9e376f56-5ecd-733e-83c4-124297f0f398", "name": "Trip 1234", "externalAttributes": { "customer_data_standPlaats": "Hendrik-Ido-Ambacht (Plus)", "tripId": "trip-1234" }, "creationDate": "2022-09-13T09:45:22.019Z", "vehicle": { "entity": { "id": "22f2ddb1-4d51-39ed-91de-89170ede0697", "vehicleType": "truck", "fuel": "EURO_6_DIESEL", "licensePlate": "ZZZ-666" }, "associationType": "inline" }, "actors": [ { "entity": { "id": "04fda035-c5a9-5d98-b2f4-fef915fbfb89", "name": "Carrier", "externalAttributes": { "externalId": "carrier_bv" } }, "roles": [ "carrier" ], "associationType": "inline" }, { "entity": { "id": "9c96409a-03a1-5675-a362-6238bdb7b6f1", "name": "Shipper & Co", "externalAttributes": { "externalId": "shipper_and_co" } }, "roles": [ "shipper" ], "associationType": "inline" }, { "entity": { "id": "85cf6415-29e2-3250-a8c6-888c563e954e", "name": "Elvis Presley" }, "roles": [ "driver" ], "associationType": "inline" } ], "actions": [ { "entity": { "id": "60aee7f6-3f01-588e-9021-baa6c018d92d", "name": "1", "externalAttributes": { "customer_data_mutated": "false", "stopId": "20874316" }, "lifecycle": "planned", "sequenceNr": 1, "location": { "entity": { "id": "b82cfaf7-38b9-d230-9c81-dacd15624a7d", "name": "PLUS Retail West", "externalAttributes": { "locationId": "158775415" }, "geoReference": { "lat": 51.84697, "lon": 4.65331, "type": "latLonPointGeoReference" }, "administrativeReference": { "name": "Location Display name", "street": "street", "postalCode": "1234AB", "city": "Amsterdam", "country": "NL" } }, "associationType": "inline" }, "startTime": "2022-09-13T06:21:00Z", "endTime": "2022-09-13T07:20:00Z", "actions": [ { "entity": { "id": "60025719-7255-3089-8210-0f62a1b3b39a", "lifecycle": "planned", "transportEquipment": { "entity": { "id": "ce636013-32fc-31bb-baa1-66cad70dab4d", "equipmentType": "trailer", "equipmentSubType": "EURO_13_60", "licensePlate": "AA-BB-CC" }, "associationType": "inline" }, "actionType": "attachTransportEquipment" }, "associationType": "inline" }, { "entity": { "id": "623dbba9-6e38-454a-88ac-be04a22c8e25", "lifecycle": "planned", "consignment": { "entity": { "id": "b711847c-96d7-db34-843d-6bbba8af513e", "externalAttributes": { "orderId": "12308478", "orderReference": "DC50032676", "trackTraceCode": "20874316" }, "type": "OVERIG", "goods": [ { "entity": { "id": "7b19aab9-7fba-3149-ac6b-5cadceb8c64a", "description": "EUR", "quantity": 12, "equipmentType": "loadCarrier", "type": "transportEquipment" }, "associationType": "inline" } ], "actors": [ { "entity": { "id": "6cf8cac0-3ce5-35ee-8f46-32a4383b1fab", "name": "Some consignee" }, "roles": [ "consignee" ], "associationType": "inline" }, { "entity": { "id": "6cf8cac0-3ce5-35ee-8f46-32a4383b1fab", "name": "Another Consignor" }, "roles": [ "consignor" ], "associationType": "inline" } ] }, "associationType": "inline" }, "startTime": "2022-09-13T06:21:00Z", "endTime": "2022-09-13T07:20:00Z", "actionType": "load" }, "associationType": "inline" } ], "constraint": { "entity": { "id": "b140e433-6956-30b1-baa0-1bf4632d6267", "value": { "startTime": "2022-09-13T06:21:00Z", "endTime": "2022-09-13T07:20:00Z", "type": "timeWindowConstraint" } }, "associationType": "inline" }, "actionType": "stop" }, "associationType": "inline" }, { "entity": { "id": "c9a5a8cc-196b-30e9-be2b-a710eec82462", "lifecycle": "planned", "from": { "uuid": "b82cfaf7-38b9-d230-9c81-dacd15624a7d", "entityType": "location", "associationType": "reference" }, "to": { "entity": { "id": "434bf7d2-ef0b-bc3d-bf30-eafc41153da9", "name": "Some place", "externalAttributes": { "groupingAddressId": "b82cfaf7-38b9-d230-9c81-dacd15624a7d", "locationId": "1382390970" }, "geoReference": { "lat": 52.12079, "lon": 5.28407, "type": "latLonPointGeoReference" }, "administrativeReference": { "name": "Another location", "street": "Neude", "postalCode": "9999ZZ", "city": "Utrecht", "country": "NL" } }, "associationType": "inline" }, "actionType": "move" }, "associationType": "inline" }, { "entity": { "id": "dfea3ae5-b018-51ff-8001-e5cb241caa65", "name": "2", "externalAttributes": { "stopId": "20874317" }, "lifecycle": "planned", "sequenceNr": 2, "location": { "uuid": "434bf7d2-ef0b-bc3d-bf30-eafc41153da9", "entityType": "location", "associationType": "reference" }, "startTime": "2022-09-13T08:27:03Z", "endTime": "2022-09-13T09:15:03Z", "actions": [ { "entity": { "id": "b5db4f58-b11d-40e4-8b34-93e30120dc57", "lifecycle": "planned", "consignment": { "entity": { "id": "57fd1792-3a4f-cd3e-a846-f855a62265b9", "externalAttributes": { "orderId": "12308478", "shipmentNumber": "1", "orderReference": "DC50032676", "trackTraceCode": "20874317" }, "type": "OVERIG", "goods": [ { "entity": { "id": "8923eee7-d06a-3210-aa1f-f3b9e87dce40", "description": "EUR", "quantity": 4, "equipmentType": "loadCarrier", "type": "transportEquipment" }, "associationType": "inline" } ] }, "associationType": "inline" }, "startTime": "0001-01-01T00:00:00Z", "endTime": "0001-01-01T00:00:00Z", "actionType": "unload" }, "associationType": "inline" } ], "constraint": { "entity": { "id": "649747d0-bda8-357d-96d9-86208ee4a048", "value": { "startTime": "2022-09-13T08:23:00Z", "endTime": "2022-09-13T09:11:00Z", "type": "timeWindowConstraint" } }, "associationType": "inline" }, "actionType": "stop" }, "associationType": "inline" } ] } ``` ## Cancel message: In some cases, as a carrier, it can happen that a previous assigned planning is withdrawn. Depending on the version of your export you will receive one or the other cancel message: ### Profile 1 You can expect the underneath message, which will remove the association between you, the actor, and the trip. All references in such a message will refer to a trip planning previously received via the Planning Push Service. ```json { "id": "cb8eb12b-abcd-4567-a8ab-4c1b134828dc", "eventType": "AssociationRemoved", "entity1": { "entityType":"trip", "associationType": "reference", "uuid": "743ff433-aaxx-4732-86f4-ea84afc25c89" }, "entity2": { "entityType":"actor", "associationType": "reference", "uuid": "c763c64d-3721-1212-a36e-cdae94c1eb19" } } ``` ### Profile 2 You can expect a normal trip message but the field `status` on trip level be filled with the value `"cancelled"`.