{
  "openapi": "3.1.0",
  "info": {
    "title": "combustivel.com.pt public API",
    "version": "1.0.0",
    "summary": "Fuel prices, electric charging and trip costs in Portugal. Public, read-only, no key.",
    "description": "Public, read-only data of combustivel.com.pt, the fuel price reference for Portugal: today's price of every fuel at every station (DGEG), the stations nearest to a point, electric charging sites with their hourly status and ad hoc prices (MOBI.E), trip planning with fuel or charging stops and tolls, and the freshness of the data. Written for people and for programs and AI agents. A human version is at https://combustivel.com.pt/desenvolvedores/; the pages of the site also exist as Markdown (https://combustivel.com.pt/llms.txt).\n\n## Data sources and what you must do with them\n\n* **Fuel prices**: DGEG (Direcao-Geral de Energia e Geologia), public service \"Precos dos Combustiveis Online\" (https://precoscombustiveis.dgeg.gov.pt/), prices that stations report under Decreto-Lei 243/2008. Say \"Fonte: DGEG\" next to any price you republish, with the report time the response gives (`updatedAt`, `latest`). The pump price is what counts: a station can change its price before it reports it, and card discounts are not included. The medians, minimums and rankings in these responses are computed by combustivel.com.pt from those reports; they are not official statistics.\n* **Electric charging**: MOBI.E through the NAP (IMT), the public charging network feed (\"sem licenca, sem contrato, livre acesso\"). Say \"Fonte: MOBI.E / NAP Portugal (IMT)\" (the responses carry it as `attribution` or `source`). Status is read about once an hour, so write \"estado lido as HH:MM\", never \"tempo real\". Prices are the ad hoc prices MOBI.E publishes, VAT included, not a quote.\n* **Routes, trips and addresses**: openrouteservice.org (HeiGIT) and, when its quota is spent, Photon (komoot); map data (c) OpenStreetMap contributors (ODbL). Show `dados.atribuicao` of every trip answer and `atribuicao` of every address answer. Toll estimates (class 1 cars) come from the IMT 2026 tariff table and OpenStreetMap toll sections and are marked as estimates.\n* **Our own work** (the combination, the medians, the optimiser): free to use. Please name combustivel.com.pt as the source and keep the timestamps that come with the numbers. No exclusivity is granted or claimed.\n\n## Access and fair use\n\nThere is no authentication and no API key: every endpoint is public. Responses of the `GET` endpoints are cached by the CDN (the `Cache-Control` header of each response says for how long); please cache on your side too and do not poll faster than the data changes (prices change in the hours after each station reports, status once an hour). There is no per-client quota except where an operation says so (the trip planner limits routes it has not seen before to 20 per IP address per hour and 170 per day for everybody; a route already in the cache is never refused; the address search limits searches it has not seen before to 30 per IP address per hour and 400 per day for everybody). Heavy or automated use: please write first (info@combustivel.com.pt). Abusive traffic may be blocked at the edge.\n\n## Errors\n\nEvery error of the API, on every endpoint and for unknown paths under /api/, is JSON: `{ \"error\": { \"code\": \"...\", \"message\": \"...\", \"hint\": \"...\" } }`. `code` is stable and listed in the `ApiError` schema; `message` (what happened) and `hint` (what to do next) are European Portuguese. The HTTP status carries the class of the error (400 request, 404 unknown, 405 method, 413 size, 422 outside Portugal, 429 rate limit, 502 and 503 data sources).\n\n## Conventions\n\nPrices in `/api/perto/` and `/api/viagem/rota/` are euros per litre as decimals; the map payloads use integers in **thousandths of a euro** (2239 = 2,239 EUR per litre) to stay small. Times written \"YYYY-MM-DD HH:MM\" are Portugal mainland local time (Europe/Lisbon); ISO instants end in Z. Coordinates are WGS84 degrees. Positions you send are rounded to two decimals (about 1 km) on arrival, used for the calculation only, and never stored or logged. Every path has a trailing slash; the same path without it redirects.",
    "termsOfService": "https://combustivel.com.pt/desenvolvedores/#licenca",
    "contact": {
      "name": "Nortex Labs",
      "url": "https://combustivel.com.pt/contacto/",
      "email": "info@combustivel.com.pt"
    },
    "license": {
      "name": "Free to use with attribution to combustivel.com.pt and the data sources (see description)",
      "url": "https://combustivel.com.pt/desenvolvedores/#licenca"
    }
  },
  "servers": [
    {
      "url": "https://combustivel.com.pt",
      "description": "Production"
    }
  ],
  "security": [],
  "tags": [
    {
      "name": "Fuel prices",
      "description": "Prices at every station in mainland Portugal, from DGEG."
    },
    {
      "name": "Electric charging",
      "description": "The MOBI.E public charging network: sites, hourly status, ad hoc prices."
    },
    {
      "name": "Trips",
      "description": "Fuel or charging stops and costs between two places."
    },
    {
      "name": "Addresses",
      "description": "An address typed in free text, turned into places in Portugal."
    },
    {
      "name": "Status",
      "description": "How fresh the data is."
    }
  ],
  "paths": {
    "/api/mapa/": {
      "get": {
        "operationId": "listFuelPriceMaps",
        "summary": "List the fuels that have a price map",
        "description": "Index of the national price data: one entry per fuel with the path of its full list (`getFuelPrices`). Use it to discover the fuel slugs. Cached for a day.",
        "tags": [
          "Fuel prices"
        ],
        "responses": {
          "200": {
            "description": "The fuels.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FuelIndex"
                },
                "example": {
                  "fuels": [
                    {
                      "slug": "gasoleo",
                      "label": "Gasóleo",
                      "url": "/api/mapa/gasoleo/"
                    },
                    {
                      "slug": "gasolina-95",
                      "label": "Gasolina 95",
                      "url": "/api/mapa/gasolina-95/"
                    }
                  ]
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "How long a cache may keep the answer.",
                "schema": {
                  "type": "string",
                  "example": "public, s-maxage=86400"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          }
        }
      }
    },
    "/api/mapa/{fuel}/": {
      "get": {
        "operationId": "getFuelPrices",
        "summary": "Get the price of one fuel at every station in mainland Portugal",
        "description": "Every mainland station with a price for the fuel, from DGEG's reports, with the national median, minimum and maximum, price bands, the 18 districts and the brand names. Use it for today's price of a fuel at a station, a concelho or a district: filter `stations` by the concelho (index 6) or read the district summary, and always show the report time (index 7 of a station, `latest` for the file). Prices are integers in thousandths of a euro. About 280 kB (50 kB gzipped); the answer is cached for 30 minutes, so do not request it more than once every few minutes. For the 15 stations around one point use `findNearestStations` instead.",
        "tags": [
          "Fuel prices"
        ],
        "parameters": [
          {
            "name": "fuel",
            "in": "path",
            "required": true,
            "description": "Fuel slug, from `listFuelPriceMaps`.",
            "schema": {
              "type": "string",
              "enum": [
                "gasoleo",
                "gasolina-95",
                "gasoleo-especial",
                "gasolina-98",
                "gpl"
              ]
            },
            "example": "gasoleo"
          }
        ],
        "responses": {
          "200": {
            "description": "The fuel's map payload.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FuelMap"
                },
                "example": {
                  "fuel": "gasoleo",
                  "label": "Gasóleo",
                  "latest": "2026-10-06 06:30",
                  "median": 2239,
                  "min": 1939,
                  "max": 2449,
                  "count": 2910,
                  "bands": [
                    2169,
                    2219,
                    2249,
                    2269
                  ],
                  "brands": {
                    "intermarche": "INTERMARCHÉ",
                    "plenergy": "PLENERGY"
                  },
                  "stations": [
                    [
                      67360,
                      40.6182,
                      -6.8434,
                      1939,
                      "intermarche",
                      "Intermarche Vilar Formoso",
                      "Almeida",
                      "2026-10-01 08:30"
                    ]
                  ],
                  "districts": [
                    {
                      "name": "Aveiro",
                      "slug": "aveiro",
                      "lat": 40.6405,
                      "lng": -8.6538,
                      "median": 2224,
                      "min": 1999,
                      "max": 2329,
                      "count": 236
                    }
                  ]
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "How long a cache may keep the answer.",
                "schema": {
                  "type": "string",
                  "example": "public, s-maxage=1800, stale-while-revalidate=3600"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          }
        }
      }
    },
    "/api/perto/": {
      "post": {
        "operationId": "findNearestStations",
        "summary": "Find the fuel stations nearest to a position",
        "description": "The 15 stations nearest to a point in mainland Portugal (within 40 km), nearest first, with the price of the fuel asked, the time the station reported it and the trend against its previous price. Sort `stations` by `price` for the cheapest nearby. The position travels in the body (never in a URL), is rounded to two decimals, used for the distance only and never stored or logged. The answer is never cached. GET is not accepted. The combustivel.com.pt page itself no longer calls this route: it does the same calculation on the device from the map data, so the position never leaves it.",
        "tags": [
          "Fuel prices"
        ],
        "requestBody": {
          "required": true,
          "description": "The position and the fuel. At most 1 KB.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NearbyStationsRequest"
              },
              "example": {
                "lat": 38.72,
                "lng": -9.14,
                "fuel": "gasoleo"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Stations, nearest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearbyStationsResponse"
                },
                "example": {
                  "fuel": "Gasóleo",
                  "stations": [
                    {
                      "id": 93454,
                      "name": "OZ ENERGIA - GRAÇA",
                      "brand": "OZ Energia",
                      "municipio": "Lisboa",
                      "address": "Rua da Graça 2-D",
                      "price": 2.184,
                      "updatedAt": "2026-10-04 23:50",
                      "km": 0.9,
                      "trend": null
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/OutsideCoverage"
          },
          "502": {
            "$ref": "#/components/responses/BadGateway"
          }
        }
      }
    },
    "/api/carregamento/mapa/": {
      "get": {
        "operationId": "getChargingMap",
        "summary": "Get the electric charging sites of Portugal, with status and price",
        "description": "All charging sites of the MOBI.E public network (mainland, Madeira and Azores, about 8,400 sites and 18,000 points) in a compact form, with the number of points, how many were free at the last hourly status read, the highest power, the connector bitmask and the cheapest published kWh price. Use `statusAt` for the time of the status and write 'estado lido às HH:MM': it is read hourly, not live. Filter with `tipo`, `kw` and `livre`. About 370 kB (90 kB gzipped) without a filter; cached for 5 minutes. For the sites around a point use `findNearbyChargingSites`; for the name of one site use `getChargingSiteName`.",
        "tags": [
          "Electric charging"
        ],
        "parameters": [
          {
            "name": "tipo",
            "in": "query",
            "required": false,
            "description": "Only sites with this connector: t2 (Type 2), ccs, chademo, tomada (socket).",
            "schema": {
              "type": "string",
              "enum": [
                "t2",
                "ccs",
                "chademo",
                "tomada"
              ]
            },
            "example": "ccs"
          },
          {
            "name": "kw",
            "in": "query",
            "required": false,
            "description": "Only sites with at least this power in kW: one of the steps 0 (any), 22, 50 ('rápido') or 150 ('ultrarrápido'). Any other value, and any parameter not listed here, is a 400 (`invalid_filter`) that caches are told to keep.",
            "schema": {
              "type": "integer",
              "enum": [
                0,
                22,
                50,
                150
              ],
              "default": 0
            },
            "example": 150
          },
          {
            "name": "livre",
            "in": "query",
            "required": false,
            "description": "1: only sites with a free point at the last status read.",
            "schema": {
              "type": "string",
              "enum": [
                "0",
                "1"
              ],
              "default": "0"
            },
            "example": "1"
          }
        ],
        "responses": {
          "200": {
            "description": "The matching sites.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChargingMap"
                },
                "example": {
                  "v": 1,
                  "attribution": "Fonte: MOBI.E / NAP Portugal (IMT)",
                  "statusAt": "2026-10-06T05:05:23.134Z",
                  "staticAt": "2026-10-06T04:42:51.511Z",
                  "filter": {
                    "tipo": "ccs",
                    "kw": 150,
                    "livre": true
                  },
                  "count": {
                    "sites": 757,
                    "points": 1761,
                    "available": 1761
                  },
                  "columns": [
                    "id",
                    "lat",
                    "lng",
                    "operator",
                    "points",
                    "available",
                    "outOfOrder",
                    "maxKw",
                    "types",
                    "kwhMili"
                  ],
                  "operators": [
                    [
                      "ACCI",
                      "Acciona Recarga Portugal"
                    ]
                  ],
                  "sites": [
                    [
                      62,
                      38.58599,
                      -8.69212,
                      66,
                      1,
                      1,
                      0,
                      180,
                      2,
                      null
                    ]
                  ]
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "How long a cache may keep the answer.",
                "schema": {
                  "type": "string",
                  "example": "public, max-age=60, s-maxage=300, stale-while-revalidate=3600"
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/carregamento/perto/": {
      "post": {
        "operationId": "findNearbyChargingSites",
        "summary": "Find the electric charging sites nearest to a position",
        "description": "The 20 charging sites nearest to a point in Portugal within 25 km, nearest first, with how many points are free at the last hourly status read, the power, the connectors and the published ad hoc price, as ready-made Portuguese strings and counts. The position travels in the body, is rounded to two decimals, used for the distance only and never stored or logged. Never cached. Show `source`, which carries the hour of the status. The combustivel.com.pt page itself no longer calls this route: it does the same calculation on the device from the map data.",
        "tags": [
          "Electric charging"
        ],
        "requestBody": {
          "required": true,
          "description": "The position and optional filters. At most 1 KB.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/NearbyChargersRequest"
              },
              "example": {
                "lat": 38.72,
                "lng": -9.14,
                "tipo": "ccs",
                "kw": 50,
                "livre": true
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "Sites, nearest first.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/NearbyChargersResponse"
                },
                "example": {
                  "radiusKm": 25,
                  "statusAt": "2026-10-06T05:05:23.134Z",
                  "source": "Fonte: MOBI.E através do NAP (IMT), estado às 06:05",
                  "sites": [
                    {
                      "id": 4090,
                      "href": "/carregamento/posto/4090/",
                      "label": "Atlante - Pingo Doce Lisboa - Campo Santana",
                      "brand": "Atlante",
                      "place": "Lisboa",
                      "km": 0.22,
                      "points": 1,
                      "available": 1,
                      "outOfOrder": 0,
                      "tone": "livre",
                      "availability": "1 de 1 ponto livre",
                      "maxKw": 60,
                      "kw": "60 kW",
                      "tier": "rapido",
                      "connectors": [
                        {
                          "kind": "ccs",
                          "name": "CCS"
                        }
                      ],
                      "price": "0,49 €/kWh",
                      "priced": true
                    }
                  ]
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "422": {
            "$ref": "#/components/responses/OutsideCoverage"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/carregamento/local/{id}/": {
      "get": {
        "operationId": "getChargingSiteName",
        "summary": "Get the name and place of one charging site",
        "description": "The label and place of a charging site, by the id used in `getChargingMap` (the compact map carries no names) and in /carregamento/posto/{id}/. Cached for an hour.",
        "tags": [
          "Electric charging"
        ],
        "parameters": [
          {
            "name": "id",
            "in": "path",
            "required": true,
            "description": "Site id, a positive integer of up to 8 digits.",
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10000000
            },
            "example": 4090
          }
        ],
        "responses": {
          "200": {
            "description": "The site.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/ChargingSiteName"
                },
                "example": {
                  "label": "Atlante - Pingo Doce Lisboa - Campo Santana",
                  "place": "Lisboa"
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "How long a cache may keep the answer.",
                "schema": {
                  "type": "string",
                  "example": "public, max-age=600, s-maxage=3600, stale-while-revalidate=86400"
                }
              }
            }
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/viagem/rota/": {
      "post": {
        "operationId": "planTrip",
        "summary": "Plan a trip between two concelhos: fuel stops, trip cost, tolls, or charging stops",
        "description": "Fuel trip (default): given two places in mainland Portugal and a car, returns the route, the cheapest places to refuel on the way with litres and prices from DGEG, the fuel cost, the saving against the corridor median and the toll estimate (class 1). Electric trip (`modo: \"eletrico\"`): the fastest charging stops on MOBI.E rapid chargers, the time, the energy and, when every stop has a published price, the cost. The two modes share the route cache, the provider and the limits. Positions are rounded to two decimals; nothing about the trip is stored except the route between two places, kept 30 days. Never cached by the CDN. Rate limit: routes that are not yet in the cache are limited to 20 per IP address per hour and 170 per day for everybody (429 with Retry-After); a route already in the cache, for example between two concelhos someone already asked, is never refused. Show `dados.atribuicao`. Body at most 2 KB.",
        "tags": [
          "Trips"
        ],
        "requestBody": {
          "required": true,
          "description": "A fuel trip (no `modo`, or `combustivel`) or an electric trip (`modo: eletrico`).",
          "content": {
            "application/json": {
              "schema": {
                "oneOf": [
                  {
                    "$ref": "#/components/schemas/FuelTripRequest"
                  },
                  {
                    "$ref": "#/components/schemas/EvTripRequest"
                  }
                ]
              },
              "examples": {
                "combustivel": {
                  "summary": "Lisboa to Porto in a diesel car",
                  "value": {
                    "de": {
                      "concelho": "lisboa"
                    },
                    "para": {
                      "concelho": "porto"
                    },
                    "combustivel": "gasoleo",
                    "carro": {
                      "deposito": 50,
                      "consumo": 6,
                      "nivel": 20
                    },
                    "opcoes": {
                      "reserva": 10,
                      "chegada": 20,
                      "desvioMaxKm": 5,
                      "custoParagem": 1
                    }
                  }
                },
                "eletrico": {
                  "summary": "Lisboa to Porto in an electric car",
                  "value": {
                    "modo": "eletrico",
                    "de": {
                      "concelho": "lisboa"
                    },
                    "para": {
                      "concelho": "porto"
                    },
                    "ev": {
                      "bateriaKwh": 60,
                      "consumoKwh100": 17,
                      "cargaInicialPct": 80,
                      "potenciaMaxKw": 150,
                      "ficha": "ccs"
                    }
                  }
                }
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The plan. The shape depends on the mode of the request.",
            "content": {
              "application/json": {
                "schema": {
                  "anyOf": [
                    {
                      "$ref": "#/components/schemas/FuelTripResponse"
                    },
                    {
                      "$ref": "#/components/schemas/EvTripResponse"
                    }
                  ]
                },
                "example": {
                  "rota": {
                    "distanciaKm": 316.1,
                    "duracaoMin": 190,
                    "geometria": [
                      [
                        -9.13623,
                        38.70686
                      ],
                      [
                        -8.61,
                        41.15
                      ]
                    ],
                    "fornecedor": "openrouteservice",
                    "emCache": true
                  },
                  "plano": {
                    "possivel": true,
                    "custoTotal": 38.41,
                    "litros": 19.2,
                    "paragens": [
                      {
                        "postoId": 94864,
                        "nome": "PETROPRIX Castanheira - Vila Franca de Xira",
                        "marca": "PETROPRIX",
                        "concelho": "Vila Franca de Xira",
                        "lat": 39.00038,
                        "lng": -8.970995,
                        "kmNaRota": 38.5,
                        "desvioKm": 0.8,
                        "foraDaRotaKm": 0.3,
                        "preco": 2.089,
                        "precoAtualizadoEm": "2026-09-28T15:10:00.000Z",
                        "litros": 3.1,
                        "nivelChegadaPct": 15,
                        "nivelSaidaPct": 21
                      },
                      {
                        "postoId": 94703,
                        "nome": "PLENERGY - OURÉM I",
                        "marca": "PLENERGY",
                        "concelho": "Ourém",
                        "lat": 39.639294,
                        "lng": -8.68459,
                        "kmNaRota": 126.3,
                        "desvioKm": 3.2,
                        "foraDaRotaKm": 1.2,
                        "preco": 1.979,
                        "precoAtualizadoEm": "2026-10-05T22:00:00.000Z",
                        "litros": 16.2,
                        "nivelChegadaPct": 11,
                        "nivelSaidaPct": 43
                      }
                    ],
                    "precoMedianoCorredor": 2.246,
                    "poupancaVsMediana": 4.8,
                    "postosConsiderados": 154,
                    "desvioTotalKm": 4,
                    "nivelDestinoPct": 20
                  },
                  "portagens": {
                    "classe": 1,
                    "total": 25.05,
                    "trocos": [
                      {
                        "via": "A1",
                        "de": "Alverca (A1/A9)",
                        "ate": "Carvalhos",
                        "preco": 25.05,
                        "lancos": 24
                      }
                    ],
                    "semPreco": [],
                    "fonte": {
                      "nome": "IMT, Taxas de Portagem de 2026",
                      "url": "https://www.imt-ip.pt/rodoviario/infraestruturas-rodoviarias/rede-rodoviaria/taxas-de-portagem/",
                      "ano": 2026,
                      "paginaAtualizadaEm": "2026-01-20",
                      "verificadoEm": "2026-10-04"
                    }
                  },
                  "dados": {
                    "dgegAte": "2026-10-06T05:30:00.000Z",
                    "atribuicao": "Rotas: openrouteservice.org (HeiGIT), dados © colaboradores do OpenStreetMap"
                  }
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "404": {
            "$ref": "#/components/responses/NotFound"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/geo/procurar/": {
      "post": {
        "operationId": "findAddress",
        "summary": "Turn an address typed in free text into places in Portugal",
        "description": "Geocoding for Portugal: a street, a street and a town, a postcode or a place name in, up to 5 candidates out, each with a label, WGS84 coordinates, its kind and the concelho and distrito when known. Use the coordinates as `de` or `para` of `planTrip`, or as `lat` and `lng` of the nearby searches. Results come from openrouteservice (and from Photon when its quota is spent), both on OpenStreetMap data; street level is what you should expect, house numbers are only found where OpenStreetMap has them. It is a POST because an address can be a person's own street and a URL ends up in logs: the text is not in any URL, is kept in our cache for 30 days without the IP so that the same address never asks the provider twice, and is never logged. Rate limit: searches that are not yet in the cache are limited to 30 per IP address per hour and 400 per day for everybody (429 with Retry-After); a search already in the cache is never refused. Never cached by the CDN. Show `atribuicao`. Body at most 1 KB.",
        "tags": [
          "Addresses"
        ],
        "requestBody": {
          "required": true,
          "description": "The address to look for.",
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/GeoSearchRequest"
              },
              "example": {
                "q": "Rua Augusta, Lisboa",
                "ambito": "continente"
              }
            }
          }
        },
        "responses": {
          "200": {
            "description": "The places that match, possibly none.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/GeoSearchResponse"
                },
                "example": {
                  "candidatos": [
                    {
                      "label": "Rua Augusta, Lisboa",
                      "lat": 38.71069,
                      "lng": -9.1377,
                      "tipo": "rua",
                      "concelho": "Lisboa",
                      "distrito": "Lisboa",
                      "regiao": "continente"
                    }
                  ],
                  "atribuicao": "Moradas: openrouteservice.org (HeiGIT), dados © colaboradores do OpenStreetMap",
                  "emCache": false
                }
              }
            }
          },
          "400": {
            "$ref": "#/components/responses/BadRequest"
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "413": {
            "$ref": "#/components/responses/PayloadTooLarge"
          },
          "429": {
            "$ref": "#/components/responses/RateLimited"
          },
          "503": {
            "$ref": "#/components/responses/Unavailable"
          }
        }
      }
    },
    "/api/saude/": {
      "get": {
        "operationId": "getServiceHealth",
        "summary": "Check how fresh the data is",
        "description": "What the last price reading did, how many minutes ago the last good one finished, the reading gaps of the last 24 hours and the state of the charging jobs. Use it to decide whether to trust or to show a 'data may be late' note. Cached for 10 minutes.",
        "tags": [
          "Status"
        ],
        "responses": {
          "200": {
            "description": "The state of the data.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/Health"
                },
                "example": {
                  "db": true,
                  "db_reads": "on",
                  "last_run": {
                    "id": 154,
                    "status": "ok",
                    "finished_at": "2026-10-06T05:30:51.221Z",
                    "rows_in": 14238,
                    "events": 38,
                    "latest_reported_local": "2026-10-06 06:30:00"
                  },
                  "age_minutes": 29,
                  "gaps_24h": 1,
                  "banner": false,
                  "ev": {
                    "static": {
                      "status": "ok",
                      "finished_at": "2026-10-06T04:42:51.511Z",
                      "rows_in": 8391,
                      "points": 18266,
                      "events": 131,
                      "age_minutes": 77
                    },
                    "status": {
                      "status": "ok",
                      "finished_at": "2026-10-06T05:05:23.134Z",
                      "rows_in": 18266,
                      "points": 18266,
                      "events": 291,
                      "age_minutes": 54
                    },
                    "stale": false
                  }
                }
              }
            },
            "headers": {
              "Cache-Control": {
                "description": "How long a cache may keep the answer.",
                "schema": {
                  "type": "string",
                  "example": "public, max-age=60, s-maxage=600, stale-while-revalidate=300"
                }
              }
            }
          },
          "405": {
            "$ref": "#/components/responses/MethodNotAllowed"
          },
          "503": {
            "description": "The data store did not answer. The body is `{ db: false, error: {...} }`.",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/HealthUnavailable"
                },
                "example": {
                  "db": false,
                  "error": {
                    "code": "data_unavailable",
                    "message": "A base de dados não respondeu.",
                    "hint": "Tente de novo dentro de minutos; os dados são atualizados de hora a hora."
                  }
                }
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "ApiErrorDetail": {
        "type": "object",
        "properties": {
          "code": {
            "type": "string",
            "enum": [
              "invalid_request",
              "invalid_json",
              "invalid_filter",
              "unknown_fuel",
              "unknown_place",
              "missing_coordinates",
              "out_of_coverage",
              "payload_too_large",
              "method_not_allowed",
              "not_found",
              "rate_limited",
              "data_unavailable",
              "upstream_unavailable"
            ],
            "description": "Stable, machine readable. Branch on this, not on the message."
          },
          "message": {
            "type": "string",
            "description": "What happened, in European Portuguese."
          },
          "hint": {
            "type": "string",
            "description": "What to do next, in European Portuguese."
          }
        },
        "required": [
          "code",
          "message",
          "hint"
        ]
      },
      "ApiError": {
        "type": "object",
        "description": "The error body of every endpoint.",
        "properties": {
          "error": {
            "$ref": "#/components/schemas/ApiErrorDetail"
          }
        },
        "required": [
          "error"
        ],
        "example": {
          "error": {
            "code": "unknown_fuel",
            "message": "Combustível desconhecido.",
            "hint": "Use um dos identificadores de combustível documentados em https://combustivel.com.pt/openapi.json (por exemplo gasoleo ou gasolina-95)."
          }
        }
      },
      "FuelIndex": {
        "type": "object",
        "properties": {
          "fuels": {
            "type": "array",
            "description": "One entry per fuel with a price map.",
            "items": {
              "type": "object",
              "properties": {
                "slug": {
                  "type": "string",
                  "enum": [
                    "gasoleo",
                    "gasolina-95",
                    "gasoleo-especial",
                    "gasolina-98",
                    "gpl"
                  ]
                },
                "label": {
                  "type": "string",
                  "description": "Display name."
                },
                "url": {
                  "type": "string",
                  "description": "Path of the price list of this fuel, with the trailing slash."
                }
              },
              "required": [
                "slug",
                "label",
                "url"
              ]
            }
          }
        },
        "required": [
          "fuels"
        ]
      },
      "FuelMapStation": {
        "type": "array",
        "description": "One station as a fixed tuple: [id, lat, lng, price in thousandths of a euro, brand slug, short name, concelho, reported 'YYYY-MM-DD HH:MM' Lisbon time]. The id is the one of /posto/<id>/.",
        "prefixItems": [
          {
            "type": "integer",
            "description": "Station id (DGEG)."
          },
          {
            "type": "number",
            "description": "Latitude, 4 decimals."
          },
          {
            "type": "number",
            "description": "Longitude, 4 decimals."
          },
          {
            "type": "integer",
            "description": "Price in thousandths of a euro per litre (2239 = 2,239 EUR)."
          },
          {
            "type": "string",
            "description": "Brand slug, a key of `brands`."
          },
          {
            "type": "string",
            "description": "Station name, tidied."
          },
          {
            "type": "string",
            "description": "Concelho."
          },
          {
            "type": "string",
            "description": "When the station reported this price to DGEG, 'YYYY-MM-DD HH:MM' (Lisbon time)."
          }
        ],
        "minItems": 8,
        "maxItems": 8
      },
      "FuelMap": {
        "type": "object",
        "description": "All mainland stations with a price for one fuel, in a compact form. About 280 kB (50 kB gzipped).",
        "properties": {
          "fuel": {
            "type": "string",
            "enum": [
              "gasoleo",
              "gasolina-95",
              "gasoleo-especial",
              "gasolina-98",
              "gpl"
            ],
            "description": "Fuel slug."
          },
          "label": {
            "type": "string",
            "description": "Display name of the fuel."
          },
          "latest": {
            "type": "string",
            "description": "Newest DGEG report in the data, 'YYYY-MM-DD HH:MM' (Lisbon time)."
          },
          "median": {
            "type": "integer",
            "description": "Median price of all stations with a price, thousandths of a euro per litre."
          },
          "min": {
            "type": "integer",
            "description": "Lowest price on the map, thousandths of a euro."
          },
          "max": {
            "type": "integer",
            "description": "Highest price on the map, thousandths of a euro."
          },
          "count": {
            "type": "integer",
            "description": "Number of stations on the map (mainland, with coordinates)."
          },
          "bands": {
            "type": "array",
            "items": {
              "type": "integer"
            },
            "description": "Ascending thresholds (thousandths of a euro) that split the stations into equal-sized price bands."
          },
          "brands": {
            "type": "object",
            "additionalProperties": {
              "type": "string"
            },
            "description": "Brand slug to display name, only for brands present."
          },
          "stations": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/FuelMapStation"
            },
            "description": "Every mainland station with a price for this fuel (about 3,000), in no particular order."
          },
          "districts": {
            "type": "array",
            "description": "The 18 districts with their price summary.",
            "items": {
              "type": "object",
              "properties": {
                "name": {
                  "type": "string",
                  "description": "District name."
                },
                "slug": {
                  "type": "string",
                  "description": "District slug (/distrito/<slug>/)."
                },
                "lat": {
                  "type": "number",
                  "description": "District capital latitude."
                },
                "lng": {
                  "type": "number",
                  "description": "District capital longitude."
                },
                "median": {
                  "type": "integer",
                  "description": "Median price, thousandths of a euro."
                },
                "min": {
                  "type": "integer",
                  "description": "Lowest price, thousandths of a euro."
                },
                "max": {
                  "type": "integer",
                  "description": "Highest price, thousandths of a euro."
                },
                "count": {
                  "type": "integer",
                  "description": "Stations with a price."
                }
              },
              "required": [
                "name",
                "slug",
                "lat",
                "lng",
                "median",
                "min",
                "max",
                "count"
              ]
            }
          }
        },
        "required": [
          "fuel",
          "label",
          "latest",
          "median",
          "min",
          "max",
          "count",
          "bands",
          "brands",
          "stations",
          "districts"
        ]
      },
      "NearbyStationsRequest": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number",
            "description": "Latitude of the position, inside mainland Portugal.",
            "minimum": 36.8,
            "maximum": 42.3,
            "example": 38.72
          },
          "lng": {
            "type": "number",
            "description": "Longitude of the position, inside mainland Portugal.",
            "minimum": -9.7,
            "maximum": -6,
            "example": -9.14
          },
          "fuel": {
            "type": "string",
            "enum": [
              "gasoleo",
              "gasolina-95",
              "gasoleo-especial",
              "gasolina-98",
              "gasolina-especial-95",
              "gasolina-especial-98",
              "gpl",
              "gasoleo-colorido"
            ],
            "description": "Fuel identifier: the slug of the fuel page (/combustivel/<slug>/).",
            "default": "gasoleo"
          }
        },
        "required": [
          "lat",
          "lng"
        ]
      },
      "NearbyStation": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Station id (DGEG), the one of /posto/<id>/."
          },
          "name": {
            "type": "string",
            "description": "Station name as DGEG gives it."
          },
          "brand": {
            "type": "string",
            "description": "Brand."
          },
          "municipio": {
            "type": "string",
            "description": "Concelho."
          },
          "address": {
            "type": "string",
            "description": "Street address as reported."
          },
          "price": {
            "type": "number",
            "description": "Price in euros per litre, for the fuel asked."
          },
          "updatedAt": {
            "type": "string",
            "description": "When the station reported this price to DGEG, 'YYYY-MM-DD HH:MM' (Lisbon time)."
          },
          "km": {
            "type": "number",
            "description": "Straight-line distance from the position, kilometres, one decimal."
          },
          "trend": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "up",
                  "down",
                  "same"
                ],
                "description": "Against the price before the last change; null when unknown."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "id",
          "name",
          "brand",
          "municipio",
          "address",
          "price",
          "updatedAt",
          "km",
          "trend"
        ]
      },
      "NearbyStationsResponse": {
        "type": "object",
        "properties": {
          "fuel": {
            "type": "string",
            "description": "Short name of the fuel, for example 'Gasóleo'."
          },
          "stations": {
            "type": "array",
            "maxItems": 15,
            "items": {
              "$ref": "#/components/schemas/NearbyStation"
            },
            "description": "Up to 15 stations within 40 km, nearest first. Stations whose price is flagged as suspect are left out. Sort by `price` yourself for the cheapest."
          }
        },
        "required": [
          "fuel",
          "stations"
        ]
      },
      "ChargingMap": {
        "type": "object",
        "description": "The charging sites of the MOBI.E network that match a filter, compact. About 370 kB (90 kB gzipped) without a filter.",
        "properties": {
          "v": {
            "type": "integer",
            "description": "Payload version, 1.",
            "const": 1
          },
          "attribution": {
            "type": "string",
            "description": "Source line to show wherever the data is shown."
          },
          "statusAt": {
            "oneOf": [
              {
                "type": "string",
                "description": "When the status was last read, ISO instant.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "staticAt": {
            "oneOf": [
              {
                "type": "string",
                "description": "When the list of sites was last read, ISO instant.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "filter": {
            "type": "object",
            "description": "The filter that was applied.",
            "properties": {
              "tipo": {
                "oneOf": [
                  {
                    "type": "string",
                    "enum": [
                      "t2",
                      "ccs",
                      "chademo",
                      "tomada"
                    ]
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "kw": {
                "type": "integer",
                "description": "Minimum power, kW."
              },
              "livre": {
                "type": "boolean"
              }
            },
            "required": [
              "tipo",
              "kw",
              "livre"
            ]
          },
          "count": {
            "type": "object",
            "description": "Totals over the sites and points that matched.",
            "properties": {
              "sites": {
                "type": "integer",
                "description": "Sites in `sites`."
              },
              "points": {
                "type": "integer",
                "description": "Matching charging points."
              },
              "available": {
                "type": "integer",
                "description": "Matching points free at the last status read."
              }
            },
            "required": [
              "sites",
              "points",
              "available"
            ]
          },
          "columns": {
            "type": "array",
            "items": {
              "type": "string"
            },
            "description": "The names of the columns of each row of `sites`, in order: id, lat, lng, operator, points, available, outOfOrder, maxKw, types, kwhMili."
          },
          "operators": {
            "type": "array",
            "items": {
              "type": "array",
              "prefixItems": [
                {
                  "type": "string",
                  "description": "Operator code."
                },
                {
                  "type": "string",
                  "description": "Operator name."
                }
              ],
              "minItems": 2,
              "maxItems": 2
            },
            "description": "[code, name] pairs; a site's `operator` is an index into this list (-1 when unknown)."
          },
          "sites": {
            "type": "array",
            "description": "One row per site with at least one matching point: [id, lat, lng, operator index, points, available, outOfOrder, maxKw, types, kwhMili]. `types` is a bitmask of connectors: 1 Type 2, 2 CCS, 4 CHAdeMO, 8 domestic or industrial socket, 16 Type 1, 32 other. `kwhMili` is the cheapest published kWh price above zero among the matching points, in thousandths of a euro, VAT included, or null.",
            "items": {
              "type": "array",
              "prefixItems": [
                {
                  "type": "integer",
                  "description": "Site id, the one of /carregamento/posto/<id>/."
                },
                {
                  "type": "number",
                  "description": "Latitude."
                },
                {
                  "type": "number",
                  "description": "Longitude."
                },
                {
                  "type": "integer",
                  "description": "Operator index."
                },
                {
                  "type": "integer",
                  "description": "Points."
                },
                {
                  "type": "integer",
                  "description": "Free points."
                },
                {
                  "type": "integer",
                  "description": "Points out of order."
                },
                {
                  "oneOf": [
                    {
                      "type": "number",
                      "description": "Highest power, kW."
                    },
                    {
                      "type": "null"
                    }
                  ]
                },
                {
                  "type": "integer",
                  "description": "Connector bitmask."
                },
                {
                  "oneOf": [
                    {
                      "type": "integer",
                      "description": "Cheapest kWh price, thousandths of a euro."
                    },
                    {
                      "type": "null"
                    }
                  ]
                }
              ],
              "minItems": 10,
              "maxItems": 10
            }
          }
        },
        "required": [
          "v",
          "attribution",
          "statusAt",
          "staticAt",
          "filter",
          "count",
          "columns",
          "operators",
          "sites"
        ]
      },
      "ChargingConnector": {
        "type": "object",
        "properties": {
          "kind": {
            "type": "string",
            "enum": [
              "ccs",
              "t2",
              "chademo",
              "tomada",
              "t1",
              "outro"
            ],
            "description": "Connector kind."
          },
          "name": {
            "type": "string",
            "description": "Display name of the connector, for example 'CCS'."
          }
        },
        "required": [
          "kind",
          "name"
        ]
      },
      "ChargingSiteRow": {
        "type": "object",
        "properties": {
          "id": {
            "type": "integer",
            "description": "Site id, the one of /carregamento/posto/<id>/."
          },
          "href": {
            "type": "string",
            "description": "Path of the site page."
          },
          "label": {
            "type": "string",
            "description": "Name of the site: its name, or brand and address when the feed's name is a code."
          },
          "brand": {
            "oneOf": [
              {
                "type": "string",
                "description": "Public brand or operator."
              },
              {
                "type": "null"
              }
            ]
          },
          "place": {
            "oneOf": [
              {
                "type": "string",
                "description": "Concelho, or the locality when the feed has no area name."
              },
              {
                "type": "null"
              }
            ]
          },
          "km": {
            "oneOf": [
              {
                "type": "number",
                "description": "Straight-line kilometres from the position."
              },
              {
                "type": "null"
              }
            ]
          },
          "points": {
            "type": "integer",
            "description": "Charging points of the site that match the filter."
          },
          "available": {
            "type": "integer",
            "description": "Points free at the last hourly status read."
          },
          "outOfOrder": {
            "type": "integer",
            "description": "Points out of order at the last read."
          },
          "tone": {
            "type": "string",
            "enum": [
              "livre",
              "ocupado",
              "avariado",
              "outro",
              "semLivre"
            ],
            "description": "Status group: livre has a free point, avariado has every point out of order, semLivre has none free."
          },
          "availability": {
            "type": "string",
            "description": "Ready-made Portuguese line, for example '1 de 1 ponto livre'."
          },
          "maxKw": {
            "oneOf": [
              {
                "type": "number",
                "description": "Highest power of the site, kW."
              },
              {
                "type": "null"
              }
            ]
          },
          "kw": {
            "type": "string",
            "description": "'150 kW' or 'potência não publicada'."
          },
          "tier": {
            "oneOf": [
              {
                "type": "string",
                "enum": [
                  "ultra",
                  "rapido"
                ],
                "description": "ultra from 150 kW DC, rapido from 50 kW DC."
              },
              {
                "type": "null"
              }
            ]
          },
          "connectors": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/ChargingConnector"
            },
            "description": "The connectors of the site, CCS first."
          },
          "price": {
            "type": "string",
            "description": "Ready-made Portuguese price line, for example '0,49 €/kWh', 'desde 0,35 €/kWh' or 'sem preço publicado'. Ad hoc price published by MOBI.E, VAT included."
          },
          "priced": {
            "type": "boolean",
            "description": "True when the price is one we show (not suspect, above zero)."
          }
        },
        "required": [
          "id",
          "href",
          "label",
          "brand",
          "place",
          "km",
          "points",
          "available",
          "outOfOrder",
          "tone",
          "availability",
          "maxKw",
          "kw",
          "tier",
          "connectors",
          "price",
          "priced"
        ]
      },
      "NearbyChargersRequest": {
        "type": "object",
        "properties": {
          "lat": {
            "type": "number",
            "description": "Latitude, inside Portugal (mainland, Madeira or Azores).",
            "example": 38.72
          },
          "lng": {
            "type": "number",
            "description": "Longitude.",
            "example": -9.14
          },
          "tipo": {
            "type": "string",
            "enum": [
              "t2",
              "ccs",
              "chademo",
              "tomada"
            ],
            "description": "Only sites with this connector."
          },
          "kw": {
            "type": "integer",
            "enum": [
              0,
              22,
              50,
              150
            ],
            "description": "Only sites with at least this power in kW (50 is 'rápido', 150 'ultrarrápido'). Other values mean no filter."
          },
          "livre": {
            "type": "boolean",
            "description": "Only sites with a free point at the last status read."
          }
        },
        "required": [
          "lat",
          "lng"
        ]
      },
      "NearbyChargersResponse": {
        "type": "object",
        "properties": {
          "radiusKm": {
            "type": "integer",
            "description": "Search radius, 25."
          },
          "statusAt": {
            "oneOf": [
              {
                "type": "string",
                "description": "When the status was last read, ISO instant.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "source": {
            "type": "string",
            "description": "Source line with the status hour, for example 'Fonte: MOBI.E através do NAP (IMT), estado às 06:05'."
          },
          "sites": {
            "type": "array",
            "maxItems": 20,
            "items": {
              "$ref": "#/components/schemas/ChargingSiteRow"
            },
            "description": "Up to 20 sites within the radius, nearest first."
          }
        },
        "required": [
          "radiusKm",
          "statusAt",
          "source",
          "sites"
        ]
      },
      "ChargingSiteName": {
        "type": "object",
        "properties": {
          "label": {
            "type": "string",
            "description": "Name of the site."
          },
          "place": {
            "oneOf": [
              {
                "type": "string",
                "description": "Concelho, or locality."
              },
              {
                "type": "null"
              }
            ]
          }
        },
        "required": [
          "label",
          "place"
        ]
      },
      "GeoSearchRequest": {
        "type": "object",
        "description": "What to look for.",
        "properties": {
          "q": {
            "type": "string",
            "description": "The address as a person types it: a street, a street and a town, a postcode, a place name. 3 to 120 characters after trimming.",
            "minLength": 3,
            "maxLength": 120
          },
          "ambito": {
            "type": "string",
            "enum": [
              "continente",
              "portugal"
            ],
            "description": "Where the result must be: `continente` (default, the trip planner and the fuel stations) or `portugal` (the mainland, Madeira and the Azores, for charging sites)."
          }
        },
        "required": [
          "q"
        ]
      },
      "GeoCandidate": {
        "type": "object",
        "description": "One place that matches the search.",
        "properties": {
          "label": {
            "type": "string",
            "description": "The line to show, for example `Rua Augusta, Lisboa`."
          },
          "lat": {
            "type": "number",
            "description": "Latitude, 5 decimals.",
            "minimum": 32.3,
            "maximum": 42.3
          },
          "lng": {
            "type": "number",
            "description": "Longitude, 5 decimals.",
            "minimum": -31.5,
            "maximum": -6
          },
          "tipo": {
            "type": "string",
            "enum": [
              "morada",
              "rua",
              "local",
              "localidade"
            ],
            "description": "A numbered address, a street, a named place or a town."
          },
          "concelho": {
            "oneOf": [
              {
                "type": "string",
                "description": "The concelho when it could be matched against the 278 concelhos of the mainland."
              },
              {
                "type": "null"
              }
            ]
          },
          "distrito": {
            "oneOf": [
              {
                "type": "string",
                "description": "Its distrito, when known."
              },
              {
                "type": "null"
              }
            ]
          },
          "regiao": {
            "type": "string",
            "enum": [
              "continente",
              "madeira",
              "acores"
            ],
            "description": "Where the point is."
          }
        },
        "required": [
          "label",
          "lat",
          "lng",
          "tipo",
          "concelho",
          "distrito",
          "regiao"
        ]
      },
      "GeoSearchResponse": {
        "type": "object",
        "description": "The places that match.",
        "properties": {
          "candidatos": {
            "type": "array",
            "maxItems": 5,
            "items": {
              "$ref": "#/components/schemas/GeoCandidate"
            },
            "description": "Up to 5 places, best first. Empty when nothing matches."
          },
          "atribuicao": {
            "type": "string",
            "description": "What to print with the results: the provider and the OpenStreetMap credit."
          },
          "emCache": {
            "type": "boolean",
            "description": "True when the answer came from our own cache and no provider was asked."
          }
        },
        "required": [
          "candidatos",
          "atribuicao",
          "emCache"
        ]
      },
      "TripPlace": {
        "description": "A place: a concelho of mainland Portugal by slug or name (the 278 concelhos, accents and case ignored), or a position inside mainland Portugal (rounded to two decimals).",
        "oneOf": [
          {
            "type": "object",
            "properties": {
              "concelho": {
                "type": "string",
                "description": "Concelho slug or name, for example `lisboa` or `Vila Nova de Gaia`.",
                "minLength": 2,
                "maxLength": 80
              }
            },
            "required": [
              "concelho"
            ]
          },
          {
            "type": "object",
            "properties": {
              "lat": {
                "type": "number",
                "description": "Latitude.",
                "minimum": 36.8,
                "maximum": 42.3
              },
              "lng": {
                "type": "number",
                "description": "Longitude.",
                "minimum": -9.7,
                "maximum": -6
              }
            },
            "required": [
              "lat",
              "lng"
            ]
          }
        ]
      },
      "FuelTripRequest": {
        "type": "object",
        "description": "Fuel trip: the cheapest stops on the way for a car.",
        "properties": {
          "modo": {
            "type": "string",
            "enum": [
              "combustivel"
            ],
            "description": "Optional. Absent or 'combustivel' is the fuel trip."
          },
          "de": {
            "$ref": "#/components/schemas/TripPlace"
          },
          "para": {
            "$ref": "#/components/schemas/TripPlace"
          },
          "combustivel": {
            "type": "string",
            "enum": [
              "gasoleo",
              "gasolina-95",
              "gasoleo-especial",
              "gasolina-98",
              "gasolina-especial-95",
              "gasolina-especial-98",
              "gpl",
              "gasoleo-colorido"
            ],
            "description": "Fuel of the car."
          },
          "carro": {
            "type": "object",
            "description": "The car: tank, consumption and the fuel in the tank at the start.",
            "properties": {
              "deposito": {
                "type": "number",
                "description": "Tank size, litres.",
                "minimum": 20,
                "maximum": 150
              },
              "consumo": {
                "type": "number",
                "description": "Consumption, litres per 100 km.",
                "minimum": 2,
                "maximum": 25
              },
              "nivel": {
                "type": "number",
                "description": "Fuel in the tank at the start, percent of the tank.",
                "minimum": 0,
                "maximum": 100
              }
            },
            "required": [
              "deposito",
              "consumo",
              "nivel"
            ]
          },
          "opcoes": {
            "type": "object",
            "description": "Optional settings of the plan; each has a default.",
            "properties": {
              "reserva": {
                "type": "number",
                "description": "Never go below this share of the tank, percent. Default 10.",
                "minimum": 0,
                "maximum": 40
              },
              "chegada": {
                "type": "number",
                "description": "Arrive with at least this share, percent. Default 10.",
                "minimum": 0,
                "maximum": 100
              },
              "desvioMaxKm": {
                "type": "number",
                "description": "Ignore stations further than this from the road, straight line, km. Default 5.",
                "minimum": 1,
                "maximum": 20
              },
              "custoParagem": {
                "type": "number",
                "description": "What a stop is worth to you in time, euros: steers the plan, not added to the cost. Default 1.",
                "minimum": 0,
                "maximum": 10
              },
              "marca": {
                "type": "string",
                "description": "Only stop at this brand (brand slug or name, for example 'galp'). An unknown brand is a 400."
              }
            },
            "required": []
          }
        },
        "required": [
          "de",
          "para",
          "combustivel",
          "carro"
        ]
      },
      "EvTripRequest": {
        "type": "object",
        "description": "Electric trip: the fastest way to charge on the way, with MOBI.E rapid chargers (DC, 50 kW or more).",
        "properties": {
          "modo": {
            "type": "string",
            "enum": [
              "eletrico"
            ],
            "description": "Selects the electric trip."
          },
          "de": {
            "$ref": "#/components/schemas/TripPlace"
          },
          "para": {
            "$ref": "#/components/schemas/TripPlace"
          },
          "ev": {
            "type": "object",
            "description": "The electric car and the charging preferences.",
            "properties": {
              "bateriaKwh": {
                "type": "number",
                "description": "Usable battery, kWh.",
                "minimum": 10,
                "maximum": 200
              },
              "consumoKwh100": {
                "type": "number",
                "description": "Consumption, kWh per 100 km.",
                "minimum": 8,
                "maximum": 40
              },
              "cargaInicialPct": {
                "type": "number",
                "description": "Charge at the start, percent.",
                "minimum": 0,
                "maximum": 100
              },
              "potenciaMaxKw": {
                "type": "number",
                "description": "The most the car accepts when charging on DC, kW. Default 150.",
                "minimum": 20,
                "maximum": 400
              },
              "ficha": {
                "type": "string",
                "enum": [
                  "ccs",
                  "chademo",
                  "t2"
                ],
                "default": "ccs",
                "description": "The car's connector at a rapid charger."
              },
              "reservaPct": {
                "type": "number",
                "description": "Never below this charge, percent. Default 10.",
                "minimum": 0,
                "maximum": 40
              },
              "chegadaPct": {
                "type": "number",
                "description": "Arrive with at least this charge, percent. Default 15.",
                "minimum": 0,
                "maximum": 100
              },
              "cargaAtePct": {
                "type": "number",
                "description": "Stop charging at this level, percent; must be above reservaPct. Default 80.",
                "minimum": 20,
                "maximum": 100
              },
              "desvioMaxKm": {
                "type": "number",
                "description": "Ignore chargers further than this from the road, km. Default 5.",
                "minimum": 1,
                "maximum": 20
              },
              "soLivres": {
                "type": "boolean",
                "description": "Only sites with a free qualifying point at the last hourly status read. Default false."
              }
            },
            "required": [
              "bateriaKwh",
              "consumoKwh100",
              "cargaInicialPct"
            ]
          }
        },
        "required": [
          "modo",
          "de",
          "para",
          "ev"
        ]
      },
      "TripRoute": {
        "type": "object",
        "properties": {
          "distanciaKm": {
            "type": "number",
            "description": "Route length, km."
          },
          "duracaoMin": {
            "type": "number",
            "description": "Driving time, minutes."
          },
          "geometria": {
            "type": "array",
            "items": {
              "type": "array",
              "prefixItems": [
                {
                  "type": "number",
                  "description": "Longitude."
                },
                {
                  "type": "number",
                  "description": "Latitude."
                }
              ],
              "minItems": 2,
              "maxItems": 2
            },
            "description": "The route as [lng, lat] pairs, simplified (at most 800 points)."
          },
          "fornecedor": {
            "type": "string",
            "description": "Routing provider, 'openrouteservice'."
          },
          "emCache": {
            "type": "boolean",
            "description": "True when the route came from our cache (30 days)."
          }
        },
        "required": [
          "distanciaKm",
          "duracaoMin",
          "geometria",
          "fornecedor",
          "emCache"
        ]
      },
      "TripData": {
        "type": "object",
        "properties": {
          "dgegAte": {
            "oneOf": [
              {
                "type": "string",
                "description": "Newest DGEG report behind the prices used, ISO instant.",
                "format": "date-time"
              },
              {
                "type": "null"
              }
            ]
          },
          "atribuicao": {
            "type": "string",
            "description": "Attribution to show with every result."
          }
        },
        "required": [
          "dgegAte",
          "atribuicao"
        ]
      },
      "TollStretch": {
        "type": "object",
        "properties": {
          "via": {
            "type": "string",
            "description": "Road, for example 'A1'."
          },
          "de": {
            "type": "string",
            "description": "From, in the direction of travel."
          },
          "ate": {
            "type": "string",
            "description": "To."
          },
          "preco": {
            "type": "number",
            "description": "Euros, VAT included."
          },
          "lancos": {
            "type": "integer",
            "description": "Tariff sections added up."
          }
        },
        "required": [
          "via",
          "de",
          "ate",
          "preco",
          "lancos"
        ]
      },
      "TripTolls": {
        "type": "object",
        "description": "Toll estimate, class 1, separate from the fuel cost. Label it 'Portagens estimadas (classe 1)'.",
        "properties": {
          "classe": {
            "type": "integer",
            "description": "Vehicle class, 1 (light cars)."
          },
          "total": {
            "type": "number",
            "description": "Euros, VAT included. A floor when `semPreco` is not empty."
          },
          "trocos": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/TollStretch"
            },
            "description": "Runs of consecutive tariff sections on one road, in route order."
          },
          "semPreco": {
            "type": "array",
            "items": {
              "type": "object",
              "properties": {
                "via": {
                  "type": "string",
                  "description": "Road."
                },
                "km": {
                  "type": "number",
                  "description": "Kilometres on it."
                }
              },
              "required": [
                "via",
                "km"
              ]
            },
            "description": "Tolled roads on the route that the tariff source does not price."
          },
          "fonte": {
            "type": "object",
            "description": "The tariff source to print next to the figure.",
            "properties": {
              "nome": {
                "type": "string",
                "description": "Source table."
              },
              "url": {
                "type": "string",
                "description": "Source URL."
              },
              "ano": {
                "type": "integer",
                "description": "Tariff year."
              },
              "paginaAtualizadaEm": {
                "type": "string",
                "description": "Source page date."
              },
              "verificadoEm": {
                "type": "string",
                "description": "Date we checked it."
              }
            },
            "required": [
              "nome",
              "url",
              "ano",
              "paginaAtualizadaEm",
              "verificadoEm"
            ]
          }
        },
        "required": [
          "classe",
          "total",
          "trocos",
          "semPreco",
          "fonte"
        ]
      },
      "FuelStop": {
        "type": "object",
        "properties": {
          "postoId": {
            "type": "integer",
            "description": "Station id."
          },
          "nome": {
            "type": "string",
            "description": "Station name."
          },
          "marca": {
            "type": "string",
            "description": "Brand."
          },
          "concelho": {
            "type": "string",
            "description": "Concelho."
          },
          "lat": {
            "type": "number",
            "description": "Latitude."
          },
          "lng": {
            "type": "number",
            "description": "Longitude."
          },
          "kmNaRota": {
            "type": "number",
            "description": "Kilometres from the start along the route."
          },
          "desvioKm": {
            "type": "number",
            "description": "Extra kilometres driven to go and come back."
          },
          "foraDaRotaKm": {
            "type": "number",
            "description": "Straight-line distance from the road, km."
          },
          "preco": {
            "type": "number",
            "description": "Euros per litre."
          },
          "precoAtualizadoEm": {
            "type": "string",
            "description": "When the station reported the price, ISO instant."
          },
          "litros": {
            "type": "number",
            "description": "Litres to buy here, detour fuel included."
          },
          "nivelChegadaPct": {
            "type": "number",
            "description": "Tank level on reaching the pump, percent."
          },
          "nivelSaidaPct": {
            "type": "number",
            "description": "Tank level when leaving, percent."
          }
        },
        "required": [
          "postoId",
          "nome",
          "marca",
          "concelho",
          "lat",
          "lng",
          "kmNaRota",
          "desvioKm",
          "foraDaRotaKm",
          "preco",
          "precoAtualizadoEm",
          "litros",
          "nivelChegadaPct",
          "nivelSaidaPct"
        ]
      },
      "FuelTripResponse": {
        "type": "object",
        "description": "Fuel trip answer.",
        "properties": {
          "rota": {
            "$ref": "#/components/schemas/TripRoute"
          },
          "plano": {
            "type": "object",
            "description": "The refuelling plan.",
            "properties": {
              "possivel": {
                "type": "boolean",
                "description": "False means no plan exists with these settings; `falha` says where it breaks."
              },
              "custoTotal": {
                "type": "number",
                "description": "Euros of fuel bought at the stops (the stop penalty is not money and is not in it)."
              },
              "litros": {
                "type": "number",
                "description": "Litres bought."
              },
              "paragens": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/FuelStop"
                }
              },
              "falha": {
                "type": "object",
                "properties": {
                  "deKm": {
                    "type": "number",
                    "description": "Start of the stretch with no station in reach, km."
                  },
                  "ateKm": {
                    "type": "number",
                    "description": "End of it, km."
                  },
                  "dicas": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 4
                  }
                },
                "required": [
                  "deKm",
                  "ateKm",
                  "dicas"
                ]
              },
              "precoMedianoCorredor": {
                "oneOf": [
                  {
                    "type": "number",
                    "description": "Median price of the stations within reach of the road, euros per litre."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "poupancaVsMediana": {
                "oneOf": [
                  {
                    "type": "number",
                    "description": "Euros saved against buying the same litres at the corridor median; can be 0 or negative."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "postosConsiderados": {
                "type": "integer",
                "description": "Stations given to the optimiser."
              },
              "desvioTotalKm": {
                "type": "number",
                "description": "Total detour of the stops, km."
              },
              "nivelDestinoPct": {
                "oneOf": [
                  {
                    "type": "number",
                    "description": "Tank level at the destination, percent."
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "possivel",
              "custoTotal",
              "litros",
              "paragens",
              "precoMedianoCorredor",
              "poupancaVsMediana",
              "postosConsiderados"
            ]
          },
          "portagens": {
            "$ref": "#/components/schemas/TripTolls"
          },
          "dados": {
            "$ref": "#/components/schemas/TripData"
          }
        },
        "required": [
          "rota",
          "plano",
          "dados"
        ]
      },
      "EvStop": {
        "type": "object",
        "properties": {
          "siteId": {
            "type": "integer",
            "description": "Charging site id."
          },
          "nome": {
            "type": "string",
            "description": "Site label."
          },
          "marca": {
            "type": "string",
            "description": "Public brand."
          },
          "marcaSlug": {
            "type": "string",
            "description": "Brand slug."
          },
          "concelho": {
            "type": "string",
            "description": "Concelho."
          },
          "lat": {
            "type": "number",
            "description": "Latitude."
          },
          "lng": {
            "type": "number",
            "description": "Longitude."
          },
          "kmNaRota": {
            "type": "number",
            "description": "Kilometres from the start along the route."
          },
          "desvioKm": {
            "type": "number",
            "description": "Round-trip detour, km."
          },
          "foraDaRotaKm": {
            "type": "number",
            "description": "Straight-line distance from the road, km."
          },
          "desvioMin": {
            "type": "number",
            "description": "Detour time, minutes."
          },
          "potenciaLocalKw": {
            "type": "number",
            "description": "The most the site offers on the car's connector, kW."
          },
          "potenciaEfetivaKw": {
            "type": "number",
            "description": "min(car, charger): what the time estimate starts from, kW."
          },
          "fichas": {
            "type": "string",
            "description": "Connectors of the site, text."
          },
          "pontos": {
            "type": "integer",
            "description": "Qualifying points."
          },
          "pontosLivres": {
            "type": "integer",
            "description": "Qualifying points free at the last hourly read."
          },
          "pontosAvariados": {
            "type": "integer",
            "description": "Qualifying points out of order."
          },
          "estado": {
            "type": "string",
            "enum": [
              "livre",
              "semLivre",
              "avariado",
              "outro"
            ],
            "description": "Status group of the qualifying points at the last hourly read."
          },
          "nivelChegadaPct": {
            "type": "number",
            "description": "Charge on arriving, percent."
          },
          "nivelSaidaPct": {
            "type": "number",
            "description": "Charge on unplugging, percent."
          },
          "kwhAdicionados": {
            "type": "number",
            "description": "Energy into the battery, kWh."
          },
          "cargaMin": {
            "type": "number",
            "description": "Estimated charging time, minutes (taper included, overhead not)."
          },
          "preco": {
            "oneOf": [
              {
                "type": "object",
                "description": "Ad hoc price published by MOBI.E, VAT included; null when not shown.",
                "properties": {
                  "texto": {
                    "type": "string",
                    "description": "Ready-made line, '0,65 €/kWh'."
                  },
                  "kwhMili": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "description": "kWh component, thousandths of a euro."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "minMili": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "description": "Per-minute component, thousandths of a euro."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "flatMili": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "description": "Flat fee, thousandths of a euro."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "texto",
                  "kwhMili",
                  "minMili",
                  "flatMili"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "custoEstimado": {
            "type": "number",
            "description": "Estimated cost of the charge here, euros; present only when the site has a price."
          }
        },
        "required": [
          "siteId",
          "nome",
          "marca",
          "concelho",
          "lat",
          "lng",
          "kmNaRota",
          "desvioKm",
          "nivelChegadaPct",
          "nivelSaidaPct",
          "kwhAdicionados",
          "cargaMin",
          "preco"
        ]
      },
      "EvTripResponse": {
        "type": "object",
        "description": "Electric trip answer.",
        "properties": {
          "modo": {
            "type": "string",
            "enum": [
              "eletrico"
            ],
            "description": "Always 'eletrico' in this answer."
          },
          "rota": {
            "$ref": "#/components/schemas/TripRoute"
          },
          "plano": {
            "type": "object",
            "description": "The charging plan.",
            "properties": {
              "possivel": {
                "type": "boolean"
              },
              "paragens": {
                "type": "array",
                "items": {
                  "$ref": "#/components/schemas/EvStop"
                }
              },
              "falha": {
                "type": "object",
                "properties": {
                  "deKm": {
                    "type": "number",
                    "description": "Start of the stretch with no charger in reach, km."
                  },
                  "ateKm": {
                    "type": "number",
                    "description": "End of it, km."
                  },
                  "dicas": {
                    "type": "array",
                    "items": {
                      "type": "string"
                    },
                    "maxItems": 4
                  }
                },
                "required": [
                  "deKm",
                  "ateKm",
                  "dicas"
                ]
              },
              "tempo": {
                "type": "object",
                "properties": {
                  "conducaoMin": {
                    "type": "number",
                    "description": "Driving time."
                  },
                  "desviosMin": {
                    "type": "number",
                    "description": "Detours."
                  },
                  "cargaMin": {
                    "type": "number",
                    "description": "Charging."
                  },
                  "paragensMin": {
                    "type": "number",
                    "description": "5 minutes per stop."
                  },
                  "totalMin": {
                    "type": "number",
                    "description": "Sum of the four."
                  }
                },
                "required": [
                  "conducaoMin",
                  "desviosMin",
                  "cargaMin",
                  "paragensMin",
                  "totalMin"
                ]
              },
              "kwhUsados": {
                "type": "number",
                "description": "Energy used driving, kWh."
              },
              "kwhCarregados": {
                "type": "number",
                "description": "Energy charged, kWh."
              },
              "custoTotal": {
                "oneOf": [
                  {
                    "type": "number",
                    "description": "Estimated cost, euros, when every stop has a published price; null otherwise."
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "postosConsiderados": {
                "type": "integer",
                "description": "Chargers given to the optimiser."
              },
              "desvioTotalKm": {
                "type": "number",
                "description": "Total detour, km."
              },
              "nivelDestinoPct": {
                "oneOf": [
                  {
                    "type": "number",
                    "description": "Charge at the destination, percent."
                  },
                  {
                    "type": "null"
                  }
                ]
              }
            },
            "required": [
              "possivel",
              "paragens",
              "tempo",
              "kwhUsados",
              "kwhCarregados",
              "custoTotal"
            ]
          },
          "portagens": {
            "$ref": "#/components/schemas/TripTolls"
          },
          "dados": {
            "type": "object",
            "description": "Freshness and attribution of the data behind the plan.",
            "properties": {
              "estadoEm": {
                "oneOf": [
                  {
                    "type": "string",
                    "description": "When the charger status was read, ISO instant. Write 'estado lido às HH:MM'.",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "listaEm": {
                "oneOf": [
                  {
                    "type": "string",
                    "description": "When the list of chargers was read, ISO instant.",
                    "format": "date-time"
                  },
                  {
                    "type": "null"
                  }
                ]
              },
              "atribuicao": {
                "type": "string",
                "description": "Attribution to show with every result."
              },
              "precosConfirmados": {
                "type": "boolean"
              },
              "notaPreco": {
                "type": "string",
                "description": "Note to show next to any price."
              }
            },
            "required": [
              "estadoEm",
              "listaEm",
              "atribuicao",
              "precosConfirmados",
              "notaPreco"
            ]
          }
        },
        "required": [
          "modo",
          "rota",
          "plano",
          "dados"
        ]
      },
      "HealthUnavailable": {
        "type": "object",
        "description": "The answer of /api/saude/ when the data store cannot be read: the standard error object next to db false.",
        "properties": {
          "db": {
            "type": "boolean",
            "description": "False."
          },
          "error": {
            "$ref": "#/components/schemas/ApiErrorDetail"
          }
        },
        "required": [
          "db",
          "error"
        ]
      },
      "Health": {
        "type": "object",
        "description": "Public health check: what the last reading did and whether the data is getting old.",
        "properties": {
          "db": {
            "type": "boolean",
            "description": "False when the data store cannot be read; then only `db` (and `error`) are present."
          },
          "db_reads": {
            "type": "string",
            "enum": [
              "on",
              "off"
            ],
            "description": "Whether the pages read from our own store (on) or live from DGEG (off)."
          },
          "last_run": {
            "oneOf": [
              {
                "type": "object",
                "description": "The last finished price reading; null before the first one.",
                "properties": {
                  "id": {
                    "type": "integer",
                    "description": "Run id."
                  },
                  "status": {
                    "type": "string",
                    "enum": [
                      "ok",
                      "unchanged",
                      "partial",
                      "failed"
                    ]
                  },
                  "finished_at": {
                    "oneOf": [
                      {
                        "type": "string",
                        "description": "ISO instant.",
                        "format": "date-time"
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "rows_in": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "description": "Rows read."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "events": {
                    "oneOf": [
                      {
                        "type": "integer",
                        "description": "Price changes stored."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  },
                  "latest_reported_local": {
                    "oneOf": [
                      {
                        "type": "string",
                        "description": "Newest report time seen, Lisbon local time."
                      },
                      {
                        "type": "null"
                      }
                    ]
                  }
                },
                "required": [
                  "id",
                  "status",
                  "finished_at",
                  "rows_in",
                  "events",
                  "latest_reported_local"
                ]
              },
              {
                "type": "null"
              }
            ]
          },
          "age_minutes": {
            "oneOf": [
              {
                "type": "integer",
                "description": "Minutes since the last good price run."
              },
              {
                "type": "null"
              }
            ]
          },
          "gaps_24h": {
            "type": "integer",
            "description": "Reading gaps in the last 24 hours."
          },
          "banner": {
            "type": "boolean",
            "description": "True when the site shows its 'data may be late' banner (last run partial or failed, or older than 180 minutes)."
          },
          "ev": {
            "type": "object",
            "description": "The same for the charging jobs: `static` and `status` runs and a `stale` flag.",
            "additionalProperties": true
          },
          "error": {
            "description": "Present with db false: the standard error object.",
            "$ref": "#/components/schemas/ApiErrorDetail"
          }
        },
        "required": [
          "db"
        ],
        "additionalProperties": true
      }
    },
    "responses": {
      "BadRequest": {
        "description": "The request is not valid: malformed JSON, a value out of range or unknown (`invalid_json`, `invalid_request`, `invalid_filter`, `unknown_fuel`, `missing_coordinates`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "invalid_json",
                "message": "Pedido inválido.",
                "hint": "Envie JSON válido no corpo, com Content-Type: application/json."
              }
            }
          }
        }
      },
      "NotFound": {
        "description": "Unknown fuel, site or place (`unknown_fuel`, `not_found`, `unknown_place`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "not_found",
                "message": "Local desconhecido.",
                "hint": "Veja os endereços públicos em https://combustivel.com.pt/openapi.json e a lista de páginas em https://combustivel.com.pt/llms.txt."
              }
            }
          }
        }
      },
      "MethodNotAllowed": {
        "description": "The method is not the one this endpoint answers; the `Allow` header says which.",
        "headers": {
          "Allow": {
            "description": "Methods this endpoint answers.",
            "schema": {
              "type": "string"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "method_not_allowed",
                "message": "Este endereço não aceita este método. Use POST.",
                "hint": "Veja o método certo em https://combustivel.com.pt/openapi.json."
              }
            }
          }
        }
      },
      "PayloadTooLarge": {
        "description": "The body is larger than the endpoint accepts (`payload_too_large`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "payload_too_large",
                "message": "Pedido demasiado grande.",
                "hint": "Envie só os campos documentados: o corpo é pequeno (até 2 KB)."
              }
            }
          }
        }
      },
      "OutsideCoverage": {
        "description": "The position is outside the area we cover (`out_of_coverage`).",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "out_of_coverage",
                "message": "Só temos postos de Portugal continental.",
                "hint": "As coordenadas têm de estar em Portugal (os postos de combustível só no continente)."
              }
            }
          }
        }
      },
      "RateLimited": {
        "description": "Too many routes that were not in the cache (`rate_limited`), or the routing provider's budget for the day is spent. Wait `Retry-After` seconds.",
        "headers": {
          "Retry-After": {
            "description": "Seconds to wait.",
            "schema": {
              "type": "integer"
            }
          }
        },
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "rate_limited",
                "message": "O cálculo de rotas está ocupado. Tente daqui a pouco.",
                "hint": "Espere cerca de 10 minutos antes de repetir; um pedido igual a um já feito não conta para o limite."
              }
            }
          }
        }
      },
      "BadGateway": {
        "description": "The data source (DGEG) did not answer (`upstream_unavailable`). Try again in a few minutes.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "upstream_unavailable",
                "message": "A DGEG não respondeu. Tente de novo dentro de minutos.",
                "hint": "A fonte dos dados não respondeu; tente de novo dentro de minutos."
              }
            }
          }
        }
      },
      "Unavailable": {
        "description": "The data is not available right now (`data_unavailable`). Try again in a few minutes.",
        "content": {
          "application/json": {
            "schema": {
              "$ref": "#/components/schemas/ApiError"
            },
            "example": {
              "error": {
                "code": "data_unavailable",
                "message": "Os dados de carregamento estão indisponíveis de momento.",
                "hint": "Tente de novo dentro de minutos; os dados são atualizados de hora a hora."
              }
            }
          }
        }
      }
    }
  },
  "externalDocs": {
    "description": "Developer page with curl examples (Portuguese)",
    "url": "https://combustivel.com.pt/desenvolvedores/"
  }
}