{
  "openapi": "3.1.0",
  "info": {
    "title": "Zenithis Maps GeoEngine API",
    "version": "1.1.0",
    "description": "Zenithis public Search, Reverse and Distance; Valhalla Route is a limited canary. Places and aviation operational data are unavailable. No commercial SLA or authenticated quotas are implied. © OpenStreetMap contributors."
  },
  "servers": [
    {
      "url": "https://map.zenithis.tech",
      "description": "Public Zenithis Maps endpoint"
    }
  ],
  "tags": [
    {
      "name": "Geocoding",
      "description": "Photon-backed read-only search and reverse geocoding"
    },
    {
      "name": "Distance",
      "description": "PostGIS geodesic distance; not road routing"
    },
    {
      "name": "Routing",
      "description": "Valhalla limited public canary; OSM coverage and quotas apply."
    }
  ],
  "paths": {
    "/v1/search": {
      "get": {
        "tags": [
          "Geocoding"
        ],
        "summary": "Search a location",
        "description": "Photon-backed text search. Result availability varies by OSM/Photon coverage. Apply reasonable request rates.",
        "operationId": "searchLocation",
        "parameters": [
          {
            "name": "q",
            "in": "query",
            "required": true,
            "description": "Human place/address query",
            "schema": {
              "type": "string",
              "minLength": 2,
              "maxLength": 160
            },
            "example": "Douala"
          },
          {
            "name": "limit",
            "in": "query",
            "required": false,
            "schema": {
              "type": "integer",
              "minimum": 1,
              "maximum": 10,
              "default": 5
            }
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureCollection"
                }
              }
            }
          },
          "400": {
            "description": "Invalid search request"
          },
          "429": {
            "description": "Request rate limit exceeded"
          },
          "502": {
            "description": "Upstream geocoder unavailable"
          }
        }
      }
    },
    "/v1/reverse": {
      "get": {
        "tags": [
          "Geocoding"
        ],
        "summary": "Reverse geocode",
        "description": "Find nearby address/place context for WGS84 latitude and longitude.",
        "operationId": "reverseGeocode",
        "parameters": [
          {
            "name": "lat",
            "in": "query",
            "required": true,
            "description": "Latitude, degrees",
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            },
            "example": 4.04294
          },
          {
            "name": "lon",
            "in": "query",
            "required": true,
            "description": "Longitude, degrees",
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            },
            "example": 9.7062
          }
        ],
        "responses": {
          "200": {
            "description": "GeoJSON FeatureCollection",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/FeatureCollection"
                }
              }
            }
          },
          "400": {
            "description": "Invalid coordinate"
          },
          "429": {
            "description": "Request rate limit exceeded"
          },
          "502": {
            "description": "Upstream geocoder unavailable"
          }
        }
      }
    },
    "/v1/distance": {
      "get": {
        "tags": [
          "Distance"
        ],
        "summary": "Geodesic distance",
        "operationId": "geodesicDistance",
        "description": "Distance in meters between two WGS84 points, calculated with PostGIS geography. This is not a road route.",
        "parameters": [
          {
            "name": "lat1",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "lon1",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "lat2",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "lon2",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          }
        ],
        "responses": {
          "200": {
            "description": "Geodesic distance in meters",
            "content": {
              "application/json": {
                "schema": {
                  "type": "object",
                  "required": [
                    "distance_m",
                    "method",
                    "routed"
                  ],
                  "properties": {
                    "distance_m": {
                      "type": "number",
                      "minimum": 0
                    },
                    "method": {
                      "type": "string",
                      "const": "geodesic"
                    },
                    "routed": {
                      "type": "boolean",
                      "const": false
                    }
                  }
                }
              }
            }
          },
          "422": {
            "description": "Missing or out-of-range coordinates"
          }
        }
      }
    },
    "/v1/route": {
      "get": {
        "tags": [
          "Routing"
        ],
        "x-release-status": "canary",
        "description": "Limited public canary. Automobile, pedestrian and bicycle; two distinct WGS84 coordinates. OSM/Valhalla estimates, no live traffic or commercial availability guarantee. Keep requests serial and back off on 429.",
        "responses": {
          "200": {
            "description": "Route estimate, polyline6 geometry and navigation instructions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteResponse"
                }
              }
            }
          },
          "422": {
            "description": "Invalid request, identical points or no available route"
          },
          "429": {
            "description": "Canary rate/concurrency quota reached. Retry with backoff; quota policy may change."
          },
          "502": {
            "description": "Invalid upstream response"
          },
          "503": {
            "description": "Routing temporarily unavailable"
          },
          "504": {
            "description": "Gateway timeout"
          }
        },
        "summary": "Calculate a route (canary)",
        "operationId": "getRoute",
        "parameters": [
          {
            "name": "from_lat",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "from_lon",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "to_lat",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -90,
              "maximum": 90
            }
          },
          {
            "name": "to_lon",
            "in": "query",
            "required": true,
            "schema": {
              "type": "number",
              "minimum": -180,
              "maximum": 180
            }
          },
          {
            "name": "costing",
            "in": "query",
            "required": false,
            "schema": {
              "type": "string",
              "enum": [
                "auto",
                "pedestrian",
                "bicycle"
              ],
              "default": "auto"
            }
          }
        ]
      },
      "post": {
        "tags": [
          "Routing"
        ],
        "x-release-status": "canary",
        "description": "Limited public canary. Automobile, pedestrian and bicycle; two distinct WGS84 coordinates. OSM/Valhalla estimates, no live traffic or commercial availability guarantee. Keep requests serial and back off on 429.",
        "responses": {
          "200": {
            "description": "Route estimate, polyline6 geometry and navigation instructions",
            "content": {
              "application/json": {
                "schema": {
                  "$ref": "#/components/schemas/RouteResponse"
                }
              }
            }
          },
          "422": {
            "description": "Invalid request, identical points or no available route"
          },
          "429": {
            "description": "Canary rate/concurrency quota reached. Retry with backoff; quota policy may change."
          },
          "502": {
            "description": "Invalid upstream response"
          },
          "503": {
            "description": "Routing temporarily unavailable"
          },
          "504": {
            "description": "Gateway timeout"
          }
        },
        "summary": "Calculate a route from JSON (canary)",
        "operationId": "postRoute",
        "requestBody": {
          "required": true,
          "content": {
            "application/json": {
              "schema": {
                "$ref": "#/components/schemas/RouteRequest"
              },
              "example": {
                "locations": [
                  {
                    "lat": 4.0511,
                    "lon": 9.7679
                  },
                  {
                    "lat": 4.0735,
                    "lon": 9.6769
                  }
                ],
                "costing": "auto"
              }
            }
          }
        }
      }
    }
  },
  "components": {
    "schemas": {
      "FeatureCollection": {
        "type": "object",
        "required": [
          "type",
          "features"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "FeatureCollection"
          },
          "features": {
            "type": "array",
            "items": {
              "$ref": "#/components/schemas/Feature"
            }
          }
        },
        "additionalProperties": true
      },
      "Feature": {
        "type": "object",
        "required": [
          "type",
          "geometry",
          "properties"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "Feature"
          },
          "geometry": {
            "oneOf": [
              {
                "$ref": "#/components/schemas/Point"
              },
              {
                "type": "null"
              }
            ]
          },
          "properties": {
            "type": "object",
            "additionalProperties": true
          }
        },
        "additionalProperties": true
      },
      "Point": {
        "type": "object",
        "required": [
          "type",
          "coordinates"
        ],
        "properties": {
          "type": {
            "type": "string",
            "const": "Point"
          },
          "coordinates": {
            "type": "array",
            "prefixItems": [
              {
                "type": "number",
                "description": "Longitude"
              },
              {
                "type": "number",
                "description": "Latitude"
              }
            ],
            "minItems": 2,
            "maxItems": 2
          }
        },
        "additionalProperties": true
      },
      "RouteLocation": {
        "type": "object",
        "required": [
          "lat",
          "lon"
        ],
        "additionalProperties": false,
        "properties": {
          "lat": {
            "type": "number",
            "minimum": -90,
            "maximum": 90
          },
          "lon": {
            "type": "number",
            "minimum": -180,
            "maximum": 180
          },
          "type": {
            "type": "string",
            "enum": [
              "break"
            ],
            "default": "break"
          }
        }
      },
      "RouteRequest": {
        "type": "object",
        "required": [
          "locations"
        ],
        "additionalProperties": false,
        "description": "Exactly two distinct finite WGS84 points. No alternatives, avoid polygons or arbitrary Valhalla options.",
        "properties": {
          "locations": {
            "type": "array",
            "minItems": 2,
            "maxItems": 2,
            "items": {
              "$ref": "#/components/schemas/RouteLocation"
            }
          },
          "costing": {
            "type": "string",
            "enum": [
              "auto",
              "pedestrian",
              "bicycle"
            ],
            "default": "auto"
          },
          "units": {
            "type": "string",
            "enum": [
              "kilometers"
            ],
            "default": "kilometers"
          },
          "language": {
            "type": "string",
            "enum": [
              "fr-FR",
              "en-US"
            ],
            "default": "fr-FR"
          },
          "directions_type": {
            "type": "string",
            "enum": [
              "instructions"
            ],
            "default": "instructions"
          }
        }
      },
      "RouteResponse": {
        "type": "object",
        "required": [
          "trip"
        ],
        "properties": {
          "trip": {
            "type": "object",
            "required": [
              "summary",
              "legs"
            ],
            "properties": {
              "units": {
                "type": "string",
                "enum": [
                  "kilometers"
                ]
              },
              "summary": {
                "type": "object",
                "required": [
                  "length",
                  "time"
                ],
                "properties": {
                  "length": {
                    "type": "number",
                    "description": "Route length in kilometers"
                  },
                  "time": {
                    "type": "number",
                    "description": "Estimated travel seconds; not live traffic"
                  }
                }
              },
              "legs": {
                "type": "array",
                "items": {
                  "type": "object",
                  "required": [
                    "shape",
                    "maneuvers"
                  ],
                  "properties": {
                    "shape": {
                      "type": "string",
                      "description": "Encoded polyline with precision 6; decode as latitude, longitude, convert to longitude, latitude for GeoJSON"
                    },
                    "maneuvers": {
                      "type": "array",
                      "items": {
                        "type": "object",
                        "properties": {
                          "instruction": {
                            "type": "string"
                          },
                          "length": {
                            "type": "number"
                          },
                          "time": {
                            "type": "number"
                          }
                        }
                      }
                    }
                  }
                }
              }
            }
          }
        }
      }
    }
  }
}
