Transportation Plans
The transportation plan API is provided to model the movement of goods across multiple modes of transportation. An example would be a container that is offloaded from a ship and delivered to a facility as a drayage mode, then unpacked and loaded into a dry van as a transload, and finally transported to the end customer as a full truck load. The underlying data model contains the following primary data objects:
- Transportation Plan - the top level object with metadata and is the parent of stages
- Service - defines a service provider like a transload, storage, or terminal
- Shipment - the v2/shipment model
- Stage - container for services and legacy shipments
The advantage of using the transportation plan model is it allows aggregation across all of the stages to do things like calculate the total cost of moving goods across multiple modes and service providers, assign different carriers to different stages of the movement of goods, and allocate different financial accounting to the different stages of the movement.
Creating transportation plans via the UI
Let’s explore how to implement a movement of goods that includes drayage → transload → full truck load to see how the transportation plan API is used to model it. To begin, here is how the UI is used to create a transportation plan, seen on the action panel below.
Next, we want to create a transload stage following the drayage move. Which if performed from the UI would be done by adding a new stage the drayage stage.
A modal is presented when adding a new stage and in our case we want to create a transload stage.
Details are provided for the transload service provider and the stage is created.
Although the UI implies the drayage stage has been created, in actuality it is created just prior to creating the transload stage. First, a multi-stage shipment is created with a drayage stage, and then the transload stage is created. Resulting in both stages being displayed in the action panel UI for the drayage shipment.
Adding an additional full truckload stage is performed the same way as adding a transload stage except FTL is selected in the model instead of Transload.
Using the API to create a multi-stage shipment
To perform the same actions using the API start by creating a drayage mode v2/shipment using the existing APIs to POST a v2/shipment. Documentation can be found here.
Create a Transportation Plan shell
Note!
The current routes will be updated shortly and usage of the current transportation plan routes will be supported going forward. The changes are in naming only, not functionality. The intention is to avoid ambiguity between the current shipment model and the new transportation plan model. The name changes will include the following:
-
All
/shipment
routes will be renamed to/transportation-plan
-
legacy_shipment_id
will be renamedshipment_id
-
legacy_shipment
will be renamedshipment
The examples below use the current naming convention for the routes and response bodies that will be updated in the future.
Create a transportation plan using the POST /shipments
route to act as the container for the stages we will
be creating. There are no required parameters in the request body and in this example none were provided.
The resulting response body contains id
of the newly created transportation plan.
Example request
curl --location --request POST 'https://sandbox-api.shipwell.com/shipments' \
--header 'Authorization: YOUR_AUTHORIZATION_HEADER'
const basePath = "";
const hostPath = "sandbox-api.shipwell.com";
const resp = await fetch(
`https://${hostPath}${basePath}/shipments`,
{
method: "POST",
headers: {
"Authorization": "YOUR_AUTHORIZATION_HEADER"
}
}
);
const data = await resp.json();
console.log(data);
import requests
base_path = ""
host_path = "sandbox-api.shipwell.com"
target_url = (
"https://"
+ host_path
+ base_path
+ "/shipments"
)
headers = {"Authorization": "YOUR_AUTHORIZATION_HEADER"}
response = requests.post(target_url, headers=headers)
data = response.json()
print(data)
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
OkHttpClient client = new OkHttpClient();
String basePath = "";
String hostPath = "sandbox-api.shipwell.com";
String targetUrl = "https://" +
host_path +
base_path +
"/shipments";
Request request = new Request.Builder()
.url(targetUrl)
.header("Authorization", "YOUR_AUTHORIZATION_HEADER")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
response.body().string();
}
Example response
{
"created_at": "2022-12-02T18:39:07.256021+00:00",
"updated_at": "2022-12-02T18:39:07.256021+00:00",
"name": null,
"archived": false,
"instructions": null,
"references": [],
"mode_specific_data": [],
"id": "01GKA255FRSJ7Y1251HE5Q78DR",
"reference_id": "QQBRR0",
"created_by": {
"tenant_id": "a54ef012-77d4-44a0-8ba5-115b09b655be",
"user_id": "f0b979c9-28e2-41d6-883e-cb1f5c320bb4"
},
"overall_status": "DRAFT",
"stages": [],
"contacts": [],
"items": [],
"stops": [],
"customer": null
}
Add the drayage shipment as the first stage
Add the drayage shipment created previously as the first stage of the transportation plan by using the
POST /shipments/{shipment_id}/legacy-shipment-stages
route providing the newly created transportation plan id
as the path parameter and the drayage shipment id in the body of the request as the legacy_shipment_id
. The
response body contains details of the newly created stage.
Example request
curl --location --request POST 'https://sandbox-api.shipwell.com/shipments/{shipment_id}/legacy-shipment-stages' \
--header 'Authorization: YOUR_AUTHORIZATION_HEADER'
const shipmentId = "YOUR_shipmentId_PARAMETER"
const basePath = "";
const hostPath = "sandbox-api.shipwell.com";
const resp = await fetch(
`https://${hostPath}${basePath}/shipments/${shipmentId}/legacy-shipment-stages`,
{
method: "POST",
headers: {
"Authorization": "YOUR_AUTHORIZATION_HEADER"
}
}
);
const data = await resp.json();
console.log(data);
import requests
shipment_id = "YOUR_shipmentId_PARAMETER"
base_path = ""
host_path = "sandbox-api.shipwell.com"
target_url = (
"https://"
+ host_path
+ base_path
+ "/shipments/"
+ shipment_id
+ "/legacy-shipment-stages"
)
headers = {"Authorization": "YOUR_AUTHORIZATION_HEADER"}
response = requests.post(target_url, headers=headers)
data = response.json()
print(data)
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
OkHttpClient client = new OkHttpClient();
String shipmentId = "YOUR_shipmentId_PARAMETER";
String basePath = "";
String hostPath = "sandbox-api.shipwell.com";
String targetUrl = "https://" +
host_path +
base_path +
"/shipments/" +
shipmentId +
"/legacy-shipment-stages";
Request request = new Request.Builder()
.url(targetUrl)
.header("Authorization", "YOUR_AUTHORIZATION_HEADER")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
response.body().string();
}
Example response
{
"id": "01GKA2E6TFS7KPYJZPK6T4B5GY",
"shipment_id": "01GKA255FRSJ7Y1251HE5Q78DR",
"stage_type": "LEGACY_SHIPMENT",
"directly_dependent_stages": [],
"directly_depends_on_stages": [],
"legacy_shipment_id": "b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e",
"legacy_shipment": {
"id": "b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e",
"resource_type": "shipment",
"self_link": "https://sandbox-api.shipwell.com/v2/shipments/b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e/"
}
}
Use the GET /shipments/{shipment_id)/stages
route with the transportation plan id
as the path parameter to review
the stages of the transportation plan and note that the response contains the drayage legacy shipment added.
Example request
curl --location --request GET 'https://sandbox-api.shipwell.com/shipments/{shipment_id}/stages' \
--header 'Authorization: YOUR_AUTHORIZATION_HEADER'
const shipmentId = "YOUR_shipmentId_PARAMETER"
const basePath = "";
const hostPath = "sandbox-api.shipwell.com";
const resp = await fetch(
`https://${hostPath}${basePath}/shipments/${shipmentId}/stages`,
{
method: "GET",
headers: {
"Authorization": "YOUR_AUTHORIZATION_HEADER"
}
}
);
const data = await resp.json();
console.log(data);
import requests
shipment_id = "YOUR_shipmentId_PARAMETER"
base_path = ""
host_path = "sandbox-api.shipwell.com"
target_url = (
"https://"
+ host_path
+ base_path
+ "/shipments/"
+ shipment_id
+ "/stages"
)
headers = {"Authorization": "YOUR_AUTHORIZATION_HEADER"}
response = requests.get(target_url, headers=headers)
data = response.json()
print(data)
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
OkHttpClient client = new OkHttpClient();
String shipmentId = "YOUR_shipmentId_PARAMETER";
String basePath = "";
String hostPath = "sandbox-api.shipwell.com";
String targetUrl = "https://" +
host_path +
base_path +
"/shipments/" +
shipmentId +
"/stages";
Request request = new Request.Builder()
.url(targetUrl)
.header("Authorization", "YOUR_AUTHORIZATION_HEADER")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
response.body().string();
}
Example response
{
"data": [
{
"id": "01GKA2E6TFS7KPYJZPK6T4B5GY",
"shipment_id": "01GKA255FRSJ7Y1251HE5Q78DR",
"stage_type": "LEGACY_SHIPMENT",
"directly_dependent_stages": [],
"directly_depends_on_stages": [],
"legacy_shipment_id": "b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e",
"legacy_shipment": {
"id": "b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e",
"resource_type": "shipment",
"self_link": "https://sandbox-api.shipwell.com/v2/shipments/b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e/"
}
}
]
}
Add a transload stage
Adding a transload stage is a multi-step process. First getting a list of service providers, then create a transload service, and finally assign the created transload service to a multi-stage shipment stage while defining the stage’s dependency.
Get a list of service providers
To get a list of potential service providers use the GET /v2/service-providers
route to identify the id
of the
desired service provider with capabilities: ["TRANSLOAD"]
. Here is an abbreviated example of the response for a
service provider:
Example request
curl --location --request GET 'https://sandbox-api.shipwell.com/v2/service-providers' \
--header 'Authorization: YOUR_AUTHORIZATION_HEADER'
const basePath = "/v2";
const hostPath = "sandbox-api.shipwell.com";
const resp = await fetch(
`https://${hostPath}${basePath}/shipments/service-providers`,
{
method: "GET",
headers: {
"Authorization": "YOUR_AUTHORIZATION_HEADER"
}
}
);
const data = await resp.json();
console.log(data);
import requests
base_path = "/v2"
host_path = "sandbox-api.shipwell.com"
target_url = (
"https://"
+ host_path
+ base_path
+ "/service-providers"
)
headers = {"Authorization": "YOUR_AUTHORIZATION_HEADER"}
response = requests.get(target_url, headers=headers)
data = response.json()
print(data)
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
OkHttpClient client = new OkHttpClient();
String basePath = "/v2";
String hostPath = "sandbox-api.shipwell.com";
String targetUrl = "https://" +
host_path +
base_path +
"/service-providers";
Request request = new Request.Builder()
.url(targetUrl)
.header("Authorization", "YOUR_AUTHORIZATION_HEADER")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
response.body().string();
}
Example response
{
"id":"01GCFAZ41VG6DC08F6CZEN4P5P",
"created_at":"2022-09-08T19:59:25.755080Z",
"updated_at":"2022-09-08T19:59:25.756034Z",
"name":"Brent Testing",
"mailing_address":{
"id":"4fcdb651-f0d9-4111-a333-8b980e463187",
"address_1":"8901 Brook Rd",
"address_2":null,
"city":"Glen Allen",
"state_province":"VA",
"postal_code":"23060",
"country":"US",
"phone_number":null,
"formatted_address":"8901 Brook Rd, Glen Allen, VA 23060, US",
"created_at":"2022-09-08T19:59:25.461200Z",
"updated_at":"2022-09-08T19:59:25.602573Z"
},
"tags":[
],
"capabilities":[
"TRANSLOAD"
],
"notes":null,
"billing_email":null,
"status":"ACTIVE",
"resource_type":"service-provider",
"self_link":"http://sandbox-api.shipwell.com/v2/service-providers/01GCFAZ41VG6DC08F6CZEN4P5P"
}
Create a transload service
Use the id
in the response body from the POST /shipments
route we started with as the shipment_id
and use the id
from
the POST /services/transload
above as the service_id
for the POST /shipments/{shipment_id}/services/{service_id}
route to associate the service with the multi-stage shipment. In the request body below the dependency that will be associated is defined. We'll
make this transload service dependent on the legacy shipment stage created earlier. Note the directly_depends_on_stages
below references the id
from the legacy shipment stage.
Example request
curl --location --request POST 'https://sandbox-api.shipwell.com/shipments/{shipment_id}/services/{service_id}' \
--header 'Authorization: YOUR_AUTHORIZATION_HEADER' \
--form 'data="{
\"directly_depends_on_stages\": [\"01GKA2E6TFS7KPYJZPK6T4B5GY\"]
}"'
const payload = {
"directly_depends_on_stages": ["01GKA2E6TFS7KPYJZPK6T4B5GY"]
};
const shipmentId = "YOUR_shipmentId_PARAMETER";
const serviceId = "YOUR_serviceId_PARAMETER";
const basePath = "";
const hostPath = "sandbox-api.shipwell.com";
const resp = await fetch(
`https://${hostPath}${basePath}/shipments/${shipmentId}/services/${serviceId}`,
{
method: "POST",
headers: {
"Authorization": "YOUR_AUTHORIZATION_HEADER"
},
body: JSON.stringify(payload)
}
);
const data = await resp.json();
console.log(data);
import requests
shipment_id = "YOUR_shipmentId_PARAMETER"
service_id = "YOUR_serviceId_PARAMETER"
base_path = ""
host_path = "sandbox-api.shipwell.com"
target_url = (
"https://"
+ host_path
+ base_path
+ "/shipments/"
+ shipment_id
+ "/services/"
+ service_id
)
headers = {
"Authorization": "YOUR_AUTHORIZATION_HEADER",
"Content-Type": "application/json",
}
payload = {
"directly_depends_on_stages": ["01GKA2E6TFS7KPYJZPK6T4B5GY"]
}
response = requests.post(target_url, headers=headers, json=payload)
data = response.json()
print(data)
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
OkHttpClient client = new OkHttpClient();
String shipmentId = "YOUR_shipmentId_PARAMETER";
String serviceId = "YOUR_serviceId_PARAMETER";
String basePath = "";
String hostPath = "sandbox-api.shipwell.com";
String targetUrl = "https://" +
host_path +
base_path +
"/shipments/" +
shipmentId +
"/services/" +
serviceId;
String requestBody = "{\"directly_depends_on_stages\": [\"01GKA2E6TFS7KPYJZPK6T4B5GY\"]}";
Request request = new Request.Builder()
.url(targetUrl)
.put(requestBody)
.header("Authorization", "YOUR_AUTHORIZATION_HEADER")
.header("Content-Type", "application/json")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
response.body().string();
}
Example response
Returns an empty response with a HTTP 204 (No Content) status code on success
Make another call to the GET /shipments/{shipment_id)/stages
to confirm the new transload stage is listed.
Example request
curl --location --request GET 'https://sandbox-api.shipwell.com/shipments/{shipment_id}/stages' \
--header 'Authorization: YOUR_AUTHORIZATION_HEADER'
const shipmentId = "YOUR_shipmentId_PARAMETER"
const basePath = "";
const hostPath = "sandbox-api.shipwell.com";
const resp = await fetch(
`https://${hostPath}${basePath}/shipments/${shipmentId}/stages`,
{
method: "GET",
headers: {
"Authorization": "YOUR_AUTHORIZATION_HEADER"
}
}
);
const data = await resp.json();
console.log(data);
import requests
shipment_id = "YOUR_shipmentId_PARAMETER"
base_path = ""
host_path = "sandbox-api.shipwell.com"
target_url = (
"https://"
+ host_path
+ base_path
+ "/shipments/"
+ shipment_id
+ "/stages"
)
headers = {"Authorization": "YOUR_AUTHORIZATION_HEADER"}
response = requests.get(target_url, headers=headers)
data = response.json()
print(data)
import java.io.IOException;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
OkHttpClient client = new OkHttpClient();
String shipmentId = "YOUR_shipmentId_PARAMETER";
String basePath = "";
String hostPath = "sandbox-api.shipwell.com";
String targetUrl = "https://" +
host_path +
base_path +
"/shipments/" +
shipmentId +
"/stages";
Request request = new Request.Builder()
.url(targetUrl)
.header("Authorization", "YOUR_AUTHORIZATION_HEADER")
.build();
try (Response response = client.newCall(request).execute()) {
if (!response.isSuccessful()) throw new IOException("Unexpected code " + response);
response.body().string();
}
Example response
[
{
"id":"01GKA2E6TFS7KPYJZPK6T4B5GY",
"shipment_id":"01GKA255FRSJ7Y1251HE5Q78DR",
"stage_type":"LEGACY_SHIPMENT",
"directly_dependent_stages":[
"01GKAATMFA9A2XHW8CE334CPE0"
],
"directly_depends_on_stages":[
],
"legacy_shipment_id":"b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e",
"legacy_shipment":{
"id":"b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e",
"resource_type":"shipment",
"self_link":"https://sandbox-api.shipwell.com/v2/shipments/b901aaa2-e9e9-4621-8de8-89f8e5ceaa2e/"
}
},
{
"id":"01GKAATMFA9A2XHW8CE334CPE0",
"shipment_id":"01GKA255FRSJ7Y1251HE5Q78DR",
"stage_type":"SERVICE",
"directly_dependent_stages":[
],
"directly_depends_on_stages":[
"01GKA2E6TFS7KPYJZPK6T4B5GY"
],
"service":{
"service_type":"TRANSLOAD",
"reference_id":"JENHSG",
"custom_data":null,
"location":{
"address":{
"country":"US",
"line_1":"8901 Three Chopt Rd",
"line_2":null,
"line_3":null,
"locality":"Richmond",
"postal_code":"23229",
"region":"VA",
"urbanization":null,
"residential":false,
"geolocation":null
},
"location_name":"Brent Testing",
"location_number":"PA-1",
"system_id":"Brent Testing, PA-1",
"company_name":"Brent Testing",
"location_type":"OTHER",
"timezone":"America/Chicago"
},
"service_provider":{
"provider_id":"01GESC9P9J5V0YW33JW7647Z6N",
"identification_codes":[
],
"name":"Brent Testing"
},
"actual_datetimes":null,
"provider_rate":null,
"customer_rate":null,
"references":[
],
"id":"01GKAASHXVS1ZKVR90RH7BAFJY"
}
}
]
Adding the full truck load stage
The final full truckload stage is added the same way the drayage stage was added to the transportation plan in the fist step of this developer guide and is left as an exercise for the developer to complete this example.