MapMatchResponse
Matched-route result. `geojson` carries the snapped LineString for small traces; longer traces return `geometry.encoded` (polyline6 — decode with @mapbox/polyline at precision 6). `match_status` and `coverage` report how much of the trace the matcher actually placed on the road network — `matched` alone only says a route was returned. Road names/classes and distances are surfaced; internal road-graph identifiers are never exposed.
Properties
| Name | Type | Description |
|---|---|---|
| matched | boolean | True when a route was returned for the trace. It does NOT mean the whole trace matched — use `match_status`. |
| distance_km | number | |
| duration_seconds | number | |
| confidence | number | 0–1: fraction of input GPS points within the snap tolerance of the matched route. A distance heuristic: it ignores point order and which parallel roadway was matched. For the matcher's own per-point r |
| road_names | array | |
| legs | array | |
| costing | string | |
| geojson | object | |
| geometry | object | |
| meta | object | |
| match_status | stringnull | Whole-trace match status from the matcher's own per-point results. `full`: every input point was matched or interpolated onto the road network AND the match is one continuous section. `none`: no input |
| coverage | object | Per-point coverage of the trace from the matcher's own per-point status — independent of the distance-based `confidence`. Every key is always present. |
JSON Schema
{
"$schema": "https://json-schema.org/draft/2020-12/schema",
"$id": "https://artifacts.apis.io/thinair-co/json-schema/thinair-co-map-match-response-schema.json",
"title": "MapMatchResponse",
"description": "Matched-route result. `geojson` carries the snapped LineString for small traces; longer traces return `geometry.encoded` (polyline6 — decode with @mapbox/polyline at precision 6). `match_status` and `coverage` report how much of the trace the matcher actually placed on the road network — `matched` alone only says a route was returned. Road names/classes and distances are surfaced; internal road-graph identifiers are never exposed.",
"x-generated": "2026-10-30",
"x-method": "derived",
"x-generator": "derive-json-schema.py",
"x-source": "openapi/geo-thinair-co-openapi.json#/components/schemas/MapMatchResponse",
"type": "object",
"properties": {
"matched": {
"type": "boolean",
"description": "True when a route was returned for the trace. It does NOT mean the whole trace matched — use `match_status`."
},
"distance_km": {
"type": "number"
},
"duration_seconds": {
"type": "number"
},
"confidence": {
"type": "number",
"description": "0–1: fraction of input GPS points within the snap tolerance of the matched route. A distance heuristic: it ignores point order and which parallel roadway was matched. For the matcher's own per-point result use `match_status` / `coverage`."
},
"road_names": {
"type": "array",
"items": {
"type": "string"
}
},
"legs": {
"type": "array",
"items": {
"type": "object",
"additionalProperties": {}
}
},
"costing": {
"type": "string"
},
"geojson": {
"type": "object",
"additionalProperties": {}
},
"geometry": {
"type": "object",
"additionalProperties": {}
},
"meta": {
"type": "object",
"properties": {
"upstream_ms": {
"type": "number"
},
"point_count": {
"type": "integer"
},
"breakage_distance_m": {
"type": "integer",
"description": "Echoes the breakage_distance_m the caller requested, for confirmation — present only when the caller set it. This is the value SENT to the matcher, not a claim about what it did with it."
}
},
"required": [
"upstream_ms",
"point_count"
],
"additionalProperties": {}
},
"match_status": {
"type": [
"string",
"null"
],
"enum": [
"full",
"partial",
"none",
null
],
"description": "Whole-trace match status from the matcher's own per-point results. `full`: every input point was matched or interpolated onto the road network AND the match is one continuous section. `none`: no input point was matched or interpolated. `partial`: anything else — some points unmatched, or the match broke into more than one section. null when the per-point check could not be completed; `coverage.unavailable_reason` says why. Gate on this field, not on `matched`."
},
"coverage": {
"type": "object",
"properties": {
"point_count": {
"type": "integer",
"description": "Number of input GPS points"
},
"matched_count": {
"type": "integer",
"description": "Input points the matcher placed on the road network directly. null when unavailable."
},
"interpolated_count": {
"type": "integer",
"description": "Input points the matcher placed on the road network by interpolating between matched neighbours; counted as covered. null when unavailable."
},
"unmatched_count": {
"type": "integer",
"description": "Input points the matcher could not place on the road network. null when unavailable."
},
"ratio": {
"type": [
"number",
"null"
],
"description": "0–1: (matched_count + interpolated_count) / point_count, rounded down to 3 decimals so a partial trace never reads 1. null when unavailable."
},
"unmatched_ranges": {
"type": [
"array",
"null"
],
"items": {
"type": "object",
"properties": {
"start_index": {
"type": "integer",
"description": "0-based index of the first unmatched input point in this run"
},
"end_index": {
"type": "integer",
"description": "0-based index of the last unmatched input point in this run (inclusive)"
},
"point_count": {
"type": "integer",
"description": "Number of input points in this run"
}
},
"required": [
"start_index",
"end_index",
"point_count"
],
"additionalProperties": {}
},
"description": "Contiguous runs of unmatched input points, as 0-based inclusive index ranges into `shape`, in trace order. Empty when every point was covered; null when unavailable."
},
"route_sections": {
"type": "integer",
"description": "Number of disjoint sections the match broke into (1 = continuous). When greater than 1, the returned geometry, distance and duration cover only the FIRST section — split the trace at the break and match the parts separately."
},
"unavailable_reason": {
"type": [
"string",
"null"
],
"enum": [
"upstream_error",
"timeout",
"no_point_status",
"point_count_mismatch",
"unknown_point_type",
null
],
"description": "Why the per-point counts and `match_status` are null: `upstream_error` (the per-point check failed), `timeout` (it did not answer in time), `no_point_status` (it answered without per-point results), `point_count_mismatch` (its results did not line up one-to-one with the input points), `unknown_point_type` (it reported a status this API does not recognise). null when coverage is available."
}
},
"required": [
"point_count",
"matched_count",
"interpolated_count",
"unmatched_count",
"ratio",
"unmatched_ranges",
"route_sections",
"unavailable_reason"
],
"additionalProperties": {},
"description": "Per-point coverage of the trace from the matcher's own per-point status — independent of the distance-based `confidence`. Every key is always present."
}
},
"required": [
"matched",
"distance_km",
"duration_seconds",
"confidence",
"road_names",
"legs",
"costing",
"meta",
"match_status",
"coverage"
],
"additionalProperties": {}
}
Work with this as data
Every JSON Schema here is available over the APIs.io API and to AI agents over MCP.
MCP server
One button, every client — Claude, Cursor, VS Code and the rest.
https://apis.io/mcp
Tools for schemas
4 MCP tools reach this
find_json_schemasBrowse and filter every JSON Schema in the catalog.apis_io_searchSTART HERE — APIs, providers and tags for one query, each with its total.resolveTurn a domain, URL or GitHub org into the provider it belongs to.find_cohortsEvery scored population of providers in the catalog.
Call it yourself
curl for this page
curl "https://apis.io/api/v1/json-schemas/thinair-co-map-match-response"
curl "https://apis.io/api/v1/json-schemas?limit=25"
Discovery needs no key. Ratings and market analysis are Pro.
Get an API key
Free tier, no form to fill in. Signing in shares your email address with us — we store it to create your key and to recognise you if you sign in with another provider. See our Privacy Policy and Terms.
A second provider on the same verified email joins the account you already have.