Skip to main content
Integration tutorial

How to call a freight emissions API from Python

A Python integration tutorial for EcoFreight: authenticate, send UN/LOCODE or IATA inputs, handle rate limits, and store audit fields from the freight CO2 API response.

Use stable codes first

Prefer UN/LOCODE for ports and IATA for airports. Text queries work, but storing resolved codes makes repeat calculations deterministic.

Store the evidence

Persist calculation_id, factor source, methodology version, and data quality tier alongside the shipment record.

Retry only safe failures

Retry 429 and 5xx responses with backoff. Treat validation errors as data problems and surface them to the operator.

1. Create the request payload

The calculate endpoint accepts coordinates, UN/LOCODE, IATA airport codes, or text queries for each location. The example below uses the Shanghai to Rotterdam sea lane and refrigerated cargo so the payload mirrors a real reefer container workflow.

python
import os
import requests

payload = {
    "origin": {"unlocode": "CNSHA"},
    "destination": {"unlocode": "NLRTM"},
    "cargo": {"weight": 21000, "type": "refrigerated"},
    "transport_mode": "sea",
    "vessel_type": "container_ship_8000_teu_plus",
}

response = requests.post(
    "https://api.ecofreight.co/api/v1/calculate",
    headers={
        "Authorization": f"Bearer {os.environ['ECOFREIGHT_API_KEY']}",
        "Content-Type": "application/json",
    },
    json=payload,
    timeout=10,
)
response.raise_for_status()
result = response.json()

print(result["emissions"]["wtw"])
print(result["calculation_id"])

2. Persist the response fields an auditor will ask for

Do not store only the final kg CO2e number. Store the method fields too: calculation ID, WTW/TTW/WTT breakdown, distance, factor source, methodology version, and ISO 14083 data quality tier. Those fields are what make the same shipment defensible later.

3. Add retry handling

python retry
from time import sleep

for attempt in range(4):
    response = requests.post(API_URL, headers=headers, json=payload, timeout=10)
    if response.status_code != 429 and response.status_code < 500:
        break
    retry_after = int(response.headers.get("Retry-After", "2"))
    sleep(retry_after * (attempt + 1))

response.raise_for_status()

Production checklist

Keep the API key in environment secrets, not source code.

Send kilogram weights as numbers and normalize units before calling the API.

Log validation errors with the shipment ID and operator-visible field names.

Cache repeat lane defaults only when cargo, mode, vessel type, and weight match.

Store calculation_id for every shipment that appears in a customer report.

Pin methodology output by report period before filing CSRD or CDP disclosures.