Skip to content
Route Enhancement API

Route Enhancement API

Use the Route Enhancement API to get the GeoJSON geometry of a GPX or KML file. You can extend it with elevation, road surface and highway type, travel time estimates, or turn-by-turn instructions by adding extra parameters.

Base URL

https://enhance.maptoolkit.net/route

Use a POST request when the geometry is large, otherwise a GET request.

Authentication

Add your API key as ?api_key=YOUR_API_KEY to every request. See Authentication for details.

Parameters

Route Data

ParameterTypeRequiredDescription
gpxURLYes (or kml/geometry)URL to a GPX file.
kmlURLYes (or gpx/geometry)URL to a KML file.
geometryGeoJSON stringYes (or gpx/kml)A GeoJSON LineString or MultiLineString.

Data to add

ParameterTypeRequiredDescription
elevation0 or 1NoInclude an elevation profile in the response. Default: 0.
surface0, 1 or objectNoInclude road surface and highway type data. Pass a JSON object to tune the map match. Default: 0.
timings0 or 1NoInclude travel time estimates. Default: 0.
mapmatch0 or 1NoInclude turn-by-turn directions matched to the road network. Default: 0.

Configuration Parameters

ParameterTypeRequiredDescription
routeTypestringNoVehicle type: car, bike, or foot.
languagestringNoLanguage for turn instructions, as a 2-letter code (e.g., en).
cache0 or 1NoUse cached results if available. Default: 1.
callbackstringNoWrap the response in a JSONP callback.

Response

GeoJSON from input route

GET https://enhance.maptoolkit.net/route?kml=https://maptoolkit.net/export/ts_demo_tours/_1603292819.kml&api_key=YOUR_API_KEY

Response:

{
  "geometry": {
    "type": "MultiLineString",
    "coordinates": [
      [
        [15.460422, 47.349047, 1181],
        [15.460593, 47.349027, 1179],
        ...
      ]
    ]
  }
}

Coordinates are [longitude, latitude, elevation_in_meters].

Add Elevation Data

GET https://enhance.maptoolkit.net/route?geometry={"type":"LineString","coordinates":[[10,50],[10.1,50.1]]}&elevation=1&api_key=YOUR_API_KEY

Response:

{
  "geometry": { "type": "MultiLineString", "coordinates": [[...]] },
  "elevation": [{
    "samples": [289, 292, 302, 305, 299],
    "distance": 13230.5,
    "ascent": 220,
    "descent": 160,
    "yrange": [200, 600],
    "labels": {
      "x": [[0, 0], [0.23, 3], [0.45, 6]],
      "y": [[0.25, 300], [0.5, 400], [0.75, 500]]
    }
  }]
}

Elevation samples are taken approximately every 100 meters. yrange gives the min/max values for the y-axis. Label values are relative positions (0-1) paired with the label value.

Add Surface Data

surface=1 returns the road surface and highway type under each part of the route, so you can tell a reader how much of a ride is asphalt and how much is gravel, colour a route line by what it runs on, or filter a set of tours down to the ones a road bike can handle.

GET https://enhance.maptoolkit.net/route?kml=https://example.com/route.kml&surface=1&api_key=YOUR_API_KEY

Response:

{
  "geometry": { "type": "MultiLineString", "coordinates": [[...]] },
  "surface": [[
    { "from": 0.053, "to": 0.088, "highway": "road", "surface": "asphalt" },
    { "from": 0.088, "to": 0.106, "highway": "road", "surface": "paved" },
    { "from": 0.106, "to": 0.241, "highway": "path", "surface": "unpaved" }
  ]]
}
FieldDescription
fromStart of this segment as a relative position along the route. 0 is the start, 1 is the end.
toEnd of this segment as a relative position along the route.
highwayRoad or path type for this segment.
surfaceSurface material for this segment.

surface is an array of arrays. There is one inner array per segment of the MultiLineString geometry, in the same order, so a route split into three segments returns three arrays. Reading response.surface[0] and assuming it covers the whole route is correct only for a single-segment route.

Positions are relative, not meters. from and to are fractions of the route, so turning a surface breakdown into distances means multiplying by the total length. Segments are contiguous and do not overlap, which makes a percentage breakdown a matter of summing to - from per surface value.

Tuning the map match

Surface data is not stored against your geometry. The service map-matches each part of the route onto the road network and reads the tags off whatever it matched. A recorded track that drifts, or a line drawn across open ground, can match a road it never touched.

surface therefore also accepts a JSON object instead of 1:

GET https://enhance.maptoolkit.net/route?kml=https://example.com/route.kml&surface={"mapMatchingThreshold":0.02}&api_key=YOUR_API_KEY
OptionTypeDescription
mapMatchingThresholdnumberLargest relative distance deviation that still counts as a match. A segment is classified as other when abs(1 - matchDistance / origDistance) reaches the threshold. Default: 0.05.

Lower the threshold to reject doubtful matches, which trades coverage for confidence and returns more other. Raise it when a clean track keeps coming back as other.

other in either field means no confident match, not an unusual road. Treat it as unknown rather than as a surface type, because presenting it as a real category is how a route ends up described as unpaved when nothing is known about it.

Highway types:

motorway, primary, road, street, pedestrian, cycleway, path, hiking, mountain_hiking, other

Surface types:

asphalt, paved, unpaved, natural, alpine, other

Add Travel Time Estimates

GET https://enhance.maptoolkit.net/route?geometry={"type":"LineString","coordinates":[[10,50],[10.1,50.1]]}&timings=1&api_key=YOUR_API_KEY

Response:

{
  "geometry": { "type": "MultiLineString", "coordinates": [[...]] },
  "timings": [{
    "walking": 300,
    "cycling": 100,
    "cycling_offroad": 110,
    "cycling_racing": 50
  }]
}

Times are in seconds, calculated from route distance and elevation.

Add Turn-by-Turn Directions

Map matching generates turn-by-turn directions matched to the road network.

GET https://enhance.maptoolkit.net/route?kml=https://example.com/route.kml&mapmatch=1&language=en&api_key=YOUR_API_KEY

Response:

{
  "geometry": { "type": "MultiLineString", "coordinates": [[...]] },
  "mapmatch": [[{
    "instructions": [{
      "distance": 336.799,
      "name": "Kaufbeurer Straße",
      "text": "Turn right onto Kaufbeurer Straße",
      "sign": 2,
      "time": 67357,
      "coordinate": [47.83471, 10.82657],
      "tags": { "surface": "asphalt", "highway": "road" }
    }],
    "geometry": {
      "type": "LineString",
      "coordinates": [[10.82623, 47.83423], ...]
    }
  }]]
}

Errors

Errors return the HTTP status code with a plain-text message in the body.

StatusMeaning
403The API key is missing (Access denied!) or not recognized (Api-key not found!). See First Steps.
400The geometry or a parameter could not be parsed, or an upstream service failed.

Common 400 messages

MessageCause
no valid geometry found, LineString & MultiLineString's are allowedgeometry is missing or has an unsupported GeoJSON type.
invalid geometry typeThe GeoJSON parsed, but is not a LineString or MultiLineString.
param '{name}' seems to be a JSON String, but it cannot be parsed: {message}A parameter value starts with { but is not valid JSON.
routing request failed: {message}The upstream surface or map-matching service returned an error.

Rate limits

Limits are monthly request quotas tied to your plan rather than a per-second rate: the service returns no RateLimit-* or Retry-After headers. Current allowances are on the pricing page.

The free Basic plan has a hard limit, so requests are refused once it is reached. On Pro and Ultra, requests past the allowance are billed rather than refused. Enterprise plans use a flexible limit.

Calls to this API count toward your plan’s API request allowance, which is the smaller of the two allowances.

Pricing

Self-service plans (Basic, Pro, and Ultra) are billed through RapidAPI; see RapidAPI for how to subscribe and authenticate. Plan limits and prices are listed on the Maptoolkit pricing page. Enterprise customers call the native hosts directly with a Maptoolkit API key.