---
updatedAt: 2025-09-22T12:39:51.000Z
agentTools:
  projectIndex: https://developer.searoutes.com/llms.txt
---

# 🔄 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

1. Build a payload for your shipment (`orders` + `transportChainElements`)
2. Prepare mode-specific `details` (e.g. `fuelType`, `truckSize`)
3. POST to the `/shipment/v2/report/co2` endpoint
4. Parse the `co2e.total` value from the JSON response
5. Repeat for each mode or transshipment combination

### Prerequisites

* ✅ Valid API key for [Shipment API v2.1](https://developer.searoutes.com/reference/getco2forshipment) (ISO 14083-compliant).
* ⚠️ Note that multi-leg requests return emissions for hubs. Run one request per scenario for easier comparisons.

***

# :technologist:Scenarios

## :one: Modal switch with direct route

***Simulate the CO₂e impact of switching between different modes.***

### ⚙️ Example payload

*Start by defining the order and the basic information of the leg :*

```python Python
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 :*

```python
road_details = { truckSize: 33, fuelType: "DIESEL" };
rail_details = {};
inland_water_details = { vesselType: "CONTAINER_COUPLED" };
```

### ⚙️ Example request

*Then, run the calculation to retrieve the emissions.*

```python
API_KEY = 'your-api-key'
SHIPMENT_API_URL = 'https://api.searoutes.com/shipment/v2/report/co2'

def one_tce_modal_switch(body, modes_and_details):
    results = []
    modal_body = dict(body)
    headers = {'x-api-key': API_KEY, 'Content-Type': 'application/json', 'Accept-Version': '2.1'}
    for mode_detail in modes_and_details:
        # Update the transport chain elements detail for the current mode
        modal_body["transportChainElements"][0]["mode"] = mode_detail[0]
        modal_body["transportChainElements"][0]["details"] = mode_detail[1]
        # Get the response
        response = requests.post(SHIPMENT_API_URL, headers=headers, json=body)
        data = response.json()
        # Save the total CO2
        results.append(data["co2e"]["total"])
    return results

# Define the modes and their details to be tested
modes_to_test = [
    ("road", road_details),
    ("rail", rail_details),
    ("inland_water", inland_water_details)
]
# Run the calculation
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      |

***

## :two: 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

*Start by defining the order and the basic information of the leg :*

```python
order = {"type": "PARCEL", "weight": 1000}
```

### 📝 Mode-specific details

*as well as the combinations of legs you want to compare*:

```python
road_details = { "truckSize": 33, "fuelType": "DIESEL" }
rail_details = {}
air_details = { "aircraft": { "type": "CARGO" } }
sea_details = { "carrier": { "scac": "CMDU" } }

alternative1_legs = [
    { "type": "leg", "from": "ATL", "to": "LHR", "mode": "air", "details": air_details }
]

alternative2_legs = [
    { "type": "leg", "from": "USATL", "to": "USSAV", "mode": "rail", "details": rail_details },
    { "type": "leg", "from": "USSAV", "to": "GBSOU", "mode": "sea", "details": sea_details },
    { "type": "leg", "from": "GBSOU", "to": "GBLHR", "mode": "road", "details": road_details }
]
```

### ⚙️ Example request

*Then, run the calculation to retrieve the emissions.*

```python
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]))
```

### ✅ 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%**.

***

## :three: 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. You will need to use the [closest location](https://developer.searoutes.com/reference/getgeocodingclosest-1) endpoint & the [geocoding/all](https://developer.searoutes.com/reference/getgeocodingall-1) endpoint.

**a. Get airport coordinates**\
Use the [`geocoding/all`](https://developer.searoutes.com/reference/getgeocodingall-1) endpoint to retrieve the coordinates of the origin and destination locations given in *IATA*. Let's write a small function to achieve that :

```python
GEOCODING_ALL_API_URL = "https://api.searoutes.com/geocoding/v2/all"

def get_coordinates_of_iata(iata):
    params = {
        "iataCode": iata,
    }
    headers = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
    response = requests.get(f"{GEOCODING_ALL_API_URL}", headers=headers, params=params)
    data = response.json()
    return data["features"][0]["geometry"]["coordinates"]
```

Note that you could make this function smarter to handler other types of input such that locode or city name, the `geocoding/v2/all` handles them all.

**b. Find nearest ocean ports**

Then, use the  [`geocoding/closest`](https://developer.searoutes.com/reference/getgeocodingclosest-1) endpoint, searching the closest large/medium ports. Let's write a function to search for the closest location to the given coordinates

```python
GEOCODING_CLOSEST_API_URL = "https://api.searoutes.com/geocoding/v2/closest"

def get_coordinates_of_iata(iata):
    params = {
        "iataCode": iata,
    }
    headers = {'x-api-key': API_KEY, 'Content-Type': 'application/json'}
    response = requests.get(f"{GEOCODING_ALL_API_URL}", headers=headers, params=params)
    data = response.json()
    return data["features"][0]["geometry"]["coordinates"]
```

In this example, you get respectively Baltimore (USBAL) and Genoa (ITGOA) ports.

Note that without passing the *large,medium* parameter, the port of Marwood Heights, Illinois would have been retrieved as the closest port to Chicago.

**c. Build the full payload**

Here’s the full python payload after resolving the transshipment points:

```python Python
def modal_switch_from_air_to_sea_and_road(source, destination, order):
    results = []
    # Retrieve the coordinates of source and destination
    source_coordinates = get_coordinates_of_iata(source)
    destination_coordinates = get_coordinates_of_iata(destination)
    # Get the closest ports
    added_ts_port_1 = get_closest(source_coordinates, "port", "large,medium")
    added_ts_port_2 = get_closest(destination_coordinates, "port", "large,medium")
    # Prepare the body for one air leg
    air_body = {
        "orders": [order],
        "transportChainElements": [
            {
                "type": "leg",
                "mode": "air",
                "from": source,
                "to": destination
            }
        ]
    }
    # Prepare the body for the new legs : road to closest port to source + sea + road from closest port to destination
    alternative_body = {
        "orders": [order],
        "transportChainElements": [
            {
                "type": "leg",
                "from": source,
                "to": added_ts_port_1,
                "mode": "road"
            },
            {
                "type": "leg",
                "from": added_ts_port_1,
                "to": added_ts_port_2,
                "mode": "sea"
            },
            {
                "type": "leg",
                "from": added_ts_port_2,
                "to": destination,
                "mode": "road"
            }
        ]
    }

    # Prepare the header of the requests
    headers = {'x-api-key': API_KEY, 'Content-Type': 'application/json', 'Accept-Version': '2.1'}
    # Pass the request for air
    air_response = requests.post(SHIPMENT_API_URL, headers=headers, json=air_body)
    air_data = air_response.json()
    results.append(
        {
            "total": air_data["co2e"]["total"],
            "by_leg": [tce["co2e"]["total"] for tce in air_data["transportChainElements"] if tce["type"] == "leg"]
        }
    )
    # Pass the request for the alternative legs
    alternative_response = requests.post(SHIPMENT_API_URL, headers=headers, json=alternative_body)
    alternative_data = alternative_response.json()
    results.append(
        {
            "total": alternative_data["co2e"]["total"],
            "by_leg": [tce["co2e"]["total"] for tce in alternative_data["transportChainElements"] if tce["type"] == "leg"]
        }
    )

    return results


# Try on our example
print(modal_switch_from_air_to_sea_and_road("ORD", "MXP", order))
```

### ✅ 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%**.

***

## :next\_track\_button: What’s next?

* :handshake: Reach out to our <support@searoutes.com>, 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](https://developer.searoutes.com/reference/getco2forshipment) for all supported params.