{
  "openapi": "3.1.0",
  "info": {
    "title": "EcoFreight API",
    "version": "1.0.0",
    "description": "Freight CO2 emissions calculation API. GLEC Framework v3.2 certified, ISO 14083 aligned.\n\nAll endpoints require a Bearer token. Get your API key from the [dashboard](/dashboard).",
    "contact": {
      "email": "hello@ecofreight.co",
      "url": "https://ecofreight.co"
    }
  },
  "servers": [
    {
      "url": "https://api.ecofreight.co/api/v1",
      "description": "Production"
    }
  ],
  "security": [
    {
      "bearerAuth": []
    }
  ],
  "paths": {
    "/autocomplete": {
      "get": {
        "operationId": "autocompleteLocation",
        "summary": "Autocomplete location query",
        "description": "Returns location suggestions for a partial query string. Backed by Mapbox Geocoding. Use to power typeahead inputs in your own UI before passing a resolved location to /calculate.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": { "type": "string" },
            "description": "Partial location string (e.g. \"Rott\", \"Shangh\")"
          },
          {
            "name": "types",
            "in": "query",
            "required": false,
            "schema": { "type": "string", "default": "place,region,country" },
            "description": "Comma-separated Mapbox feature types to include"
          }
        ],
        "responses": {
          "200": {
            "description": "Autocomplete suggestions",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "suggestions": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "name": { "type": "string" },
                          "country": { "type": "string" },
                          "coordinates": {
                            "type": "object",
                            "properties": {
                              "lat": { "type": "number" },
                              "lng": { "type": "number" }
                            }
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing or invalid query parameter" },
          "401": { "description": "Missing or invalid API key" }
        }
      }
    },
    "/location": {
      "get": {
        "operationId": "geocodeLocation",
        "summary": "Geocode a location query",
        "description": "Resolves a free-text location query to coordinates and a canonical place name. Use this when you want a single resolved location rather than autocomplete suggestions.",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "schema": { "type": "string" },
            "description": "Location string to geocode (e.g. \"Rotterdam, Netherlands\")"
          }
        ],
        "responses": {
          "200": {
            "description": "Geocoded location",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "properties": {
                    "name": { "type": "string" },
                    "country": { "type": "string" },
                    "coordinates": {
                      "type": "object",
                      "properties": {
                        "lat": { "type": "number" },
                        "lng": { "type": "number" }
                      }
                    }
                  }
                }
              }
            }
          },
          "400": { "description": "Missing or invalid query parameter" },
          "401": { "description": "Missing or invalid API key" },
          "404": { "description": "Location not found" }
        }
      }
    },
    "/calculate": {
      "post": {
        "operationId": "calculateEmissions",
        "summary": "Calculate freight emissions",
        "description": "Calculate CO2 emissions for a freight route. Returns WTW, TTW, and WTT breakdowns using GLEC Framework v3.2 emission factors.\n\nHub/transshipment emissions are automatically included for air and sea transport (GLEC v3.2 defaults). Use `hub_emissions_per_tonne` to override with primary data, or set to `0` to disable.",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/CalculateRequest"
              },
              "examples": {
                "coordinates": {
                  "summary": "Using coordinates",
                  "value": {
                    "origin": { "coordinates": { "lat": 31.2, "lng": 121.5 } },
                    "destination": { "coordinates": { "lat": 51.9, "lng": 4.5 } },
                    "cargo": { "weight": 21000, "type": "general" },
                    "transport_mode": "sea",
                    "vessel_type": "container_ship_8000_teu_plus"
                  }
                },
                "query": {
                  "summary": "Using text query",
                  "value": {
                    "origin": { "query": "Shanghai, China" },
                    "destination": { "query": "Rotterdam, Netherlands" },
                    "cargo": { "weight": 5000, "type": "general" },
                    "transport_mode": "air",
                    "vessel_type": "dedicated_cargo"
                  }
                },
                "iata": {
                  "summary": "Using IATA codes (air freight)",
                  "value": {
                    "origin": { "iata": "PVG" },
                    "destination": { "iata": "AMS" },
                    "cargo": { "weight": 2000, "type": "general" },
                    "transport_mode": "air",
                    "vessel_type": "dedicated_cargo"
                  }
                },
                "unlocode": {
                  "summary": "Using UN/LOCODE (sea freight)",
                  "value": {
                    "origin": { "unlocode": "CNSHA" },
                    "destination": { "unlocode": "NLRTM" },
                    "cargo": { "weight": 21000, "type": "general" },
                    "transport_mode": "sea",
                    "vessel_type": "container_ship_8000_teu_plus"
                  }
                },
                "hub_override": {
                  "summary": "With hub emissions override",
                  "value": {
                    "origin": { "query": "Frankfurt, Germany" },
                    "destination": { "query": "New York, USA" },
                    "cargo": { "weight": 3000, "type": "general" },
                    "transport_mode": "air",
                    "vessel_type": "dedicated_cargo",
                    "hub_emissions_per_tonne": 4.2
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Emissions calculation result",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/CalculateResponse"
                },
                "example": {
                  "emissions": {
                    "total": 3842.7,
                    "wtw": 3842.7,
                    "ttw": 3267.3,
                    "wtt": 575.4
                  },
                  "calculation": {
                    "distance": 19550,
                    "activity": 410550,
                    "data_quality": "default",
                    "emission_factor": {
                      "value": 9.8,
                      "source": "GLEC Framework v3.2",
                      "quality": "default"
                    }
                  },
                  "methodology": {
                    "standard": "ISO 14083:2023",
                    "framework": "GLEC Framework v3.2",
                    "formula": "emissions (kg CO2e) = activity (tonne-km) × emission_factor (g CO2e/tkm) / 1000",
                    "assumptions": [
                      "Activity data: weight (tonnes) × distance (km) = tonne-km",
                      "Emission factor unit: g CO2e/tkm (WTW)",
                      "WTW = TTW + WTT",
                      "Hub/transshipment emissions: 1.8 kg CO2e/tonne (GLEC v3.2 default — port terminal handling at origin + destination)"
                    ]
                  },
                  "timestamp": "2026-03-13T10:00:00Z",
                  "calculation_id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
                }
              }
            }
          },
          "400": {
            "description": "Invalid request",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Error"
                }
              }
            }
          },
          "401": {
            "description": "Missing or invalid API key"
          },
          "429": {
            "description": "Rate limit exceeded"
          }
        }
      }
    }
  },
  "components": {
    "securitySchemes": {
      "bearerAuth": {
        "type": "http",
        "scheme": "bearer",
        "description": "API key from your dashboard. Include as `Authorization: Bearer YOUR_API_KEY`."
      }
    },
    "schemas": {
      "LocationInput": {
        "type": "object",
        "description": "Flexible location input. Provide at least one of: coordinates, iata, unlocode, or query. Resolution priority: coordinates > iata/unlocode > query.",
        "properties": {
          "coordinates": {
            "type": "object",
            "properties": {
              "lat": { "type": "number", "description": "Latitude (-90 to 90)", "minimum": -90, "maximum": 90 },
              "lng": { "type": "number", "description": "Longitude (-180 to 180)", "minimum": -180, "maximum": 180 }
            },
            "required": ["lat", "lng"]
          },
          "iata": { "type": "string", "description": "3-letter IATA airport code (e.g. PVG, AMS)", "minLength": 3, "maxLength": 3 },
          "unlocode": { "type": "string", "description": "5-character UN/LOCODE (e.g. CNSHA, NLRTM)", "minLength": 5, "maxLength": 5 },
          "query": { "type": "string", "description": "Free-text location search (e.g. \"Shanghai, China\")" }
        }
      },
      "CalculateRequest": {
        "type": "object",
        "required": ["origin", "destination", "cargo", "transport_mode"],
        "properties": {
          "origin": {
            "$ref": "#/components/schemas/LocationInput"
          },
          "destination": {
            "$ref": "#/components/schemas/LocationInput"
          },
          "cargo": {
            "type": "object",
            "required": ["weight"],
            "properties": {
              "weight": { "type": "number", "description": "Cargo weight in kg", "minimum": 1, "maximum": 100000 },
              "type": {
                "type": "string",
                "enum": ["general", "refrigerated", "hazardous"],
                "default": "general",
                "description": "Cargo type. Refrigerated adds +12%, hazardous adds +5% to emissions."
              }
            }
          },
          "transport_mode": {
            "type": "string",
            "enum": ["road", "rail", "sea", "air", "pipeline", "electric"],
            "description": "Transport mode"
          },
          "vessel_type": {
            "type": "string",
            "description": "Vehicle/vessel type. Options depend on transport_mode.",
            "enum": [
              "heavy_truck_16t_plus", "medium_truck_7_5_16t", "light_commercial_under_7_5t", "electric_truck",
              "diesel_freight", "electric_freight",
              "container_ship_8000_teu_plus", "container_ship_3000_8000_teu", "container_ship_under_3000_teu", "bulk_carrier", "tanker",
              "dedicated_cargo", "belly_cargo", "dedicated_cargo_short_haul", "dedicated_cargo_long_haul", "belly_cargo_long_haul",
              "gas_pipeline"
            ]
          },
          "distance_override": {
            "type": "number",
            "description": "Override calculated distance (km). Use when you have a known route distance.",
            "minimum": 0,
            "exclusiveMinimum": true
          },
          "hub_emissions_per_tonne": {
            "type": "number",
            "description": "Override hub/transshipment emissions (kg CO2e per tonne of cargo, WTW). GLEC v3.2 defaults: air = 3.5, sea = 1.8. Set to 0 to disable hub emissions.",
            "minimum": 0
          },
          "fuel_consumed": {
            "type": "number",
            "description": "Actual fuel consumed (litres for diesel/petrol, kg for HFO/jet fuel, kWh for electric). Enables ISO 14083 Tier 1 primary data calculation.",
            "minimum": 0,
            "exclusiveMinimum": true
          },
          "fuel_type": {
            "type": "string",
            "enum": ["diesel", "petrol", "hfo", "jet_fuel", "lng", "electric"],
            "description": "Fuel type. Required when fuel_consumed is provided."
          },
          "include_rf": {
            "type": "boolean",
            "description": "Include radiative forcing for air freight (default: true, multiplier: 1.9×).",
            "default": true
          }
        }
      },
      "CalculateResponse": {
        "type": "object",
        "properties": {
          "emissions": {
            "type": "object",
            "properties": {
              "total": { "type": "number", "description": "Total CO2e in kg (same as WTW)" },
              "wtw": { "type": "number", "description": "Well-to-Wheel CO2e in kg — total lifecycle emissions" },
              "ttw": { "type": "number", "description": "Tank-to-Wheel CO2e in kg — direct combustion emissions" },
              "wtt": { "type": "number", "description": "Well-to-Tank CO2e in kg — upstream fuel production emissions" }
            }
          },
          "calculation": {
            "type": "object",
            "properties": {
              "distance": { "type": "number", "description": "Route distance in km" },
              "activity": { "type": "number", "description": "Transport activity in tonne-km" },
              "data_quality": { "type": "string", "enum": ["primary", "secondary", "default"], "description": "ISO 14083 data quality tier" },
              "emission_factor": {
                "type": "object",
                "properties": {
                  "value": { "type": "number", "description": "Emission factor in g CO2e/tkm" },
                  "source": { "type": "string" },
                  "quality": { "type": "string", "enum": ["primary", "secondary", "default"] }
                }
              }
            }
          },
          "methodology": {
            "type": "object",
            "properties": {
              "standard": { "type": "string" },
              "framework": { "type": "string" },
              "formula": { "type": "string" },
              "description": { "type": "string" },
              "references": { "type": "array", "items": { "type": "string" } },
              "assumptions": { "type": "array", "items": { "type": "string" } }
            }
          },
          "timestamp": { "type": "string", "format": "date-time" },
          "calculation_id": { "type": "string", "format": "uuid" }
        }
      },
      "Error": {
        "type": "object",
        "properties": {
          "error": {
            "type": "object",
            "properties": {
              "code": { "type": "string" },
              "message": { "type": "string" },
              "details": {}
            }
          },
          "request_id": { "type": "string" }
        }
      }
    }
  }
}
