🔄 Modal switch
Simulate the impact on CO₂e emissions when switching between different modes of transport for your shipments, and gain insights on lower-emitting modes.
🎯 What this guide is about
This guide shows you:
- How to compare CO₂e emissions across different transport modes for the same route.
- How to handle both simple and more complex modal switches with transshipment points.
- Example payloads and code to help you integrate into your own app or scripts.
🧠 Scenarios covered
In this guide we’ll look at:
- Road vs rail vs barge for a single leg;
- Direct air vs ocean + road + rail with transshipment points;
- Finding the closest port or rail station if none is provided.
🛠 Steps overview and prerequisites
- Build a payload for your shipment (
orders
+transportChainElements
) - Prepare mode-specific
details
(e.g.fuelType
,truckSize
) - POST to the
/shipment/v2/report/co2
endpoint - Parse the
co2e.total
value from the JSON response - Repeat for each mode or transshipment combination
Prerequisites
- ✅ Valid API key for Shipment API v2.1 (ISO 14083-compliant).
- ⚠️ Note that multi-leg requests return emissions for hubs. Run one request per scenario for easier comparisons.
🧑💻Scenarios
1️⃣ Modal switch with direct route
Simulate the CO₂e impact of switching between different modes.
⚙️ Example payload
one_leg_shipment_body = {
"orders": [
{
"type": "fcl",
"nContainers": 1,
"containerSizeTypeCode": "40GP"
}
],
"transportChainElements": [
{
"from": "DEDUI",
"to": "NLRTM",
"type": "leg",
}
]
}
📝 Mode-specific details
Define the details you'd like to apply for each mode. For example :
road_details = { truckSize: 33, fuelType: "DIESEL" };
rail_details = {};
inland_water_details = { vesselType: "CONTAINER_COUPLED" };
⚙️ Example request
modes_to_test = [
("road", road_details),
("rail", rail_details),
("inland_water", inland_water_details)
]
def one_tce_modal_switch(body, modes_and_details):
results = []
for mode, detail in modes_and_details:
body["transportChainElements"][0]["mode"] = mode
body["transportChainElements"][0]["details"] = detail
data = requests.post(SHIPMENT_API_URL, headers=headers, json=body).json()
results.append(data["co2e"]["total"])
return results
print(one_tce_modal_switch(one_leg_shipment_body, modes_to_test))
✅ Example results
Mode | CO₂e WTW (g) |
---|---|
Road | 585 570 |
Rail | 95 076 |
Barge | 115 331 |
2️⃣ Modal switch with known transshipment points
Compare a direct air shipment against a rail-ocean-road alternative.
When changing from one mode to another (for example, air to ocean), you often introduce one or more new transshipment points.
For example, switching from direct air freight to ocean freight usually requires:
- Rail or road to and from an ocean port
- Ocean shipping to a destination port
Here, your payload will list each leg explicitly in the transportChainElements
.
Here’s a payload to compare a direct air shipment (ATL
to LHR
) against a combined rail → sea → road itinerary (ATL
→ USSAV
→ GBSOU
→ GBLHR
):
⚙️ Example payload
# Direct air option
direct_air_payload = {
"orders": [{"type": "PARCEL", "weight": 1000}],
"transportChainElements": [
{ "type": "leg", "from": "ATL", "to": "LHR", "mode": "air",
"details": { "aircraft": { "type": "CARGO" } } }
]
}
# Rail-ocean-road alternative
rail_ocean_road_payload = {
"orders": [{"type": "PARCEL", "weight": 1000}],
"transportChainElements": [
{ "type": "leg", "from": "USATL", "to": "USSAV", "mode": "rail", "details": { ... } },
{ "type": "leg", "from": "USSAV", "to": "GBSOU", "mode": "sea", "details": { "carrier": { "scac": "CMDU" } } },
{ "type": "leg", "from": "GBSOU", "to": "GBLHR", "mode": "road", "details": { "truckSize": 33, "fuelType": "DIESEL" } }
]
}
✅ Example results
Mode | CO₂e WTW (g) | Alternative modes | CO₂e WTW (g) |
---|---|---|---|
TOTAL | 4 165 206 | TOTAL | 70 430 |
Rail USATL>USSAV | 7 299 | ||
Sea USSAV>GBSOU | 40 451 | ||
Road GBSOU>GBLHR | 14 183 | ||
In this example, switching from direct air to ocean-based routing reduces emissions by 98%.
3️⃣ Modal switch with unknown transshipment points
Simulate a switch to ocean/rail without pre-identified transshipment points — letting Searoutes pick the closest ports/stations for you.
When comparing modes like direct air to ocean-based routes, you may not already know the new transshipment points (ports, etc.). Searoutes’ geocoding API helps you discover the closest ones.
⚙️ Example payload
In this example, we’ll switch a direct air shipment from Chicago (ORD
) to Milan (MXP
) into an ocean-based shipment, step by step.
a. Get airport coordinates
Use the geocoding/all
endpoint to retrieve the longitude/latitude of your origin (ORD
) and destination (MXP
).
- Example with
ORD
:GET /geocoding/v2/all?iataCode=ORD
- Response :
"geometry": { "coordinates": [-87.9048, 41.9786] }
b. Find nearest ocean ports
Use the geocoding/closest
endpoint with type=port
and size=large,medium
to get the nearest ocean ports.
- Example:
GET /geocoding/v2/closest?lon=-87.9048&lat=41.9786&type=port&size=large,medium
- Response returns the closest large or medium port :
USBAL
(Baltimore port).
c. Build the ocean payload
With USBAL
as origin port and ITGOA
as destination port, add the ocean leg and the surrounding road legs as shown in the payload above.
Here’s the full python payload after resolving the transshipment points:
unknown_points_payload = {
orders: [{ type: "PARCEL", weight: 1000 }],
transportChainElements: [
{ type: "leg", from: "ORD", to: "USBAL", mode: "road" },
{ type: "leg", from: "USBAL", to: "ITGOA", mode: "sea" },
{ type: "leg", from: "ITGOA", to: "MXP", mode: "road" },
],
};
✅ Example results
Direct air (ATL->LHR) | CO₂e WTW (g) | Alternative modes | CO₂e WTW (g) |
---|---|---|---|
TOTAL | 5 791 055 | TOTAL | 376 292 |
Road USORD>USBAL | 127 911 | ||
Sea USBAL>ITGOA | 74 519 | ||
Road ITGOA>ITMXP | 171 722 |
In this example, switching from direct air to ocean-based routing reduces emissions by 93%.
💡 Optional helper function for batch comparisons
If you’d like to quickly compare multiple routes in one script, you can use a helper like this:
def compare_different_legs(orders, alternative_legs):
results = []
body = {
"orders": orders,
}
headers = {'x-api-key': API_KEY, 'Content-Type': 'application/json', 'Accept-Version': '2.1'}
for alternative in alternative_legs:
# Update the transport chain elements
body["transportChainElements"] = alternative
# Get the response
response = requests.post(SHIPMENT_API_URL, headers=headers, json=body)
data = response.json()
# Save the total CO2 and the CO2 by leg
alternative_result = {
"total": data["co2e"]["total"],
"by_leg": [tce["co2e"]["total"] for tce in data["transportChainElements"] if tce["type"] == "leg"]
}
results.append(alternative_result)
return results
print(compare_different_legs([order], [alternative1_legs, alternative2_legs]))
✅ What’s next?
- 🤝 Reach out to our [email protected], we’d love to hear your feedback on these guides or suggestions for new hands‑on topics!
- 📖 Check the full Shipment API v2.1 docs for all supported params.
Updated 1 day ago