← Back to Geo docs

Geo — Tool Reference

Location intelligence on OpenStreetMap data: geocoding via LocationIQ or Geoapify, OSM feature queries, and geometry operations

7 tools · auto-generated from the deployed toolkit

Your AI assistant discovers and invokes these tools through the MCP Server's meta tools — it calls execute_tool with the tool name and arguments below.

# geocode read

Batch geocode up to 25 free-text queries to coordinates and OSM metadata via LocationIQ or Geoapify.

Full description
Geocode free-text queries to coordinates and OpenStreetMap metadata.

Runs up to 25 queries in one call against the provider chosen with
`source` (the matching API key must be configured for the Geo toolkit).
Each match includes lat/lon, a [west, south, east, north] bbox, display
name, OSM type/id, class/type, and an importance score where available.
Set `include_geojson` to get boundary polygons for areas (LocationIQ
only). Pass `near_bbox` to bias ambiguous names toward your region;
bias is soft and can lose to strong global matches, so add
restrict_to_bbox=true when results must fall inside the box (a per-query
`warning` is set when the top match lands far outside the box). LocationIQ matches always carry osm_type/osm_id; Geoapify's API
does not expose them, so prefer source='locationiq' when you need OSM
ids (e.g. to chain into lookup_place). Calls are paced to the provider's
free-tier rate limit; if the provider still returns 429, remaining
queries are skipped and `rate_limited` is set. Results include
OpenStreetMap/provider attribution that must be shown when data is
displayed publicly.
Parameter Type Required Description
queries array<string> Yes Free-text queries to geocode, e.g. '650 Main St, Edmonds, WA'. Up to 25 per call.
source "locationiq" | "geoapify" Yes Geocoding provider to use. Requires that provider's API key to be configured for the Geo toolkit.
limit integer No Maximum matches to return per query. Default: 3
include_geojson boolean No Include boundary polygons as GeoJSON where available. Supported by LocationIQ only; Geoapify matches always omit geometry. Default: false
near_bbox array<number> | null No [west, south, east, north] bias box: prefer matches inside it. Bias is a soft preference and can lose to strong global name matches (especially on LocationIQ); set restrict_to_bbox=true when results must come from your region.
restrict_to_bbox boolean No With near_bbox: exclude matches outside the box entirely instead of just preferring inside. Default: false
Parameter schema (JSON)
{
  "properties": {
    "queries": {
      "description": "Free-text queries to geocode, e.g. '650 Main St, Edmonds, WA'. Up to 25 per call.",
      "items": {
        "type": "string"
      },
      "maxItems": 25,
      "minItems": 1,
      "title": "Queries",
      "type": "array"
    },
    "source": {
      "description": "Geocoding provider to use. Requires that provider's API key to be configured for the Geo toolkit.",
      "enum": [
        "locationiq",
        "geoapify"
      ],
      "title": "Source",
      "type": "string"
    },
    "limit": {
      "default": 3,
      "description": "Maximum matches to return per query.",
      "maximum": 10,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    },
    "include_geojson": {
      "default": false,
      "description": "Include boundary polygons as GeoJSON where available. Supported by LocationIQ only; Geoapify matches always omit geometry.",
      "title": "Include Geojson",
      "type": "boolean"
    },
    "near_bbox": {
      "anyOf": [
        {
          "items": {
            "type": "number"
          },
          "maxItems": 4,
          "minItems": 4,
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "[west, south, east, north] bias box: prefer matches inside it. Bias is a soft preference and can lose to strong global name matches (especially on LocationIQ); set restrict_to_bbox=true when results must come from your region.",
      "title": "Near Bbox"
    },
    "restrict_to_bbox": {
      "default": false,
      "description": "With near_bbox: exclude matches outside the box entirely instead of just preferring inside.",
      "title": "Restrict To Bbox",
      "type": "boolean"
    }
  },
  "required": [
    "queries",
    "source"
  ],
  "title": "GeocodeParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "GeocodeMatch": {
      "properties": {
        "lat": {
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "title": "Lon",
          "type": "number"
        },
        "display_name": {
          "title": "Display Name",
          "type": "string"
        },
        "bbox": {
          "anyOf": [
            {
              "items": {
                "type": "number"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "[west, south, east, north] in WGS84 degrees.",
          "title": "Bbox"
        },
        "osm_type": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "OSM object type: node, way, or relation.",
          "title": "Osm Type"
        },
        "osm_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Osm Id"
        },
        "category": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "OSM class, e.g. 'place', 'amenity', 'boundary'.",
          "title": "Category"
        },
        "type": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "OSM type within the class, e.g. 'city', 'restaurant'.",
          "title": "Type"
        },
        "importance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Relative importance score when the provider supplies one.",
          "title": "Importance"
        },
        "address": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Normalized address components.",
          "title": "Address",
          "type": "object"
        },
        "geojson": {
          "anyOf": [
            {
              "additionalProperties": true,
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Boundary geometry as GeoJSON when include_geojson is set and available.",
          "title": "Geojson"
        }
      },
      "required": [
        "lat",
        "lon",
        "display_name"
      ],
      "title": "GeocodeMatch",
      "type": "object"
    },
    "GeocodeQueryResult": {
      "properties": {
        "query": {
          "title": "Query",
          "type": "string"
        },
        "matches": {
          "items": {
            "$ref": "#/$defs/GeocodeMatch"
          },
          "title": "Matches",
          "type": "array"
        },
        "error": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Error"
        },
        "warning": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Set when the top match falls far outside near_bbox: the soft bias lost to a global name match. Retry with restrict_to_bbox=true when results must come from that area.",
          "title": "Warning"
        }
      },
      "required": [
        "query"
      ],
      "title": "GeocodeQueryResult",
      "type": "object"
    }
  },
  "properties": {
    "success": {
      "title": "Success",
      "type": "boolean"
    },
    "source": {
      "title": "Source",
      "type": "string"
    },
    "attribution": {
      "title": "Attribution",
      "type": "string"
    },
    "rate_limited": {
      "default": false,
      "description": "True when the provider rate limit was hit and remaining queries were skipped.",
      "title": "Rate Limited",
      "type": "boolean"
    },
    "results": {
      "items": {
        "$ref": "#/$defs/GeocodeQueryResult"
      },
      "title": "Results",
      "type": "array"
    }
  },
  "required": [
    "success",
    "source",
    "attribution",
    "results"
  ],
  "title": "GeocodeResult",
  "type": "object"
}

# lookup_place read

Get full details (tags, centroid, bbox, boundary GeoJSON) for one OSM object by type and id (no key needed).

Full description
Get full details for a single OpenStreetMap object by type and id.

Returns the complete tag set, a representative point, the bounding box,
geometry metadata (type, vertex and ring counts, reported even when the
shape itself is not requested, so call with include_geometry=false to
gauge payload size first), area_km2 for polygonal shapes (computed on
the geometry as returned, with a warning when simplification shifted
the area noticeably), and (for ways/relations) the boundary or shape as
GeoJSON, assembled from the object's geometry, suitable as AOI input. Nodes are points and carry no polygon; a warning says so, and
find_boundary=true additionally searches for a same-named boundary
polygon nearby and returns that object instead (useful for neighborhoods
that exist in OSM only as a labeled point). Use simplify_tolerance_m or
max_points to compress large shapes; ring count floors how far
max_points can go. Runs on the public Overpass API with automatic
endpoint failover; no API key required. Results carry OpenStreetMap
ODbL attribution that must be shown when data is displayed publicly.
Parameter Type Required Description
osm_type "node" | "way" | "relation" Yes OSM object type.
osm_id integer Yes OSM object id.
include_geometry boolean No Include the boundary/shape as GeoJSON. Very large geometries (>50k points) are omitted with a warning. Default: true
simplify_tolerance_m number | null No Douglas-Peucker simplify the shape to this tolerance in meters before returning it.
max_points integer No Adaptively simplify the shape to at most this many points (default 2000, visually lossless at city scale; raise it explicitly when you need raw vertices). Default: 2000
find_boundary boolean No When the object resolves to a node (a point with no polygon, common for neighborhoods), also search Overpass for a same-named boundary/place polygon nearby and return that object instead. The warning field reports what happened. Default: false
Parameter schema (JSON)
{
  "properties": {
    "osm_type": {
      "description": "OSM object type.",
      "enum": [
        "node",
        "way",
        "relation"
      ],
      "title": "Osm Type",
      "type": "string"
    },
    "osm_id": {
      "description": "OSM object id.",
      "minimum": 1,
      "title": "Osm Id",
      "type": "integer"
    },
    "include_geometry": {
      "default": true,
      "description": "Include the boundary/shape as GeoJSON. Very large geometries (>50k points) are omitted with a warning.",
      "title": "Include Geometry",
      "type": "boolean"
    },
    "simplify_tolerance_m": {
      "anyOf": [
        {
          "exclusiveMinimum": 0,
          "maximum": 10000,
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Douglas-Peucker simplify the shape to this tolerance in meters before returning it.",
      "title": "Simplify Tolerance M"
    },
    "max_points": {
      "default": 2000,
      "description": "Adaptively simplify the shape to at most this many points (default 2000, visually lossless at city scale; raise it explicitly when you need raw vertices).",
      "maximum": 50000,
      "minimum": 8,
      "title": "Max Points",
      "type": "integer"
    },
    "find_boundary": {
      "default": false,
      "description": "When the object resolves to a node (a point with no polygon, common for neighborhoods), also search Overpass for a same-named boundary/place polygon nearby and return that object instead. The warning field reports what happened.",
      "title": "Find Boundary",
      "type": "boolean"
    }
  },
  "required": [
    "osm_type",
    "osm_id"
  ],
  "title": "LookupPlaceParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "properties": {
    "success": {
      "title": "Success",
      "type": "boolean"
    },
    "attribution": {
      "title": "Attribution",
      "type": "string"
    },
    "found": {
      "title": "Found",
      "type": "boolean"
    },
    "osm_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Osm Type"
    },
    "osm_id": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Osm Id"
    },
    "name": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Name"
    },
    "lat": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Representative point (node location or bounds center).",
      "title": "Lat"
    },
    "lon": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Lon"
    },
    "bbox": {
      "anyOf": [
        {
          "items": {
            "type": "number"
          },
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "[west, south, east, north] in WGS84 degrees.",
      "title": "Bbox"
    },
    "tags": {
      "additionalProperties": {
        "type": "string"
      },
      "title": "Tags",
      "type": "object"
    },
    "geometry_type": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Shape type (Point/LineString/Polygon/MultiPolygon), reported even when geojson is omitted.",
      "title": "Geometry Type"
    },
    "geometry_points": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Vertex count of the geometry as returned (after any simplification); use with include_geometry=false to gauge size before fetching.",
      "title": "Geometry Points"
    },
    "geometry_rings": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Ring count for polygonal shapes (outer rings + holes); rings floor how far max_points can compress.",
      "title": "Geometry Rings"
    },
    "area_km2": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Area of the returned geometry for polygonal shapes (after any simplification; include_geometry=false probes report the uncompressed original); a warning is added when simplification shifted it noticeably.",
      "title": "Area Km2"
    },
    "geojson": {
      "anyOf": [
        {
          "additionalProperties": true,
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Geojson"
    },
    "warning": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Warning"
    }
  },
  "required": [
    "success",
    "attribution",
    "found"
  ],
  "title": "LookupPlaceResult",
  "type": "object"
}

# make_aoi read

Build and transform GeoJSON areas of interest: point buffers, bbox polygons, buffering, simplify, merge, intersect, difference, boundary-to-line, validate.

Full description
Build or transform a GeoJSON area of interest (AOI) with geometry ops.

Operations (all results in WGS84, with area_km2 and vertex_count):
- point_buffer: circle of buffer_m meters around point
- bbox_to_polygon: [west, south, east, north] bbox as a polygon
- buffer_geometry: grow a GeoJSON geometry by buffer_m meters
- simplify: reduce vertex count with tolerance_m meters tolerance (topology-preserving)
- merge: union 2-100 GeoJSON geometries into one (for features from a
  query, geometry='merged' on query_features unions server-side instead)
- intersect: shared region of exactly 2 geometries; a line intersected
  with a polygon yields the line segment(s) inside it, which is how to
  extract a boundary sub-segment (e.g. a park boundary's shoreline:
  boundary_to_line the park, intersect with the buffered water geometry,
  then measure op=length)
- difference: the first of exactly 2 geometries minus the second
- boundary_to_line: a polygon's boundary rings as line geometry, ready
  for intersect or measure op=length
- validate: check a geometry, explain problems, and return a repaired version when invalid

Metric operations run in a local projected plane anchored at the
geometry, so distances are meters, not degrees; accuracy is ~1% for AOIs
up to a few tens of km, degrading with size and latitude. Geometries
spanning the antimeridian or within 0.1 degrees of the poles are
rejected. Runs entirely in-Lambda; no external calls, no API key. Output
GeoJSON is directly usable as an AOI for other geo tools and
earth-observation workflows.
Parameter Type Required Description
op "point_buffer" | "bbox_to_polygon" | "buffer_geometry" | "simplify" | "merge" | "intersect" | "difference" | "boundary_to_line" | "validate" Yes Geometry operation to perform.
point Coordinate | null No Center point (required for point_buffer).
buffer_m number | null No Buffer distance in meters (required for point_buffer and buffer_geometry).
bbox array<number> | null No [west, south, east, north] in WGS84 degrees (required for bbox_to_polygon).
geometry object | null No GeoJSON geometry (required for buffer_geometry, simplify, boundary_to_line, validate).
geometries array<object> | null No GeoJSON geometries (required for merge: 2-100 to union; intersect/difference: exactly 2).
tolerance_m number | null No Simplification tolerance in meters (required for simplify).
Parameter schema (JSON)
{
  "$defs": {
    "Coordinate": {
      "properties": {
        "lat": {
          "description": "Latitude in WGS84 decimal degrees.",
          "maximum": 90,
          "minimum": -90,
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "description": "Longitude in WGS84 decimal degrees.",
          "maximum": 180,
          "minimum": -180,
          "title": "Lon",
          "type": "number"
        }
      },
      "required": [
        "lat",
        "lon"
      ],
      "title": "Coordinate",
      "type": "object",
      "additionalProperties": false
    }
  },
  "properties": {
    "op": {
      "description": "Geometry operation to perform.",
      "enum": [
        "point_buffer",
        "bbox_to_polygon",
        "buffer_geometry",
        "simplify",
        "merge",
        "intersect",
        "difference",
        "boundary_to_line",
        "validate"
      ],
      "title": "Op",
      "type": "string"
    },
    "point": {
      "anyOf": [
        {
          "$ref": "#/$defs/Coordinate"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Center point (required for point_buffer)."
    },
    "buffer_m": {
      "anyOf": [
        {
          "exclusiveMinimum": 0,
          "maximum": 100000,
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Buffer distance in meters (required for point_buffer and buffer_geometry).",
      "title": "Buffer M"
    },
    "bbox": {
      "anyOf": [
        {
          "items": {
            "type": "number"
          },
          "maxItems": 4,
          "minItems": 4,
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "[west, south, east, north] in WGS84 degrees (required for bbox_to_polygon).",
      "title": "Bbox"
    },
    "geometry": {
      "anyOf": [
        {
          "additionalProperties": true,
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "GeoJSON geometry (required for buffer_geometry, simplify, boundary_to_line, validate).",
      "title": "Geometry"
    },
    "geometries": {
      "anyOf": [
        {
          "items": {
            "additionalProperties": true,
            "type": "object"
          },
          "maxItems": 100,
          "minItems": 2,
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "GeoJSON geometries (required for merge: 2-100 to union; intersect/difference: exactly 2).",
      "title": "Geometries"
    },
    "tolerance_m": {
      "anyOf": [
        {
          "exclusiveMinimum": 0,
          "maximum": 10000,
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Simplification tolerance in meters (required for simplify).",
      "title": "Tolerance M"
    }
  },
  "required": [
    "op"
  ],
  "title": "MakeAoiParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "properties": {
    "success": {
      "title": "Success",
      "type": "boolean"
    },
    "op": {
      "title": "Op",
      "type": "string"
    },
    "geojson": {
      "anyOf": [
        {
          "additionalProperties": true,
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Resulting geometry as GeoJSON (WGS84).",
      "title": "Geojson"
    },
    "area_km2": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Area Km2"
    },
    "vertex_count": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Vertex Count"
    },
    "valid": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Set by op=validate: whether the input geometry is valid.",
      "title": "Valid"
    },
    "validity_reason": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Set by op=validate when invalid: what is wrong and where.",
      "title": "Validity Reason"
    }
  },
  "required": [
    "success",
    "op"
  ],
  "title": "AoiResult",
  "type": "object"
}

# measure read

Measure great-circle distance along a path, geometry area, line length, centroid, or point-in-polygon containment.

Full description
Measure distances, areas, lengths, centroids, and containment on WGS84 geometry.

- distance: great-circle (haversine, spherical-earth ~0.3% accuracy)
  length along a path of 2-100 points — straight-line, not travel
  distance; use the route tool for routed walk/drive/bike distance
- area: area in km² and m² plus perimeter_km (local projected plane;
  antimeridian-spanning and near-polar geometry rejected)
- length: length of LineString/MultiLineString geometry (e.g. a
  boundary segment from make_aoi boundary_to_line + intersect), or
  boundary length of polygonal geometry
- centroid: planar centroid in lat/lon degree space; can fall outside
  concave or multi-part shapes
- contains: whether a geometry covers a point (boundary counts)

Geometry ops accept inline GeoJSON or an OSM reference (osm_type +
osm_id): with a reference the shape is fetched server-side and only the
numbers return, so large boundaries never pass through the
conversation ("how big is this park" is one small call). Pass
simplify_tolerance_m to measure a simplified version of the shape —
comparing original vs simplified area is two small calls, no GeoJSON
shuttling. Geometry math runs in-Lambda; references fetch from the
public Overpass API.
Parameter Type Required Description
op "distance" | "area" | "length" | "centroid" | "contains" Yes Measurement to perform.
points array<Coordinate> | null No Path of points for op=distance (great-circle, summed leg by leg).
geometry object | null No GeoJSON geometry (for area, centroid, contains). Alternatively pass osm_type + osm_id.
osm_type "node" | "way" | "relation" | null No With osm_id: measure an OSM object directly by reference; its shape is fetched server-side, so no GeoJSON needs to pass through the conversation.
osm_id integer | null No OSM object id (with osm_type).
point Coordinate | null No Test point for op=contains.
simplify_tolerance_m number | null No Douglas-Peucker simplify the geometry (topology-preserving) before measuring. With an OSM reference this compares original vs simplified in two small calls without any GeoJSON passing through the conversation.
Parameter schema (JSON)
{
  "$defs": {
    "Coordinate": {
      "properties": {
        "lat": {
          "description": "Latitude in WGS84 decimal degrees.",
          "maximum": 90,
          "minimum": -90,
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "description": "Longitude in WGS84 decimal degrees.",
          "maximum": 180,
          "minimum": -180,
          "title": "Lon",
          "type": "number"
        }
      },
      "required": [
        "lat",
        "lon"
      ],
      "title": "Coordinate",
      "type": "object",
      "additionalProperties": false
    }
  },
  "properties": {
    "op": {
      "description": "Measurement to perform.",
      "enum": [
        "distance",
        "area",
        "length",
        "centroid",
        "contains"
      ],
      "title": "Op",
      "type": "string"
    },
    "points": {
      "anyOf": [
        {
          "items": {
            "$ref": "#/$defs/Coordinate"
          },
          "maxItems": 100,
          "minItems": 2,
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Path of points for op=distance (great-circle, summed leg by leg).",
      "title": "Points"
    },
    "geometry": {
      "anyOf": [
        {
          "additionalProperties": true,
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "GeoJSON geometry (for area, centroid, contains). Alternatively pass osm_type + osm_id.",
      "title": "Geometry"
    },
    "osm_type": {
      "anyOf": [
        {
          "enum": [
            "node",
            "way",
            "relation"
          ],
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "With osm_id: measure an OSM object directly by reference; its shape is fetched server-side, so no GeoJSON needs to pass through the conversation.",
      "title": "Osm Type"
    },
    "osm_id": {
      "anyOf": [
        {
          "minimum": 1,
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "OSM object id (with osm_type).",
      "title": "Osm Id"
    },
    "point": {
      "anyOf": [
        {
          "$ref": "#/$defs/Coordinate"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Test point for op=contains."
    },
    "simplify_tolerance_m": {
      "anyOf": [
        {
          "exclusiveMinimum": 0,
          "maximum": 10000,
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Douglas-Peucker simplify the geometry (topology-preserving) before measuring. With an OSM reference this compares original vs simplified in two small calls without any GeoJSON passing through the conversation.",
      "title": "Simplify Tolerance M"
    }
  },
  "required": [
    "op"
  ],
  "title": "MeasureParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "properties": {
    "success": {
      "title": "Success",
      "type": "boolean"
    },
    "op": {
      "title": "Op",
      "type": "string"
    },
    "distance_m": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Distance M"
    },
    "distance_km": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Distance Km"
    },
    "area_km2": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Area Km2"
    },
    "area_m2": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Area M2"
    },
    "perimeter_km": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Boundary length for op=area, including holes and islands.",
      "title": "Perimeter Km"
    },
    "length_km": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "For op=length: line length of linear geometry, or boundary length of polygonal geometry.",
      "title": "Length Km"
    },
    "length_m": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "title": "Length M"
    },
    "lat": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Centroid latitude for op=centroid.",
      "title": "Lat"
    },
    "lon": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Centroid longitude for op=centroid.",
      "title": "Lon"
    },
    "contains": {
      "anyOf": [
        {
          "type": "boolean"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Whether the geometry covers the point (boundary counts as inside).",
      "title": "Contains"
    }
  },
  "required": [
    "success",
    "op"
  ],
  "title": "MeasureResult",
  "type": "object"
}

# query_features read

Find OpenStreetMap features by tag within a radius, bbox, named area, or boundary referenced by OSM id via the Overpass API (no key needed).

Full description
Find OpenStreetMap features matching tag filters in a bounded area.

Tag filters are AND-combined (up to 6), e.g. leisure=pitch + sport=tennis.
Center+radius results carry distance_m and are sorted nearest-first
(within the returned page; if `truncated` is set, narrow the radius for
a guaranteed nearest-N).
Values are checked against real OSM vocabulary: common misnomers are
auto-corrected (leisure=tennis_court is interpreted as leisure=pitch +
sport=tennis and reported in `note`), unknown values for well-known keys
fail fast with suggestions, and multi-value keys like sport match
semicolon lists (sport=tennis;basketball). Search within exactly one of:
center + radius_m (max 30km), bbox [west, south, east, north] (max
~2500 km²), area_name (an exact, case-sensitive OSM area name like
'Edmonds', resolved by Overpass itself, so no geocoding key is required;
the place must exist as an OSM area, i.e. a boundary relation or closed
way), or area_osm_type + area_osm_id (search inside one specific
boundary by OSM reference — the reliable path for "all X in <city>":
geocode the city or find its admin boundary, then pass its relation id
here; names collide across the planet, ids do not).
Runs on the public Overpass API with automatic endpoint failover.
geometry='center' (default) returns one point per feature;
geometry='full' adds real geometry as GeoJSON, suitable as AOI input;
geometry='merged' unions all matched polygonal features server-side
into one merged_geojson AOI (with merged_area_km2 and
merged_vertex_count) while individual features stay compact — "all parks in a city as one buffered AOI" is
then one query plus one make_aoi buffer_geometry call, with no
geometry shuttling through the conversation. include_area=true adds
area_km2 per polygonal feature in any mode, so "largest park in X" is
one call. Use simplify_tolerance_m
or max_points_per_feature to compress large shapes (lakes, boundaries)
without losing their form. Restricted
features (access=private/no) are included with their access tag
visible; filter by that tag when the user wants visitable places, or
set exclude_private=true. Results carry OpenStreetMap ODbL attribution
that must be shown when data is displayed publicly.
Parameter Type Required Description
tags array<TagFilter> Yes Tag filters, AND-combined. E.g. [{key: 'leisure', value: 'pitch'}, {key: 'sport', value: 'tennis'}].
center Coordinate | null No Search center; requires radius_m. Exactly one of center+radius_m, bbox, or area_name.
radius_m integer | null No Search radius in meters around center (max 30km).
bbox array<number> | null No [west, south, east, north] in WGS84 degrees; max ~2500 km².
area_name string | null No Search inside the OSM area with this exact name (e.g. 'Edmonds'), resolved by Overpass itself; no geocoding key needed. Names are globally ambiguous — prefer area_osm_type + area_osm_id when you hold the boundary's OSM reference.
area_osm_type "way" | "relation" | null No With area_osm_id: search inside one specific OSM area by reference (e.g. an admin boundary relation from geocode or an earlier query). Unambiguous, unlike area_name.
area_osm_id integer | null No OSM object id of the boundary to search inside (with area_osm_type).
exclude_private boolean No Server-side exclusion of features tagged access=private/no. Off by default: results include restricted features with their access tag visible, so filter contextually (e.g. drop access=private when the user wants places they can visit). Set true to exclude them outright. Default: false
geometry "center" | "full" | "merged" No 'center' returns one point per feature (compact); 'full' adds actual geometry as GeoJSON for AOI use; 'merged' unions all matched polygonal features server-side into one AOI (merged_geojson, with merged_area_km2 and merged_vertex_count) while individual features stay compact — the zero-shuttle path for 'all X in an area as one AOI'. Default: "center"
include_area boolean No Compute area_km2 per polygonal feature (null for nodes/lines), so size questions like 'largest park' are one call. Fetches geometry server-side even with geometry='center'; the response stays compact. Default: false
limit integer No Maximum features to return. Default: 50
simplify_tolerance_m number | null No With geometry='full': Douglas-Peucker simplify each shape to this tolerance in meters (10-25 keeps shapes visually intact at ~10-20% of the points).
max_points_per_feature integer No With geometry='full': adaptively simplify each shape to at most this many points. Default 100 keeps multi-feature responses renderable; for one precise boundary raise this, or take the osm_id to lookup_place (default 2000) or measure. Default: 100
Parameter schema (JSON)
{
  "$defs": {
    "Coordinate": {
      "properties": {
        "lat": {
          "description": "Latitude in WGS84 decimal degrees.",
          "maximum": 90,
          "minimum": -90,
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "description": "Longitude in WGS84 decimal degrees.",
          "maximum": 180,
          "minimum": -180,
          "title": "Lon",
          "type": "number"
        }
      },
      "required": [
        "lat",
        "lon"
      ],
      "title": "Coordinate",
      "type": "object",
      "additionalProperties": false
    },
    "TagFilter": {
      "properties": {
        "key": {
          "description": "OSM tag key, e.g. 'leisure', 'amenity', 'sport'.",
          "minLength": 1,
          "title": "Key",
          "type": "string"
        },
        "value": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "OSM tag value, e.g. 'tennis'. Omit to match any feature that has the key. Common natural-language misnomers are auto-corrected (e.g. leisure=tennis_court becomes leisure=pitch + sport=tennis, amenity=gas_station becomes amenity=fuel) and reported in the response note; unknown values for well-known keys fail fast with suggestions.",
          "title": "Value"
        }
      },
      "required": [
        "key"
      ],
      "title": "TagFilter",
      "type": "object",
      "additionalProperties": false
    }
  },
  "properties": {
    "tags": {
      "description": "Tag filters, AND-combined. E.g. [{key: 'leisure', value: 'pitch'}, {key: 'sport', value: 'tennis'}].",
      "items": {
        "$ref": "#/$defs/TagFilter"
      },
      "maxItems": 6,
      "minItems": 1,
      "title": "Tags",
      "type": "array"
    },
    "center": {
      "anyOf": [
        {
          "$ref": "#/$defs/Coordinate"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Search center; requires radius_m. Exactly one of center+radius_m, bbox, or area_name."
    },
    "radius_m": {
      "anyOf": [
        {
          "maximum": 30000,
          "minimum": 1,
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Search radius in meters around center (max 30km).",
      "title": "Radius M"
    },
    "bbox": {
      "anyOf": [
        {
          "items": {
            "type": "number"
          },
          "maxItems": 4,
          "minItems": 4,
          "type": "array"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "[west, south, east, north] in WGS84 degrees; max ~2500 km².",
      "title": "Bbox"
    },
    "area_name": {
      "anyOf": [
        {
          "minLength": 1,
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Search inside the OSM area with this exact name (e.g. 'Edmonds'), resolved by Overpass itself; no geocoding key needed. Names are globally ambiguous — prefer area_osm_type + area_osm_id when you hold the boundary's OSM reference.",
      "title": "Area Name"
    },
    "area_osm_type": {
      "anyOf": [
        {
          "enum": [
            "way",
            "relation"
          ],
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "With area_osm_id: search inside one specific OSM area by reference (e.g. an admin boundary relation from geocode or an earlier query). Unambiguous, unlike area_name.",
      "title": "Area Osm Type"
    },
    "area_osm_id": {
      "anyOf": [
        {
          "minimum": 1,
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "OSM object id of the boundary to search inside (with area_osm_type).",
      "title": "Area Osm Id"
    },
    "exclude_private": {
      "default": false,
      "description": "Server-side exclusion of features tagged access=private/no. Off by default: results include restricted features with their access tag visible, so filter contextually (e.g. drop access=private when the user wants places they can visit). Set true to exclude them outright.",
      "title": "Exclude Private",
      "type": "boolean"
    },
    "geometry": {
      "default": "center",
      "description": "'center' returns one point per feature (compact); 'full' adds actual geometry as GeoJSON for AOI use; 'merged' unions all matched polygonal features server-side into one AOI (merged_geojson, with merged_area_km2 and merged_vertex_count) while individual features stay compact — the zero-shuttle path for 'all X in an area as one AOI'.",
      "enum": [
        "center",
        "full",
        "merged"
      ],
      "title": "Geometry",
      "type": "string"
    },
    "include_area": {
      "default": false,
      "description": "Compute area_km2 per polygonal feature (null for nodes/lines), so size questions like 'largest park' are one call. Fetches geometry server-side even with geometry='center'; the response stays compact.",
      "title": "Include Area",
      "type": "boolean"
    },
    "limit": {
      "default": 50,
      "description": "Maximum features to return.",
      "maximum": 200,
      "minimum": 1,
      "title": "Limit",
      "type": "integer"
    },
    "simplify_tolerance_m": {
      "anyOf": [
        {
          "exclusiveMinimum": 0,
          "maximum": 10000,
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "With geometry='full': Douglas-Peucker simplify each shape to this tolerance in meters (10-25 keeps shapes visually intact at ~10-20% of the points).",
      "title": "Simplify Tolerance M"
    },
    "max_points_per_feature": {
      "default": 100,
      "description": "With geometry='full': adaptively simplify each shape to at most this many points. Default 100 keeps multi-feature responses renderable; for one precise boundary raise this, or take the osm_id to lookup_place (default 2000) or measure.",
      "maximum": 50000,
      "minimum": 8,
      "title": "Max Points Per Feature",
      "type": "integer"
    }
  },
  "required": [
    "tags"
  ],
  "title": "QueryFeaturesParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "Feature": {
      "properties": {
        "osm_type": {
          "title": "Osm Type",
          "type": "string"
        },
        "osm_id": {
          "title": "Osm Id",
          "type": "integer"
        },
        "name": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Name"
        },
        "lat": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Representative point (node location or bounds center).",
          "title": "Lat"
        },
        "lon": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Lon"
        },
        "distance_m": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Great-circle distance from the query center in meters (center+radius queries only).",
          "title": "Distance M"
        },
        "area_km2": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Feature area with include_area=true; null for non-polygonal features.",
          "title": "Area Km2"
        },
        "tags": {
          "additionalProperties": {
            "type": "string"
          },
          "title": "Tags",
          "type": "object"
        },
        "geojson": {
          "anyOf": [
            {
              "additionalProperties": true,
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Feature geometry as GeoJSON when geometry='full'.",
          "title": "Geojson"
        }
      },
      "required": [
        "osm_type",
        "osm_id"
      ],
      "title": "Feature",
      "type": "object"
    }
  },
  "properties": {
    "success": {
      "title": "Success",
      "type": "boolean"
    },
    "attribution": {
      "title": "Attribution",
      "type": "string"
    },
    "count": {
      "title": "Count",
      "type": "integer"
    },
    "truncated": {
      "default": false,
      "description": "True when more matches exist than `limit`; narrow the area or raise the limit.",
      "title": "Truncated",
      "type": "boolean"
    },
    "note": {
      "anyOf": [
        {
          "type": "string"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Caveat about the result, e.g. when an area_name search returns nothing.",
      "title": "Note"
    },
    "merged_geojson": {
      "anyOf": [
        {
          "additionalProperties": true,
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "With geometry='merged': union of all matched polygonal features as one AOI (compressed to ~2000 points), ready for make_aoi buffer_geometry or measure.",
      "title": "Merged Geojson"
    },
    "merged_area_km2": {
      "anyOf": [
        {
          "type": "number"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Area of merged_geojson in km².",
      "title": "Merged Area Km2"
    },
    "merged_vertex_count": {
      "anyOf": [
        {
          "type": "integer"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Vertex count of merged_geojson as returned (after compression); confirms simplification without inspecting the GeoJSON.",
      "title": "Merged Vertex Count"
    },
    "features": {
      "items": {
        "$ref": "#/$defs/Feature"
      },
      "title": "Features",
      "type": "array"
    }
  },
  "required": [
    "success",
    "attribution",
    "count",
    "features"
  ],
  "title": "QueryFeaturesResult",
  "type": "object"
}

# reverse_geocode read

Batch reverse geocode up to 25 coordinates to addresses via LocationIQ or Geoapify.

Full description
Reverse geocode coordinates to addresses with normalized components.

Runs up to 25 coordinate pairs in one call against the provider chosen
with `source` (the matching API key must be configured for the Geo
toolkit). `zoom` controls granularity from country (3) to building (18).
Address components (street, city, state, postcode, country, ...) are
normalized to the same keys regardless of provider. Calls are paced to
the provider's free-tier rate limit; if the provider still returns 429,
remaining coordinates are skipped and `rate_limited` is set. Results
include OpenStreetMap/provider attribution that must be shown when data
is displayed publicly.
Parameter Type Required Description
coordinates array<Coordinate> Yes Coordinates to reverse geocode. Up to 25 per call.
source "locationiq" | "geoapify" Yes Geocoding provider to use. Requires that provider's API key to be configured for the Geo toolkit.
zoom integer No Result granularity: 3 country, 5 state, 10 city, 14 suburb, 16 street, 18 building. LocationIQ honors all levels; Geoapify only supports country/state/city/street steps, so intermediate zooms map to the nearest coarser level (e.g. 14 returns city-level). Default: 18
Parameter schema (JSON)
{
  "$defs": {
    "Coordinate": {
      "properties": {
        "lat": {
          "description": "Latitude in WGS84 decimal degrees.",
          "maximum": 90,
          "minimum": -90,
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "description": "Longitude in WGS84 decimal degrees.",
          "maximum": 180,
          "minimum": -180,
          "title": "Lon",
          "type": "number"
        }
      },
      "required": [
        "lat",
        "lon"
      ],
      "title": "Coordinate",
      "type": "object",
      "additionalProperties": false
    }
  },
  "properties": {
    "coordinates": {
      "description": "Coordinates to reverse geocode. Up to 25 per call.",
      "items": {
        "$ref": "#/$defs/Coordinate"
      },
      "maxItems": 25,
      "minItems": 1,
      "title": "Coordinates",
      "type": "array"
    },
    "source": {
      "description": "Geocoding provider to use. Requires that provider's API key to be configured for the Geo toolkit.",
      "enum": [
        "locationiq",
        "geoapify"
      ],
      "title": "Source",
      "type": "string"
    },
    "zoom": {
      "default": 18,
      "description": "Result granularity: 3 country, 5 state, 10 city, 14 suburb, 16 street, 18 building. LocationIQ honors all levels; Geoapify only supports country/state/city/street steps, so intermediate zooms map to the nearest coarser level (e.g. 14 returns city-level).",
      "maximum": 18,
      "minimum": 3,
      "title": "Zoom",
      "type": "integer"
    }
  },
  "required": [
    "coordinates",
    "source"
  ],
  "title": "ReverseGeocodeParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "$defs": {
    "GeocodeMatch": {
      "properties": {
        "lat": {
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "title": "Lon",
          "type": "number"
        },
        "display_name": {
          "title": "Display Name",
          "type": "string"
        },
        "bbox": {
          "anyOf": [
            {
              "items": {
                "type": "number"
              },
              "type": "array"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "[west, south, east, north] in WGS84 degrees.",
          "title": "Bbox"
        },
        "osm_type": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "OSM object type: node, way, or relation.",
          "title": "Osm Type"
        },
        "osm_id": {
          "anyOf": [
            {
              "type": "integer"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Osm Id"
        },
        "category": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "OSM class, e.g. 'place', 'amenity', 'boundary'.",
          "title": "Category"
        },
        "type": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "OSM type within the class, e.g. 'city', 'restaurant'.",
          "title": "Type"
        },
        "importance": {
          "anyOf": [
            {
              "type": "number"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Relative importance score when the provider supplies one.",
          "title": "Importance"
        },
        "address": {
          "additionalProperties": {
            "type": "string"
          },
          "description": "Normalized address components.",
          "title": "Address",
          "type": "object"
        },
        "geojson": {
          "anyOf": [
            {
              "additionalProperties": true,
              "type": "object"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "description": "Boundary geometry as GeoJSON when include_geojson is set and available.",
          "title": "Geojson"
        }
      },
      "required": [
        "lat",
        "lon",
        "display_name"
      ],
      "title": "GeocodeMatch",
      "type": "object"
    },
    "ReverseGeocodeItemResult": {
      "properties": {
        "lat": {
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "title": "Lon",
          "type": "number"
        },
        "match": {
          "anyOf": [
            {
              "$ref": "#/$defs/GeocodeMatch"
            },
            {
              "type": "null"
            }
          ],
          "default": null
        },
        "error": {
          "anyOf": [
            {
              "type": "string"
            },
            {
              "type": "null"
            }
          ],
          "default": null,
          "title": "Error"
        }
      },
      "required": [
        "lat",
        "lon"
      ],
      "title": "ReverseGeocodeItemResult",
      "type": "object"
    }
  },
  "properties": {
    "success": {
      "title": "Success",
      "type": "boolean"
    },
    "source": {
      "title": "Source",
      "type": "string"
    },
    "attribution": {
      "title": "Attribution",
      "type": "string"
    },
    "rate_limited": {
      "default": false,
      "description": "True when the provider rate limit was hit and remaining coordinates were skipped.",
      "title": "Rate Limited",
      "type": "boolean"
    },
    "results": {
      "items": {
        "$ref": "#/$defs/ReverseGeocodeItemResult"
      },
      "title": "Results",
      "type": "array"
    }
  },
  "required": [
    "success",
    "source",
    "attribution",
    "results"
  ],
  "title": "ReverseGeocodeResult",
  "type": "object"
}

# route read

Route between 2-10 waypoints on the real road/path network (walk, drive, bike) via LocationIQ or Geoapify: routed distance and travel time, not straight-line.

Full description
Route between waypoints on the real road/path network.

Returns routed travel distance and estimated duration for walk, drive,
or bike between 2-10 waypoints visited in order — unlike measure's
distance op, which is straight-line. Uses the provider chosen with
`source` (the matching API key must be configured for the Geo toolkit):
LocationIQ Directions or Geoapify Routing, normalized to one result
shape. Set include_geometry for the route line as GeoJSON (e.g. to map
the walk). Results include provider attribution that must be shown when
data is displayed publicly.
Parameter Type Required Description
waypoints array<Coordinate> Yes Waypoints routed in order (2-10): start, optional vias, end.
mode "walk" | "drive" | "bike" No Travel mode: walk, drive, or bike. Default: "walk"
source "locationiq" | "geoapify" Yes Routing provider to use. Requires that provider's API key to be configured for the Geo toolkit.
include_geometry boolean No Include the route line as GeoJSON. Default: false
Parameter schema (JSON)
{
  "$defs": {
    "Coordinate": {
      "properties": {
        "lat": {
          "description": "Latitude in WGS84 decimal degrees.",
          "maximum": 90,
          "minimum": -90,
          "title": "Lat",
          "type": "number"
        },
        "lon": {
          "description": "Longitude in WGS84 decimal degrees.",
          "maximum": 180,
          "minimum": -180,
          "title": "Lon",
          "type": "number"
        }
      },
      "required": [
        "lat",
        "lon"
      ],
      "title": "Coordinate",
      "type": "object",
      "additionalProperties": false
    }
  },
  "properties": {
    "waypoints": {
      "description": "Waypoints routed in order (2-10): start, optional vias, end.",
      "items": {
        "$ref": "#/$defs/Coordinate"
      },
      "maxItems": 10,
      "minItems": 2,
      "title": "Waypoints",
      "type": "array"
    },
    "mode": {
      "default": "walk",
      "description": "Travel mode: walk, drive, or bike.",
      "enum": [
        "walk",
        "drive",
        "bike"
      ],
      "title": "Mode",
      "type": "string"
    },
    "source": {
      "description": "Routing provider to use. Requires that provider's API key to be configured for the Geo toolkit.",
      "enum": [
        "locationiq",
        "geoapify"
      ],
      "title": "Source",
      "type": "string"
    },
    "include_geometry": {
      "default": false,
      "description": "Include the route line as GeoJSON.",
      "title": "Include Geometry",
      "type": "boolean"
    }
  },
  "required": [
    "waypoints",
    "source"
  ],
  "title": "RouteParams",
  "type": "object",
  "additionalProperties": false
}
Result schema (JSON)
{
  "properties": {
    "success": {
      "title": "Success",
      "type": "boolean"
    },
    "source": {
      "title": "Source",
      "type": "string"
    },
    "attribution": {
      "title": "Attribution",
      "type": "string"
    },
    "mode": {
      "title": "Mode",
      "type": "string"
    },
    "distance_m": {
      "description": "Routed travel distance in meters (not straight-line).",
      "title": "Distance M",
      "type": "number"
    },
    "distance_km": {
      "title": "Distance Km",
      "type": "number"
    },
    "duration_min": {
      "description": "Estimated travel time in minutes.",
      "title": "Duration Min",
      "type": "number"
    },
    "geojson": {
      "anyOf": [
        {
          "additionalProperties": true,
          "type": "object"
        },
        {
          "type": "null"
        }
      ],
      "default": null,
      "description": "Route line as GeoJSON when include_geometry is set.",
      "title": "Geojson"
    }
  },
  "required": [
    "success",
    "source",
    "attribution",
    "mode",
    "distance_m",
    "distance_km",
    "duration_min"
  ],
  "title": "RouteResult",
  "type": "object"
}