> ## Documentation Index
> Fetch the complete documentation index at: https://code.dcycle.io/llms.txt
> Use this file to discover all available pages before exploring further.

# Step 1: Track Transport Operations

> Create transport legs, select TOCs, handle multi-modal shipments, and upload bulk data following GLEC v3.0

## Understanding Transport Operations in GLEC

In the GLEC Framework, every shipment is broken down into **transport legs** — individual segments where goods move from one point to another using a specific vehicle type. Each leg is classified by its **TOC (Transport Operation Category)**, which determines the emission factor applied.

```
┌──────────────────────────────────────────────────────────────────────────────┐
│                        TRANSPORT OPERATION FLOW                              │
├──────────────────────────────────────────────────────────────────────────────┤
│                                                                              │
│  Shipment: Madrid → Hamburg (multi-modal)                                   │
│                                                                              │
│  Leg 1 (Road)           Leg 2 (Maritime)         Leg 3 (Road)              │
│  ─────────────          ────────────────         ─────────────              │
│  Madrid → Barcelona     Barcelona → Hamburg      Hamburg → Warehouse        │
│  TOC: artic_truck       TOC: general_cargo       TOC: van_diesel           │
│  500 km · 12t           1800 km · 12t            30 km · 12t               │
│                                                                              │
│  CO2e = tkm × WTW      CO2e = tkm × WTW         CO2e = tkm × WTW         │
│                                                                              │
│  Total shipment CO2e = Leg 1 + Leg 2 + Leg 3                               │
│                                                                              │
└──────────────────────────────────────────────────────────────────────────────┘
```

<Note>
  **GLEC Calculation Formula**

  For each transport leg:

  **CO2e (kg) = tkm x WTW emission factor (kgCO2e/tkm)**

  Where:

  * **tkm** = load (tonnes) x distance (km)
  * **WTW** = Well-to-Wheel factor from the TOC (includes fuel production + combustion)
  * For **electric vehicles**: CO2e = tkm x grid emission factor x energy efficiency factor
</Note>

## Prerequisites

Before starting, ensure you have:

* Dcycle API credentials ([get them here](/docs/quickstart#step-1-get-your-api-key))
* An organization configured in Dcycle
* Shipment data: origins, destinations, weights, and vehicle types (or at least transport category)

## Step 1.1: Explore Available TOCs

Before creating transport legs, list the available vehicle types and their emission factors:

<Accordion title="📋 Data Map: List TOCs">
  No input data required. Returns all available TOCs with their WTW factors and default loads.

  **Response fields:**

  | Field          | Description                        | Example        |
  | -------------- | ---------------------------------- | -------------- |
  | `toc`          | Vehicle identifier (vehicle\_type) | `"van_diesel"` |
  | `category`     | Transport mode                     | `"road"`       |
  | `vehicle`      | Vehicle type                       | `"van"`        |
  | `type`         | Fuel/specification                 | `"diesel"`     |
  | `wtw`          | WTW factor (kgCO2e/tkm)            | `0.196`        |
  | `default_load` | Default capacity (kg)              | `3500.0`       |
  | `location`     | Region                             | `"EU"`         |
</Accordion>

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  import requests
  import os

  headers = {
      "Authorization": f"Bearer {os.getenv('DCYCLE_API_KEY')}",
      "Content-Type": "application/json",
      "x-organization-id": os.getenv("DCYCLE_ORG_ID"),
      "x-user-id": os.getenv("DCYCLE_USER_ID"),
  }

  # List all available TOCs
  tocs = requests.get(
      "https://api.dcycle.io/v1/logistics/tocs",
      headers=headers,
  ).json()

  print("Available Transport Operation Categories:")
  for toc in tocs:
      print(f"  {toc['toc']:30s} | {toc['category']:10s} | WTW: {toc['wtw']:.4f} kgCO2e/tkm | Region: {toc['location']}")
  ```

  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  const axios = require('axios');

  const headers = {
    Authorization: `Bearer ${process.env.DCYCLE_API_KEY}`,
    'Content-Type': 'application/json',
    'x-organization-id': process.env.DCYCLE_ORG_ID,
    'x-user-id': process.env.DCYCLE_USER_ID,
  };

  // List all available TOCs
  const { data: tocs } = await axios.get(
    'https://api.dcycle.io/v1/logistics/tocs',
    { headers }
  );

  console.log('Available Transport Operation Categories:');
  tocs.forEach(toc => {
    console.log(`  ${toc.toc.padEnd(30)} | ${toc.category.padEnd(10)} | WTW: ${toc.wtw.toFixed(4)} kgCO2e/tkm | Region: ${toc.location}`);
  });
  ```
</CodeGroup>

### Common TOCs by Transport Mode

<Tabs>
  <Tab title="Road">
    | TOC                    | Vehicle           | Fuel     | Typical Use                    |
    | ---------------------- | ----------------- | -------- | ------------------------------ |
    | `van_diesel`           | Van               | Diesel   | Urban/last-mile deliveries     |
    | `van_electric`         | Van               | Electric | Zero-emission urban deliveries |
    | `rigid_truck_diesel`   | Rigid truck       | Diesel   | Regional freight               |
    | `artic_truck_diesel`   | Articulated truck | Diesel   | Long-haul freight              |
    | `artic_truck_electric` | Articulated truck | Electric | Electric long-haul             |
    | `tank_truck_diesel`    | Tank truck        | Diesel   | Liquid bulk transport          |
    | `generic_average_road` | Generic           | Average  | When vehicle type is unknown   |

    **Road fuels supported**: diesel, electric, CNG, LNG, HVO, biodiesel blends, LPG.
  </Tab>

  <Tab title="Rail">
    | TOC                    | Vehicle               | Typical Use                       |
    | ---------------------- | --------------------- | --------------------------------- |
    | `generic_average_rail` | Generic freight train | Bulk goods, intermodal containers |

    Rail has the lowest emission intensity of land transport modes.
  </Tab>

  <Tab title="Maritime">
    | TOC                              | Vehicle       | Typical Use                   |
    | -------------------------------- | ------------- | ----------------------------- |
    | `oil_tanker_average_maritime`    | Oil tanker    | Crude oil, petroleum products |
    | `general_cargo_average_maritime` | General cargo | Break-bulk goods              |
    | `bulk_carrier_average_maritime`  | Bulk carrier  | Grain, coal, ore              |
    | `ro_ro_average_maritime`         | Ro-Ro         | Vehicles, wheeled cargo       |
    | `generic_average_maritime`       | Generic       | When vessel type is unknown   |
  </Tab>

  <Tab title="Air">
    | TOC                         | Vehicle         | Typical Use                      |
    | --------------------------- | --------------- | -------------------------------- |
    | `freighter_average_air`     | Cargo freighter | Dedicated cargo aircraft         |
    | `belly_freight_average_air` | Belly freight   | Cargo in passenger aircraft hold |
    | `generic_average_air`       | Generic         | When aircraft type is unknown    |

    <Warning>
      Air freight has the highest emission intensity — typically 20-50x higher than maritime and 5-10x higher than road per tkm.
    </Warning>
  </Tab>
</Tabs>

<Tip>
  **Don't know the exact vehicle type?** Provide only `category` (e.g., `"road"`, `"maritime"`) instead of `toc`, and Dcycle will use the generic average TOC for that mode and region.
</Tip>

## Step 1.2: Create a Single Transport Leg

<Accordion title="📋 Data Map: Create Transport Leg">
  | Field            | Type    | Required    | Description                                           | Example                |
  | ---------------- | ------- | ----------- | ----------------------------------------------------- | ---------------------- |
  | `origin`         | string  | Conditional | Origin address (required if no `distance_km`)         | `"Madrid, Spain"`      |
  | `destination`    | string  | Conditional | Destination address (required if no `distance_km`)    | `"Barcelona, Spain"`   |
  | `distance_km`    | number  | Conditional | Distance in km (used as-is, overrides geocoding)      | `620`                  |
  | `toc`            | string  | Conditional | TOC identifier (if omitted, provide `category`)       | `"rigid_truck_diesel"` |
  | `category`       | string  | Conditional | Transport mode (if `toc` is omitted)                  | `"road"`               |
  | `origin_country` | string  | No          | ISO 3166-2 code for region-specific factors           | `"ES"`                 |
  | `load`           | number  | No          | Cargo weight (defaults to TOC's `default_load`)       | `5000`                 |
  | `load_unit`      | string  | No          | Unit: `kg`, `ton`, `pallets`, `teu`, `feu`            | `"kg"`                 |
  | `load_factor`    | number  | No          | Allocation factor 0-1 (e.g., 0.5 = half truck)        | `0.5`                  |
  | `year`           | number  | No          | Emission factor year (defaults to current)            | `2025`                 |
  | `cleaning`       | boolean | No          | Vehicle cleaning done (adds cleaning emissions)       | `false`                |
  | `subcontractor`  | boolean | No          | Handled by a subcontractor (affects scope allocation) | `false`                |
  | `client`         | string  | No          | Client identifier for reporting                       | `"AMAZON"`             |
  | `movement_id`    | string  | No          | Groups multiple legs of the same shipment             | `"MOV-2025-001"`       |
  | `shipment_date`  | date    | No          | Date of shipment (YYYY-MM-DD)                         | `"2025-03-15"`         |
  | `hub_id`         | string  | No          | Hub associated with this leg                          | `"HUB-MAD-001"`        |
  | `package_key`    | string  | No          | Package identifier (requires `movement_id`)           | `"PKG-12345"`          |

  **Where to get this data:**

  * **toc**: Use `GET /v1/logistics/tocs` to list available vehicle types
  * **origin/destination**: Physical addresses or city names (geocoded automatically)
  * **load**: From your shipping manifest, bill of lading, or TMS
  * **client**: From your customer management system
</Accordion>

### Basic shipment (addresses + TOC)

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  # Calculate a single road shipment
  shipment = {
      "origin": "Calle Gran Via 1, Madrid, Spain",
      "destination": "Passeig de Gracia 50, Barcelona, Spain",
      "origin_country": "ES",
      "toc": "rigid_truck_diesel",
      "load": 8000,
      "load_unit": "kg",
      "year": 2025,
      "client": "RETAILCO",
      "shipment_date": "2025-03-15",
  }

  response = requests.post(
      "https://api.dcycle.io/v1/logistics/requests",
      headers=headers,
      json=shipment,
  ).json()

  print(f"Request ID: {response['id']}")
  print(f"Distance: {response['distance_km']:.1f} km (with DAF applied)")
  print(f"CO2e: {response['co2e']:.2f} kg")
  print(f"TOC: {response['toc']}")
  ```

  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  // Calculate a single road shipment
  const shipment = {
    origin: 'Calle Gran Via 1, Madrid, Spain',
    destination: 'Passeig de Gracia 50, Barcelona, Spain',
    origin_country: 'ES',
    toc: 'rigid_truck_diesel',
    load: 8000,
    load_unit: 'kg',
    year: 2025,
    client: 'RETAILCO',
    shipment_date: '2025-03-15',
  };

  const { data: result } = await axios.post(
    'https://api.dcycle.io/v1/logistics/requests',
    shipment,
    { headers }
  );

  console.log(`Request ID: ${result.id}`);
  console.log(`Distance: ${result.distance_km.toFixed(1)} km (with DAF applied)`);
  console.log(`CO2e: ${result.co2e.toFixed(2)} kg`);
  console.log(`TOC: ${result.toc}`);
  ```
</CodeGroup>

### Using known distance (skip geocoding)

When you already have the distance, provide `distance_km` directly:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Known distance — geocoding is skipped
shipment = {
    "distance_km": 620,
    "origin_country": "ES",
    "toc": "artic_truck_diesel",
    "load": 15,
    "load_unit": "ton",
    "year": 2025,
}

response = requests.post(
    "https://api.dcycle.io/v1/logistics/requests",
    headers=headers,
    json=shipment,
).json()

print(f"CO2e: {response['co2e']:.2f} kg")
```

### Using tkm directly

If you already know the tonne-kilometers, provide `tkm`:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Known tkm — skip distance and load calculation
shipment = {
    "tkm": 9300,  # 15 tonnes x 620 km
    "origin_country": "ES",
    "toc": "artic_truck_diesel",
    "year": 2025,
}

response = requests.post(
    "https://api.dcycle.io/v1/logistics/requests",
    headers=headers,
    json=shipment,
).json()
```

### Using category instead of TOC

When you don't know the exact vehicle type:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Only know it's road transport
shipment = {
    "origin": "Madrid, Spain",
    "destination": "Sevilla, Spain",
    "category": "road",  # Will use generic_average_road for the region
    "load": 3000,
    "load_unit": "kg",
}

response = requests.post(
    "https://api.dcycle.io/v1/logistics/requests",
    headers=headers,
    json=shipment,
).json()

print(f"TOC selected: {response['toc']}")
print(f"CO2e: {response['co2e']:.2f} kg")
```

## Step 1.3: Multi-Modal and Multi-Leg Shipments

Use `movement_id` to group multiple legs into a single shipment, and `package_key` to track individual packages across legs:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
movement_id = "MOV-2025-MAD-HAM-001"

# Leg 1: Road (first mile)
leg1 = {
    "origin": "Madrid, Spain",
    "destination": "Barcelona Port, Spain",
    "origin_country": "ES",
    "toc": "artic_truck_diesel",
    "load": 12000,
    "load_unit": "kg",
    "movement_id": movement_id,
    "movement_stretch": "first_mile",
    "package_key": "PKG-26830007899",
    "client": "IMPORT-CO",
}

# Leg 2: Maritime (main haul)
leg2 = {
    "origin": "Barcelona, Spain",
    "destination": "Hamburg, Germany",
    "origin_country": "ES",
    "toc": "general_cargo_average_maritime",
    "load": 12000,
    "load_unit": "kg",
    "movement_id": movement_id,
    "movement_stretch": "main_haul",
    "package_key": "PKG-26830007899",
    "client": "IMPORT-CO",
}

# Leg 3: Road (last mile)
leg3 = {
    "origin": "Hamburg Port, Germany",
    "destination": "Hamburg Warehouse, Germany",
    "origin_country": "DE",
    "toc": "van_diesel",
    "load": 12000,
    "load_unit": "kg",
    "movement_id": movement_id,
    "movement_stretch": "last_mile",
    "package_key": "PKG-26830007899",
    "client": "IMPORT-CO",
}

total_co2e = 0
for i, leg in enumerate([leg1, leg2, leg3], 1):
    result = requests.post(
        "https://api.dcycle.io/v1/logistics/requests",
        headers=headers,
        json=leg,
    ).json()
    total_co2e += result["co2e"]
    print(f"Leg {i} ({leg['movement_stretch']}): {result['co2e']:.2f} kg CO2e | {result['distance_km']:.0f} km")

print(f"\nTotal shipment CO2e: {total_co2e:.2f} kg")
```

<Tip>
  **Package tracking**: When `package_key` is provided, Dcycle creates or updates a `LogisticPackage` that aggregates `total_distance_km` and `total_co2e` across all legs. Retrieve package details with `GET /v1/logistics/packages/{package_id}`.
</Tip>

### Subcontracted Transport

Mark legs handled by a subcontractor. These emissions are classified as **Scope 3** in the GLEC company report (instead of Scope 1 for own fleet):

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
subcontracted_leg = {
    "origin": "Madrid, Spain",
    "destination": "Lisbon, Portugal",
    "origin_country": "ES",
    "toc": "artic_truck_diesel",
    "load": 20,
    "load_unit": "ton",
    "subcontractor": True,  # Scope 3 in GLEC report
    "client": "CLIENTCO",
}

response = requests.post(
    "https://api.dcycle.io/v1/logistics/requests",
    headers=headers,
    json=subcontracted_leg,
).json()
```

<Note>
  **Own fleet vs Subcontracted — Scope allocation**

  |                    | Own Fleet         | Subcontracted |
  | ------------------ | ----------------- | ------------- |
  | **TTW (direct)**   | Scope 1           | Scope 3       |
  | **WTT (upstream)** | Scope 3           | Scope 3       |
  | **Total WTW**      | Split Scope 1 + 3 | Scope 3       |

  Set `subcontractor: true` for any leg not operated by your own fleet.
</Note>

## Step 1.4: Load Units and Allocation

GLEC supports multiple load units. Dcycle converts them to kg internally:

| Unit      | Conversion          | Typical Use               |
| --------- | ------------------- | ------------------------- |
| `kg`      | 1 kg                | Default, most common      |
| `ton`     | 1 ton = 1,000 kg    | Heavy freight             |
| `pallets` | 1 pallet = 1,500 kg | Palletized goods          |
| `teu`     | 1 TEU = 20,000 kg   | Container shipping (20ft) |
| `feu`     | 1 FEU = 40,000 kg   | Container shipping (40ft) |

### Load Factor (Allocation)

Use `load_factor` to account for partial loads or shared capacity:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Half-truck load
shipment = {
    "origin": "Madrid, Spain",
    "destination": "Valencia, Spain",
    "toc": "artic_truck_diesel",
    "load": 100,
    "load_unit": "pallets",
    "load_factor": 0.5,  # Only using 50% of capacity → 50 pallets
}
```

## Step 1.5: Bulk Upload (Up to 5,000 Records)

For high-volume operations, use the bulk endpoint to process up to 5,000 transport legs in a single request:

<Accordion title="📋 Data Map: Bulk Upload">
  | Field                       | Type    | Required | Description                                                    |
  | --------------------------- | ------- | -------- | -------------------------------------------------------------- |
  | `records`                   | array   | Yes      | Array of transport leg objects (same schema as single request) |
  | `options.continue_on_error` | boolean | No       | Continue processing if some records fail (default: `true`)     |

  Each record in the `records` array uses the same fields as the single request in Step 1.2.
</Accordion>

<CodeGroup>
  ```python Python theme={"theme":{"light":"github-light","dark":"github-dark"}}
  # Bulk upload multiple transport legs
  bulk_payload = {
      "records": [
          {
              "origin": "Madrid, Spain",
              "destination": "Barcelona, Spain",
              "toc": "rigid_truck_diesel",
              "load": 5000,
              "load_unit": "kg",
              "client": "CLIENT-A",
              "shipment_date": "2025-03-01",
          },
          {
              "origin": "Barcelona, Spain",
              "destination": "Valencia, Spain",
              "toc": "van_diesel",
              "load": 1200,
              "load_unit": "kg",
              "client": "CLIENT-A",
              "shipment_date": "2025-03-01",
          },
          {
              "origin": "Madrid, Spain",
              "destination": "Sevilla, Spain",
              "toc": "artic_truck_diesel",
              "load": 18,
              "load_unit": "ton",
              "client": "CLIENT-B",
              "shipment_date": "2025-03-02",
          },
      ],
      "options": {
          "continue_on_error": True,
      },
  }

  response = requests.post(
      "https://api.dcycle.io/v1/logistics/requests/bulk",
      headers=headers,
      json=bulk_payload,
  ).json()

  print(f"Total received: {response['total_received']}")
  print(f"Success: {response['success']}")
  print(f"Failed: {response['failed']}")

  # Check individual results
  for result in response["results"]:
      print(f"  Record {result['index']}: {result['co2e']:.2f} kg CO2e (ID: {result['id']})")

  # Check errors
  for error in response["errors"]:
      print(f"  Error at record {error['index']}: {error['error']}")
  ```

  ```javascript JavaScript theme={"theme":{"light":"github-light","dark":"github-dark"}}
  // Bulk upload multiple transport legs
  const bulkPayload = {
    records: [
      {
        origin: 'Madrid, Spain',
        destination: 'Barcelona, Spain',
        toc: 'rigid_truck_diesel',
        load: 5000,
        load_unit: 'kg',
        client: 'CLIENT-A',
        shipment_date: '2025-03-01',
      },
      {
        origin: 'Barcelona, Spain',
        destination: 'Valencia, Spain',
        toc: 'van_diesel',
        load: 1200,
        load_unit: 'kg',
        client: 'CLIENT-A',
        shipment_date: '2025-03-01',
      },
      {
        origin: 'Madrid, Spain',
        destination: 'Sevilla, Spain',
        toc: 'artic_truck_diesel',
        load: 18,
        load_unit: 'ton',
        client: 'CLIENT-B',
        shipment_date: '2025-03-02',
      },
    ],
    options: {
      continue_on_error: true,
    },
  };

  const { data: result } = await axios.post(
    'https://api.dcycle.io/v1/logistics/requests/bulk',
    bulkPayload,
    { headers }
  );

  console.log(`Total received: ${result.total_received}`);
  console.log(`Success: ${result.success}`);
  console.log(`Failed: ${result.failed}`);
  ```
</CodeGroup>

<Warning>
  **Bulk limits**: Maximum 5,000 records per request. For larger datasets, split into multiple bulk requests or use the legacy CSV upload endpoint (`POST /logistics/upload`).
</Warning>

## Step 1.6: Query Transport Requests

Retrieve your transport legs with pagination and filtering:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Get paginated transport requests
response = requests.get(
    "https://api.dcycle.io/v1/logistics/requests",
    headers=headers,
    params={
        "page": 1,
        "size": 50,
    },
).json()

print(f"Total requests: {response['total']}")
for req in response["items"]:
    print(f"  {req['id'][:8]}... | {req['origin']} → {req['destination']} | {req['co2e']:.2f} kg CO2e")
```

### Query Packages

Track multi-leg shipments via packages:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Get all packages for a specific client
packages = requests.get(
    "https://api.dcycle.io/v1/logistics/packages",
    headers=headers,
    params={
        "client": "IMPORT-CO",
        "page": 1,
        "size": 50,
    },
).json()

for pkg in packages["items"]:
    print(f"Package {pkg['package_key']}: {pkg['total_co2e']:.2f} kg CO2e | {pkg['total_distance_km']:.0f} km")

# Get a single package with all its legs
package_detail = requests.get(
    f"https://api.dcycle.io/v1/logistics/packages/{packages['items'][0]['id']}",
    headers=headers,
).json()

print(f"\nPackage legs:")
for leg in package_detail["legs"]:
    print(f"  {leg['origin']} → {leg['destination']}: {leg['co2e']:.2f} kg CO2e")
```

### List Clients

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Get all client names for the organization
clients = requests.get(
    "https://api.dcycle.io/v1/logistics/clients",
    headers=headers,
).json()

print("Clients with logistics data:")
for client_name in clients:
    print(f"  - {client_name}")
```

## Best Practices

### 1. Choose the Most Specific TOC

More specific TOCs yield more accurate results:

```
Least accurate                                        Most accurate
generic_average_road  →  rigid_truck_diesel  →  rigid_truck_hvo_blend
```

When you know the fuel type and vehicle class, always use the specific TOC.

### 2. Provide Origin Country

Always include `origin_country` for region-specific emission factors:

```python theme={"theme":{"light":"github-light","dark":"github-dark"}}
# Without origin_country → uses GLO (global) factors
shipment = {"category": "road", "distance_km": 500, "load": 5000, "load_unit": "kg"}

# With origin_country → uses EU-specific factors (more accurate)
shipment = {"category": "road", "distance_km": 500, "load": 5000, "load_unit": "kg", "origin_country": "ES"}
```

### 3. Use Movement IDs Consistently

Group related legs with `movement_id` for accurate shipment-level reporting and deduplication.

### 4. Mark Subcontracted Legs

Always set `subcontractor: true` for legs not operated by your own fleet — this ensures correct scope allocation in the GLEC report.

## Next Steps

<CardGroup cols={2}>
  <Card title="Step 2: Hub Operations" icon="warehouse" href="/guides/emissions/glec-step-2-hub-operations">
    Configure logistics hubs and track hub emissions
  </Card>

  <Card title="Step 4: GLEC Reports" icon="chart-pie" href="/guides/emissions/glec-step-4-reports">
    Generate your GLEC company report
  </Card>
</CardGroup>
