- API documentation
EcoFreight CO2 Emissions API
A REST API for calculating freight CO2 emissions across road, sea, rail, and air. It returns WTW, TTW, and WTT breakdowns using GLEC Framework v3.2 factors aligned with ISO 14083:2023.
https://api.ecofreight.co/api/v1Endpoints
POST /calculate- calculate emissions for a single shipment.GET /autocomplete- location autocomplete for calculator-style search.GET /location- location geocoding and code resolution.GET /methodology- methodology metadata and supported factors.
Quick start
The calculate endpoint accepts coordinates, free-text places, IATA airport codes, and UN/LOCODE port codes. The location resolver uses coordinates first, then code, then query.
curl https://api.ecofreight.co/api/v1/calculate \
-H "Authorization: Bearer $ECOFREIGHT_API_KEY" \
-H "Content-Type: application/json" \
-d '{
"origin": { "unlocode": "CNSHA" },
"destination": { "unlocode": "NLRTM" },
"cargo": { "weight": 21000, "type": "refrigerated" },
"transport_mode": "sea",
"vessel_type": "container_ship_8000_teu_plus"
}'JavaScript - air freight with IATA codes
const response = await fetch("https://api.ecofreight.co/api/v1/calculate", {
method: "POST",
headers: {
Authorization: `Bearer ${process.env.ECOFREIGHT_API_KEY}`,
"Content-Type": "application/json",
},
body: JSON.stringify({
origin: { iata: "PVG" },
destination: { iata: "AMS" },
cargo: { weight: 2000, type: "general" },
transport_mode: "air",
vessel_type: "dedicated_cargo",
}),
});
const result = await response.json();Python - free-text locations
import os
import requests
payload = {
"origin": {"query": "Shanghai, China"},
"destination": {"query": "Rotterdam, Netherlands"},
"cargo": {"weight": 5000, "type": "general"},
"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']}"},
json=payload,
timeout=10,
)
response.raise_for_status()
print(response.json()["emissions"]["wtw"])Location inputs
Airports
Use 3-letter IATA airport codes for air freight when you already know the origin and destination airports.
{ "origin": { "iata": "PVG" }, "destination": { "iata": "AMS" } }Ports and terminals
Use 5-character UN/LOCODE values for sea freight and intermodal port legs.
{ "origin": { "unlocode": "CNSHA" }, "destination": { "unlocode": "NLRTM" } }Coordinates
Coordinates are the most explicit input and bypass geocoding ambiguity.
{ "coordinates": { "lat": 31.2, "lng": 121.5 } }Text queries
Use text queries for ad-hoc tools, then store the resolved code or coordinates for repeat calculations.
{ "query": "Rotterdam, Netherlands" }Cargo and mode rules
Cargo type is sent inside the cargo object. Supported values are general, refrigerated, and hazardous. Refrigerated cargo is supported for sea freight, road, rail, and air, and adds the documented refrigeration load to the result instead of changing the vessel class.
Vehicle and vessel types remain mode-specific. For example, a container ship vessel type is valid with transport_mode: "sea", while dedicated_cargo is valid with air freight.
Authentication
Send an Authorization: Bearer ef_live_... header with every production request. You can generate and rotate API keys in the dashboard. Public calculator calls use reCAPTCHA and do not replace authenticated API access.
Rate limits
| Plan | Monthly limit | Burst limit | Headers |
|---|---|---|---|
| Free | 1,000 requests | 60 requests/minute | X-RateLimit-* |
| Growth | 50,000 requests | 300 requests/minute | Retry-After |
| Enterprise | Custom | Contract-specific | X-Request-Id |
Errors and retries
| HTTP | Code | Meaning |
|---|---|---|
| 400 | invalid_request | Required field missing, unsupported cargo type, or impossible coordinates. |
| 401 | unauthorized | Bearer token missing, malformed, expired, or revoked. |
| 404 | location_not_found | A query, IATA airport code, or UN/LOCODE could not be resolved. |
| 422 | unsupported_mode | The selected vessel or vehicle type is not valid for the transport mode. |
| 429 | rate_limited | Plan limit exceeded. Retry after the reset time in the rate-limit headers. |
| 500 | internal_error | Unexpected server error. Safe to retry with exponential backoff. |
Versioning and changelog
Breaking response-shape changes are versioned at the API path. Methodology and rate-limit changes are dated in the methodology changelog. First-party Python and Node SDKs, batch ingest, and webhooks are listed on the roadmap. Until those SDKs ship, the public OpenAPI specification is the supported contract.
Methodology evidence
Every calculation response includes WTW, TTW, WTT, distance, factor source, data quality tier, methodology version, timestamp, and stable calculation ID fields. Use the methodology page and source catalogue as audit references when storing API results.
Implementation templates
OpenAPI contract
The interactive reference loads in the browser. The same OpenAPI 3.1 specification is also available directly at /openapi.json.