{
  "openapi": "3.1.1",
  "info": {
    "title": "Emissions Calculator",
    "description": "This API calculates the CO2e emission of a trip for different transport modes.\n\nFor most transport modes, the SINTEF energy module calculates the emission. It uses the route and a typical vehicle for the transport mode. The emission includes the full lifecycle of the vehicle: production of the fuel or energy, manufacture, maintenance and tailpipe emission.\n\nFor bike, electrical bike and electrical scooter, the API uses a fixed emission factor for each passenger kilometre. SINTEF supplies these factors.\n\n## Client identification\n\nSend the header `ET-Client-Name` in all requests. Use the format `<party>-<application>`, for example `brakar-journeyplanner`. If a client does not send the header, Entur can apply a stricter rate limit to it or block it.\n\n## Rate limits\n\nEach client has a limit for the number of requests each minute and for the highest rate. The API identifies the client from `ET-Client-Name`. A client without the header, or with a name that Entur has not agreed a limit for, can send 60 requests each minute and 5 requests each second. Without the header, the limit applies to each IP address. If a client is over its limit, the API answers with status 429. Wait the number of seconds in the `Retry-After` header before you send more requests. Contact Entur if your client needs a higher limit.\n\n## Correlation ID\n\nEach response has the header `x-correlation-id`. You can send your own value in this header. Use only letters, digits and the characters `.`, `_`, `:` and `-`, with a maximum of 128 characters. Otherwise the API makes a new value.\n\nAn error response also gives the correlation ID in `instance`. Give this value when you contact Entur about a request.",
    "termsOfService": "https://developer.entur.no/terms-of-service",
    "contact": {
      "name": "Team Miljødata",
      "email": "team.miljodata@entur.org"
    },
    "version": "2026.10.0"
  },
  "servers": [
    {
      "url": "https://api.entur.io/emissions-calculator-api/api",
      "description": "Production"
    },
    {
      "url": "https://api.staging.entur.io/emissions-calculator-api/api",
      "description": "Staging"
    },
    {
      "url": "https://api.dev.entur.io/emissions-calculator-api/api",
      "description": "Development"
    }
  ],
  "tags": [
    {
      "name": "Emissions",
      "description": "CO2e emission calculations"
    }
  ],
  "paths": {
    "/v1/calculate-emissions": {
      "post": {
        "tags": [
          "Emissions"
        ],
        "summary": "Calculate the CO2e emission of a route for each transport mode",
        "description": "Each emission is in grams of CO2e and is for all passengers (`numberOfPassengers`) together. The calculation is different for each group of transport modes:\n\n- Train, plane, bus, metro, tram and ferry: the emission of one vehicle, divided by its number of seats and multiplied by the number of passengers.\n- Car and motorcycle: the emission of all the vehicles that are necessary for the passengers.\n- Bike, electrical bike and electrical scooter: the distance multiplied by a fixed factor from SINTEF for each passenger kilometre, and by the number of passengers.\n\nUsually, the response has one calculation for each transport mode in the request. But `calculations` can have fewer items than `transportModes`, for two causes:\n\n- Some transport modes cannot travel the route. An example is a plane between two places that have no airport near them. The response does not include these transport modes. It includes a warning instead.\n- If the calculation fails for a transport mode, the response shows the transport mode in `failures`. The response still includes the other transport modes.",
        "operationId": "calculateEmissions",
        "requestBody": {
          "description": "The route, the number of passengers and the transport modes to calculate the emission for.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/EmissionsRequest"
              },
              "examples": {
                "default": {
                  "value": {
                    "transportModes": [
                      "TRAIN",
                      "DIESEL_CAR",
                      "BIKE"
                    ],
                    "route": {
                      "stopIds": [
                        "NSR:StopPlace:337",
                        "NSR:StopPlace:59983"
                      ]
                    },
                    "numberOfPassengers": 2
                  }
                }
              }
            }
          },
          "required": true
        },
        "responses": {
          "200": {
            "description": "The CO2e emission for each transport mode",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/EmissionsResponse"
                },
                "examples": {
                  "default": {
                    "value": {
                      "calculations": [
                        {
                          "transportMode": "TRAIN",
                          "calculationSummary": {
                            "numberOfVehicles": 1,
                            "co2eEmissionInGrams": "1739.564818547628",
                            "distanceKm": 464.2760378447166
                          },
                          "legs": [
                            {
                              "trainLine": null,
                              "vehicleId": "web:train-type-75",
                              "distanceKm": 464.2760378447166,
                              "co2eEmissionInGrams": "1739.564818547628"
                            }
                          ]
                        },
                        {
                          "transportMode": "DIESEL_CAR",
                          "calculationSummary": {
                            "numberOfVehicles": 1,
                            "co2eEmissionInGrams": "98239.23316014852",
                            "distanceKm": 460.7870161608051
                          },
                          "legs": null
                        },
                        {
                          "transportMode": "BIKE",
                          "detailedSintefCalculations": null,
                          "calculationSummary": {
                            "numberOfVehicles": 2,
                            "co2eEmissionInGrams": "18010.825956526136",
                            "distanceKm": 459.4598458297483
                          },
                          "legs": null
                        }
                      ],
                      "warnings": [],
                      "failures": []
                    }
                  }
                }
              }
            }
          },
          "400": {
            "description": "The request is not valid. The value of `title` shows the cause:\n\n- `Bad Request`: The body is not valid JSON, or a field has a value that is not permitted. For example, a required field is missing, `transportModes` is empty, or `numberOfPassengers` is less than 1.\n- `invalid_route`: The route has fewer than two points. If the route has waypoints, it must have two or more, and each waypoint must have x and y. If the route has no waypoints, it must have two or more stop IDs, and each stop ID must have a value that is not blank.\n- `unknown_stop_place`: The stop place register does not have a stop place, quay or group of stop places with this stop ID.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "invalidRequest": {
                    "summary": "Invalid request body",
                    "value": {
                      "type": "about:blank",
                      "title": "Bad Request",
                      "status": 400,
                      "detail": "Invalid request content.",
                      "instance": "urn:uuid:3f2b8c1e-6d4a-4b7e-9a1f-2c5d8e7b6a90"
                    }
                  },
                  "invalidRoute": {
                    "summary": "Route with fewer than two points",
                    "value": {
                      "type": "https://api.entur.io/emissions-calculator-api/problems/invalid-route",
                      "title": "invalid_route",
                      "status": 400,
                      "detail": "route must have at least two waypoints, each with x and y, or at least two stopIds",
                      "instance": "urn:uuid:9d0c7e2a-1b4f-4c3d-8e5a-6f7b8c9d0e1f"
                    }
                  },
                  "unknownStopPlace": {
                    "summary": "Stop id not found",
                    "value": {
                      "type": "https://api.entur.io/emissions-calculator-api/problems/unknown-stop-place",
                      "title": "unknown_stop_place",
                      "status": 400,
                      "detail": "Unknown stop place or quay: NSR:StopPlace:999999999",
                      "instance": "urn:uuid:5a6b7c8d-9e0f-4a1b-8c2d-3e4f5a6b7c8d"
                    }
                  }
                }
              }
            }
          },
          "429": {
            "description": "The client sent too many requests. Wait the number of seconds in the `Retry-After` header before you send more requests. See the section about rate limits.",
            "headers": {
              "Retry-After": {
                "description": "The number of seconds to wait before the next request.",
                "style": "simple",
                "explode": false,
                "schema": {
                  "type": "integer",
                  "examples": [
                    1
                  ]
                }
              }
            },
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "default": {
                    "value": {
                      "type": "https://api.entur.io/emissions-calculator-api/problems/rate-limit-exceeded",
                      "title": "rate_limit_exceeded",
                      "status": 429,
                      "detail": "The client sent too many requests. Wait the number of seconds in the Retry-After header before you send more requests.",
                      "instance": "urn:uuid:7a1c2e3d-4b5f-4a6e-8c7d-9e0f1a2b3c4d"
                    }
                  }
                }
              }
            }
          },
          "500": {
            "description": "An unexpected error occurred. For example, the stop place register is not available when the API examines which transport modes can travel the route.\n\nAn error in the SINTEF energy module or the stop place register can also occur during the calculation for one transport mode. Then the response shows that transport mode in `failures`, and the status is 200.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                },
                "examples": {
                  "default": {
                    "value": {
                      "type": "https://api.entur.io/emissions-calculator-api/problems/internal-error",
                      "title": "internal_error",
                      "status": 500,
                      "detail": "Unexpected error while calculating emissions",
                      "instance": "urn:uuid:c1d2e3f4-a5b6-4c7d-8e9f-0a1b2c3d4e5f"
                    }
                  }
                }
              }
            }
          }
        }
      },
      "parameters": [
        {
          "$ref": "#/components/parameters/ET-Client-Name"
        },
        {
          "$ref": "#/components/parameters/X-Correlation-Id"
        }
      ]
    }
  },
  "components": {
    "schemas": {
      "TransportMode": {
        "type": "string",
        "description": "The SINTEF energy module calculates the emission for all transport modes, but not for BIKE, ELECTRICAL_BIKE and ELECTRICAL_SCOOTER. For these three, the API uses a fixed factor from SINTEF for each passenger kilometre.",
        "enum": [
          "TRAIN",
          "ELECTRICAL_CAR",
          "DIESEL_CAR",
          "MOTORCYCLE",
          "PLANE",
          "ELECTRICAL_BUS",
          "DIESEL_BUS",
          "METRO",
          "FERRY",
          "TRAM",
          "BIKE",
          "ELECTRICAL_BIKE",
          "ELECTRICAL_SCOOTER"
        ]
      },
      "Route": {
        "type": "object",
        "properties": {
          "waypoints": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Point"
            }
          },
          "stopIds": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "examples": [
              [
                "NSR:StopPlace:337",
                "NSR:StopPlace:59983"
              ]
            ]
          }
        },
        "description": "The route of the trip, as waypoints or as stop IDs. A stop ID can identify a stop place, a quay or a group of stop places.\n\nIf the route has waypoints, the API uses only the waypoints and ignores the stop IDs. Then the route must have two or more waypoints, and each waypoint must have x and y. If the route has no waypoints, the API uses the stop IDs. Then the route must have two or more stop IDs.",
        "anyOf": [
          {
            "required": [
              "waypoints"
            ],
            "properties": {
              "waypoints": {
                "minItems": 2
              }
            },
            "description": "Waypoints"
          },
          {
            "required": [
              "stopIds"
            ],
            "properties": {
              "stopIds": {
                "minItems": 2,
                "type": "array",
                "items": {
                  "pattern": "\\S",
                  "type": "string"
                }
              },
              "waypoints": {
                "maxItems": 0
              }
            },
            "description": "Stop IDs, and no waypoints"
          }
        ]
      },
      "Point": {
        "required": [
          "x",
          "y"
        ],
        "type": "object",
        "properties": {
          "x": {
            "type": "number",
            "format": "double",
            "examples": [
              10.7522
            ]
          },
          "y": {
            "type": "number",
            "format": "double",
            "examples": [
              59.9111
            ]
          },
          "z": {
            "type": "number",
            "format": "double"
          }
        },
        "description": "A coordinate in WGS84 (EPSG:4326). x is the longitude and y is the latitude."
      },
      "EmissionsRequest": {
        "required": [
          "numberOfPassengers",
          "route",
          "transportModes"
        ],
        "type": "object",
        "properties": {
          "transportModes": {
            "minItems": 1,
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransportMode"
            }
          },
          "route": {
            "$ref": "#/components/schemas/Route"
          },
          "numberOfPassengers": {
            "minimum": 1,
            "type": "integer",
            "format": "int32"
          },
          "distanceKm": {
            "exclusiveMinimum": 0,
            "type": "number",
            "description": "The distance of the trip in kilometres. The API uses this distance for bike, electrical bike and electrical scooter. If you do not send it, the API calculates the distance along the roads.",
            "format": "double"
          }
        }
      },
      "EmissionsResponse": {
        "required": [
          "calculations",
          "failures",
          "warnings"
        ],
        "type": "object",
        "properties": {
          "calculations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransportModeCalculation"
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string",
              "enum": [
                "UNSUPPORTED_TRANSPORT_MODES_OMITTED_FROM_CALCULATIONS"
              ]
            }
          },
          "failures": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TransportModeCalculationFailure"
            }
          }
        }
      },
      "TransportModeCalculation": {
        "required": [
          "calculationSummary",
          "transportMode"
        ],
        "type": "object",
        "properties": {
          "transportMode": {
            "$ref": "#/components/schemas/TransportMode"
          },
          "detailedSintefCalculations": {
            "type": [
              "object",
              "null"
            ],
            "additionalProperties": true,
            "description": "The response from the SINTEF energy module, without changes. The value is null for bike, electrical bike and electrical scooter. It is also null for a train trip with more than one leg."
          },
          "calculationSummary": {
            "$ref": "#/components/schemas/CalculationSummary"
          },
          "legs": {
            "type": [
              "array",
              "null"
            ],
            "description": "The parts of a train trip. Each leg uses one train type, for example an electric train or a diesel train. If the full trip uses one train type, there is one leg, and `detailedSintefCalculations` also has a value. The value is null for all transport modes other than TRAIN.",
            "items": {
              "$ref": "#/components/schemas/TrainLeg"
            }
          }
        }
      },
      "TrainLeg": {
        "required": [
          "co2eEmissionInGrams",
          "vehicleId"
        ],
        "type": "object",
        "properties": {
          "trainLine": {
            "type": [
              "string",
              "null"
            ],
            "description": "The diesel line of the leg. The value is null if the leg uses an electric train.",
            "examples": [
              "NORDLANDSBANEN"
            ]
          },
          "vehicleId": {
            "type": "string",
            "description": "The SINTEF vehicle that the calculation for the leg uses.",
            "examples": [
              "web:train-type-93"
            ]
          },
          "distanceKm": {
            "type": [
              "number",
              "null"
            ],
            "description": "The length of the leg in kilometres. The value is null if the SINTEF energy module does not give a length.",
            "format": "double"
          },
          "co2eEmissionInGrams": {
            "type": "string",
            "description": "The CO2e emission of the leg in grams. The value is a string, to keep full precision."
          }
        }
      },
      "CalculationSummary": {
        "required": [
          "co2eEmissionInGrams",
          "numberOfVehicles"
        ],
        "type": "object",
        "properties": {
          "numberOfVehicles": {
            "type": "integer",
            "description": "The number of vehicles that are necessary for all the passengers.",
            "format": "int32"
          },
          "co2eEmissionInGrams": {
            "type": "string",
            "description": "The total CO2e emission for all passengers in grams. The value is a string, to keep full precision."
          },
          "distanceKm": {
            "type": [
              "number",
              "null"
            ],
            "description": "The length of the route in kilometres. The value is null if the SINTEF energy module does not give a length.",
            "format": "double"
          }
        }
      },
      "TransportModeCalculationFailure": {
        "required": [
          "reason",
          "transportMode"
        ],
        "type": "object",
        "properties": {
          "transportMode": {
            "$ref": "#/components/schemas/TransportMode"
          },
          "reason": {
            "type": "string",
            "description": "The cause of the failure, as text for a person to read. Use it in logs. Do not compare it with a fixed value, because the text can change."
          }
        }
      },
      "Problem": {
        "required": [
          "instance",
          "status",
          "title",
          "type"
        ],
        "type": "object",
        "properties": {
          "type": {
            "type": "string",
            "description": "Identifies the type of error. Errors from the API have their own URI. The URI only identifies the type of error: it does not open a page. For other errors, the value is `about:blank`.",
            "format": "uri",
            "examples": [
              "https://api.entur.io/emissions-calculator-api/problems/unknown-stop-place"
            ]
          },
          "title": {
            "type": "string",
            "description": "For errors from the API, a code for the type of error, for example `unknown_stop_place`. For other errors, the HTTP status text.",
            "examples": [
              "unknown_stop_place"
            ]
          },
          "status": {
            "type": "integer",
            "description": "The HTTP status code.",
            "format": "int32",
            "examples": [
              400
            ]
          },
          "detail": {
            "type": "string",
            "description": "An explanation of this occurrence of the error, as text for a person to read."
          },
          "instance": {
            "type": "string",
            "description": "Identifies this occurrence of the error with the correlation ID of the request. If the correlation ID is a UUID, the value is `urn:uuid:<correlation ID>`. If not, the value is `urn:correlation-id:<correlation ID>`. Give this value when you contact Entur about the error.",
            "format": "uri",
            "examples": [
              "urn:uuid:3f2b8c1e-6d4a-4b7e-9a1f-2c5d8e7b6a90"
            ]
          }
        },
        "description": "An error response as described by RFC 9457. All errors from the endpoint use this format."
      }
    },
    "parameters": {
      "ET-Client-Name": {
        "name": "ET-Client-Name",
        "in": "header",
        "description": "Entur Client Header.\nIt is required that all consumers identify themselves by using this header.\nEntur will deploy strict rate-limiting policies on API-consumers who do not identify with a header and reserves the right to block unidentified consumers.\nThe structure of ET-Client-Name should be: `<company>-<application>`.",
        "required": false,
        "style": "simple",
        "explode": false,
        "schema": {
          "type": "string"
        }
      },
      "X-Correlation-Id": {
        "name": "X-Correlation-Id",
        "in": "header",
        "description": "Correlation id",
        "required": false,
        "style": "simple",
        "explode": false,
        "schema": {
          "type": "string"
        }
      }
    }
  }
}