{
  "openapi": "3.1.1",
  "info": {
    "title": "Road Trip Fuel and Charging Cost API",
    "version": "1.0.0",
    "summary": "Fuel or charging cost of a road trip, leg by leg with country prices, split fairly per person.",
    "description": "Every endpoint performs the same calculation as the human page and returns inputs, result, units, assumptions, sources, warnings and computedAt. MCP endpoint: /mcp."
  },
  "servers": [
    {
      "url": "https://hearthtripenergycost.usefulweb.site"
    }
  ],
  "paths": {
    "/api/v1/calculate": {
      "post": {
        "operationId": "calculate",
        "summary": "Fuel or charging cost of a road trip, leg by leg with country prices, split fairly per person.",
        "description": "Enter the legs of a road trip with the price per litre or kWh you expect in each country, your car’s consumption and extras such as tolls, vignettes or ferries. You get the energy and cost per leg, the total, the cost per 100 km and each person’s share to the cent. No routing service is used: enter the kilometres yourself or let two coordinates give an estimate.\n\nMethodology:\n- Energy per leg = distance × consumption ÷ 100 (doubled for “there and back”); for electric cars the energy you pay for is the battery energy × (1 + charging losses). Cost per leg = energy × your price, rounded to the cent.\n- Extras (tolls, vignettes, ferries, parking) are added once. The total is split equally between the people with the largest-remainder method in whole cents — the same method as the Tip \u0026 Bill Split Calculator — so the shares add up exactly to the total.\n- Optional distance estimate: the WGS84 geodesic distance between two coordinates (Karney 2013, RavingDesk geo engine) × 1.46, the average road circuity for Europe from Ballou, Rahardja \u0026 Sakai (2002); the Detour Budget Planner uses the same factor. It fills one leg left at 0 km. No routing or map service is contacted.\n- Prices are yours: enter what you expect to pay in each country. The cheapest and dearest legs by price show where filling up or charging is worth planning.\n\nAn estimate: real consumption depends on speed, load, weather and traffic. Check toll and vignette rules for every country you drive through.",
        "tags": [
          "apps"
        ],
        "x-mcp-tool": "hearth_trip_energy_cost",
        "x-owner-app": "hearth",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/HearthTripEnergyCostInput"
              },
              "examples": {
                "example1": {
                  "summary": "Munich to Venice by petrol car, Brennero toll, three people",
                  "value": {
                    "energy": "fuel",
                    "consumption": 6.5,
                    "legs": [
                      {
                        "label": "Munich to the Brenner",
                        "country": "Germany and Austria",
                        "km": 160,
                        "price": 1.75
                      },
                      {
                        "label": "Brenner to Venice",
                        "country": "Italy",
                        "km": 290,
                        "price": 1.85
                      }
                    ],
                    "extras": [
                      {
                        "label": "Austrian vignette (10 days)",
                        "amount": 12.4
                      },
                      {
                        "label": "Brenner motorway toll",
                        "amount": 11.5
                      }
                    ],
                    "people": 3,
                    "names": "Alex, Sam, Robin",
                    "currency": "EUR"
                  }
                },
                "example2": {
                  "summary": "Electric car, 18 kWh/100 km, home charging and fast chargers, there and back",
                  "value": {
                    "energy": "electric",
                    "consumption": 18,
                    "lossPercent": 10,
                    "roundTrip": true,
                    "legs": [
                      {
                        "label": "Home charge",
                        "country": "Germany",
                        "km": 250,
                        "price": 0.35
                      },
                      {
                        "label": "Fast charger",
                        "country": "Germany",
                        "km": 200,
                        "price": 0.59
                      }
                    ],
                    "people": 2,
                    "currency": "EUR"
                  }
                },
                "example3": {
                  "summary": "Estimate the distance from coordinates: Hamburg to Copenhagen, diesel",
                  "value": {
                    "energy": "fuel",
                    "consumption": 5.4,
                    "legs": [
                      {
                        "label": "Hamburg to Copenhagen",
                        "country": "Germany and Denmark",
                        "km": 0,
                        "price": 1.7
                      }
                    ],
                    "people": 2,
                    "currency": "EUR",
                    "from": "53.55, 9.99",
                    "to": "55.68, 12.57"
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Calculation result envelope.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HearthTripEnergyCostResult"
                }
              }
            }
          },
          "400": {
            "description": "Malformed JSON body.",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "422": {
            "description": "Invalid input (see errors[]).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          },
          "429": {
            "description": "Rate limit exceeded (see Retry-After).",
            "content": {
              "application/problem+json": {
                "schema": {
                  "$ref": "#/components/schemas/Problem"
                }
              }
            }
          }
        }
      }
    },
    "/api/v1/tool": {
      "get": {
        "operationId": "getToolDefinition",
        "summary": "Inputs, output schema and examples for this tool",
        "responses": {
          "200": {
            "description": "Tool definition.",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object"
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "Problem": {
        "type": "object",
        "description": "RFC 9457 problem details. 422 responses include per-field `errors`.",
        "required": [
          "type",
          "title",
          "status",
          "detail"
        ],
        "properties": {
          "type": {
            "type": "string"
          },
          "title": {
            "type": "string"
          },
          "status": {
            "type": "integer"
          },
          "detail": {
            "type": "string"
          },
          "code": {
            "type": "string"
          },
          "errors": {
            "type": "array",
            "items": {
              "type": "object",
              "required": [
                "field",
                "message"
              ],
              "properties": {
                "field": {
                  "type": "string"
                },
                "message": {
                  "type": "string"
                }
              }
            }
          }
        }
      },
      "HearthTripEnergyCostInput": {
        "type": "object",
        "additionalProperties": false,
        "properties": {
          "energy": {
            "title": "Vehicle",
            "type": "string",
            "enum": [
              "fuel",
              "electric"
            ],
            "default": "fuel"
          },
          "consumption": {
            "title": "Consumption per 100 km (litres or kWh)",
            "type": "number",
            "minimum": 0.1,
            "maximum": 100,
            "default": 6.5
          },
          "lossPercent": {
            "title": "Charging losses (%, electric only)",
            "description": "Energy you pay for at the charger that does not reach the battery. Enter your own figure if you know it.",
            "type": "number",
            "minimum": 0,
            "maximum": 50,
            "default": 0
          },
          "roundTrip": {
            "title": "Drive every leg there and back",
            "type": "boolean",
            "default": false
          },
          "legs": {
            "title": "Legs",
            "type": "array",
            "minItems": 1,
            "maxItems": 12,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "label": {
                  "title": "Leg",
                  "type": "string",
                  "maxLength": 60
                },
                "country": {
                  "title": "Country (optional)",
                  "type": "string",
                  "maxLength": 40
                },
                "km": {
                  "title": "Distance (km)",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 20000
                },
                "price": {
                  "title": "Price per litre or kWh",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100
                }
              },
              "required": [
                "km",
                "price"
              ]
            },
            "default": [
              {
                "label": "Munich to the Brenner",
                "country": "Germany and Austria",
                "km": 160,
                "price": 1.75
              },
              {
                "label": "Brenner to Venice",
                "country": "Italy",
                "km": 290,
                "price": 1.85
              }
            ]
          },
          "extras": {
            "title": "Tolls, vignettes, ferries, parking (optional)",
            "type": "array",
            "maxItems": 10,
            "items": {
              "type": "object",
              "additionalProperties": false,
              "properties": {
                "label": {
                  "title": "Cost",
                  "type": "string",
                  "maxLength": 60
                },
                "amount": {
                  "title": "Amount",
                  "type": "number",
                  "minimum": 0,
                  "maximum": 100000
                }
              },
              "required": [
                "amount"
              ]
            },
            "default": []
          },
          "people": {
            "title": "Split between (people)",
            "type": "integer",
            "minimum": 1,
            "maximum": 9,
            "default": 2
          },
          "names": {
            "title": "Names (optional, comma-separated)",
            "type": "string",
            "maxLength": 400,
            "default": ""
          },
          "currency": {
            "title": "Currency code",
            "type": "string",
            "maxLength": 3,
            "default": "EUR"
          },
          "from": {
            "title": "Estimate from (latitude, longitude; optional)",
            "description": "With “to”, the straight-line distance × 1.46 (European road circuity) fills one leg without kilometres.",
            "type": "string",
            "maxLength": 60,
            "default": ""
          },
          "to": {
            "title": "Estimate to (latitude, longitude; optional)",
            "type": "string",
            "maxLength": 60,
            "default": ""
          }
        },
        "required": []
      },
      "HearthTripEnergyCostResult": {
        "type": "object",
        "additionalProperties": false,
        "required": [
          "schemaVersion",
          "tool",
          "computedAt",
          "inputs",
          "summary",
          "result",
          "units",
          "assumptions",
          "sources",
          "warnings",
          "presentation",
          "links"
        ],
        "properties": {
          "schemaVersion": {
            "type": "string",
            "const": "1.0"
          },
          "tool": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "id",
              "name",
              "version"
            ],
            "properties": {
              "id": {
                "type": "string"
              },
              "name": {
                "type": "string"
              },
              "version": {
                "type": "string"
              }
            }
          },
          "computedAt": {
            "type": "string",
            "format": "date-time"
          },
          "inputs": {
            "type": "object",
            "description": "Normalised inputs actually used, including applied defaults."
          },
          "summary": {
            "type": "string"
          },
          "result": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "energy",
              "unit",
              "consumption",
              "lossPercent",
              "roundTrip",
              "currency",
              "legs",
              "extras",
              "totalKm",
              "totalEnergy",
              "energyCost",
              "extrasCost",
              "total",
              "costPer100Km",
              "perPerson",
              "cheapestLeg",
              "estimate"
            ],
            "properties": {
              "energy": {
                "enum": [
                  "fuel",
                  "electric"
                ]
              },
              "unit": {
                "type": "string"
              },
              "consumption": {
                "type": "number"
              },
              "lossPercent": {
                "type": "number"
              },
              "roundTrip": {
                "type": "boolean"
              },
              "currency": {
                "type": "string"
              },
              "legs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "label",
                    "country",
                    "km",
                    "energy",
                    "price",
                    "cost"
                  ],
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "country": {
                      "type": "string"
                    },
                    "km": {
                      "type": "number"
                    },
                    "energy": {
                      "type": "number"
                    },
                    "price": {
                      "type": "number"
                    },
                    "cost": {
                      "type": "number"
                    }
                  }
                }
              },
              "extras": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "label",
                    "amount"
                  ],
                  "properties": {
                    "label": {
                      "type": "string"
                    },
                    "amount": {
                      "type": "number"
                    }
                  }
                }
              },
              "totalKm": {
                "type": "number"
              },
              "totalEnergy": {
                "type": "number"
              },
              "energyCost": {
                "type": "number"
              },
              "extrasCost": {
                "type": "number"
              },
              "total": {
                "type": "number"
              },
              "costPer100Km": {
                "type": "number"
              },
              "perPerson": {
                "type": "array",
                "items": {
                  "type": "object",
                  "additionalProperties": false,
                  "required": [
                    "name",
                    "pays"
                  ],
                  "properties": {
                    "name": {
                      "type": "string"
                    },
                    "pays": {
                      "type": "number"
                    }
                  }
                }
              },
              "cheapestLeg": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "label",
                  "country",
                  "price",
                  "dearestCountry",
                  "dearestPrice"
                ],
                "properties": {
                  "label": {
                    "type": "string"
                  },
                  "country": {
                    "type": "string"
                  },
                  "price": {
                    "type": "number"
                  },
                  "dearestCountry": {
                    "type": "string"
                  },
                  "dearestPrice": {
                    "type": "number"
                  }
                }
              },
              "estimate": {
                "type": [
                  "object",
                  "null"
                ],
                "additionalProperties": false,
                "required": [
                  "straightKm",
                  "roadKm",
                  "circuity"
                ],
                "properties": {
                  "straightKm": {
                    "type": "number"
                  },
                  "roadKm": {
                    "type": "number"
                  },
                  "circuity": {
                    "type": "number"
                  }
                }
              }
            }
          },
          "units": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            }
          },
          "assumptions": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "sources": {
            "type": "array",
            "items": {
              "type": "object",
              "additionalProperties": false,
              "required": [
                "title"
              ],
              "properties": {
                "title": {
                  "type": "string"
                },
                "url": {
                  "type": "string"
                },
                "publisher": {
                  "type": "string"
                },
                "retrievedAt": {
                  "type": "string"
                },
                "note": {
                  "type": "string"
                }
              }
            }
          },
          "warnings": {
            "type": "array",
            "items": {
              "type": "string"
            }
          },
          "presentation": {
            "type": "array",
            "items": {
              "type": "object"
            },
            "description": "Display blocks used by the human page (same data)."
          },
          "links": {
            "type": "object",
            "additionalProperties": false,
            "required": [
              "human",
              "api",
              "openapi",
              "methodology"
            ],
            "properties": {
              "human": {
                "type": "string",
                "format": "uri"
              },
              "api": {
                "type": "string",
                "format": "uri"
              },
              "openapi": {
                "type": "string",
                "format": "uri"
              },
              "methodology": {
                "type": "string",
                "format": "uri"
              }
            }
          }
        }
      }
    }
  }
}