---
title: "Exact counts and nameless pins along one route, its legs and its stops"
method: POST
path: "/v1/map/route"
tags: ["map"]
---

# Exact counts and nameless pins along one route, its legs and its stops

`POST /v1/map/route`

## Request

- Base URL: `https://api.offendersearch.app`
- URL: `https://api.offendersearch.app/v1/map/route`
- Auth: API key in header `X-API-Key`

Who is registered along a route: within a corridor either side of a line,
within a radius of each stop, or both. The answer is exact, never an
estimate and never partial.

Send the line as one of `path` (a GeoJSON LineString, or `[[lng, lat], …]`),
`points` (`[[lng, lat], …]`) or `polyline` (an encoded polyline: precision 5
for Google Directions `overview_polyline`, 6 for Mapbox Directions
`geometry: polyline6`). Without a line, two or more `stops` are joined by
straight lines.

The answer counts people per leg (between two stops) and per stop, places
every pin on the route (`distanceMiles`, `leg`, `alongMiles`) and next to
its nearest stop (`nearestStop`, `stopDistanceFeet`). People mapped only to
a ZIP code, city or county are counted separately under `approximate` and
never in `total`. **A route answer never carries a name**, on any plan; for
a labelled map, request a viewport at zoom 15 or closer. The record behind a
pin opens with `GET /v1/map/records/{markerId}`.

**Billing.** A route is billed as route units, each one map request:
`ceil(corridor miles) × width factor` when the corridor is measured (×1 up
to a 0.25-mile corridor) plus `ceil(stops / 10)` when stop radii are
measured, at least 1. A 17.42-mile bus route with a 0.1-mile corridor and 35
stops at 1,000 feet is 18 + 4 = 22 units. `detail=count` costs the same. A
`304`, test mode and any error response are free.

**Never partial.** More than 300 pins with `detail=full` is `422
route_too_many_people` with the exact counts and nothing charged; a route
through more addresses than one call counts exactly is `422
route_too_dense`; a read that fails is `503` with no result and nothing
charged.

**Caching.** `Cache-Control: private, max-age=300` and an `ETag`. Send it
back in `If-None-Match`: the same route asked again answers `304`, free.

**Auth.** A secret API key, or a map browser key (`os_map_pk_…`) from a
site on its list. A browser key must send `X-End-User`.

## Headers

- `X-End-User` string
- `If-None-Match` string

## Request body

- MapRouteRequest: The body of `POST /v1/map/route`, and of each entry in `POST /v1/map/routes`. Send at most one of `path`, `points` and `polyline`; without any, two or more `stops` are joined by straight lines.
  - `path` union: The line: a GeoJSON LineString (or a Feature holding one), or a list of `[lng, lat]` points. Up to 50,000 points; a longer line is simplified to within about 5 metres when it has more than 2,000.
    - object
    - array[]
      - number[]
  - `points` array[]: The line as `[[lng, lat], …]`: the same list `POST /v1/map/area` takes.
    - number[]
  - `polyline` string: The line as an encoded polyline: Google Directions `overview_polyline.points`, or a Mapbox, OSRM or Valhalla `polyline6` geometry.
  - `polylinePrecision` 5 | 6: 5 for Google, 6 for Mapbox, OSRM and Valhalla.
  - `stops` MapRouteStopInput[]: The stops, in route order: `{id, lng, lat}` objects, or `[lng, lat]` pairs. Walk: up to 50. Bus: up to 150.
    - `id` string: Your id for the stop, unique in the route. Left out: `s1`, `s2`, …
    - `lng` number, required
    - `lat` number, required
    - `label` string: Accepted and never echoed: answers name stops by `id` only.
  - `profile` 'walk' | 'bus': Sets the limits and the default stop radius: walk 15 miles, 50 stops, 500 feet; bus 60 miles, 150 stops, 1,000 feet.
  - `measure` 'corridor' | 'stops' | 'both': What is counted. Left out: `both` when `stopRadiusFeet` is sent (or `stops` when there is no line), otherwise `corridor`.
  - `corridorMiles` number: The distance either side of the line, in miles.
  - `stopRadiusFeet` number: The radius around each stop, in feet. Left out: 500 for walk, 1,000 for bus.
  - `parcelAllowanceFeet` number: Feet added to the stop radius, for the distance between a geocoded address point and its property line.
  - `detail` 'full' | 'count': `full` for counts and pins, `count` for counts only. The same price.
  - `format` 'json' | 'geojson': `geojson` answers a single route as a FeatureCollection.
  - `housing` union: As on `GET /v1/map/viewport`. A comma-separated string or a list.
    - string
    - string[]
  - `precision` 'street' | 'any': `street` leaves out the people counted under `approximate`.
  - `sandbox` boolean: `true` answers in test mode.
  - `externalId` string: Your own id for the route, echoed in the answer.

## Response `200`

The answer for this route.

- MapRouteResponse: The answer for one route (`format=json`), and each entry of a `POST /v1/map/routes` answer.
  - `routeIndex` integer: In a `POST /v1/map/routes` answer only: the route's position in the request, from 0.
  - `shape` 'route'
  - `profile` 'walk' | 'bus'
  - `measure` 'corridor' | 'stops' | 'both'
  - `detail` 'full' | 'count'
  - `datasetVersion` string, date
  - `complete` boolean: Always `true`: a route is answered whole or refused.
  - `lengthMiles` number
  - `corridorMiles` number, nullable: `null` when the corridor is not measured.
  - `stopRadiusFeet` number, nullable: `null` when stops are not measured.
  - `parcelAllowanceFeet` number, nullable: `null` when stops are not measured.
  - `units` integer: Route units: the map requests this route is billed as.
  - `tilesRead` integer: Zoom-14 map tiles the route touches.
  - `total` integer: Distinct people with a street address in the corridor or a stop's reach.
  - `corridorTotal` integer, nullable: People in the corridor. `null` when it is not measured.
  - `stopsTotal` integer, nullable: People within reach of any stop. `null` when stops are not measured.
  - `breakdown` MapBreakdown: Of a count: how many have an exact street address, and housing status where the registry states it.
    - `street` integer: People with an exact street address.
    - `housed` integer
    - `homeless` integer
    - `incarcerated` integer
  - `legs` MapRouteLeg[]
    - `leg` integer: From 1.
    - `fromStop` string, nullable
    - `toStop` string, nullable
    - `lengthMiles` number
    - `count` integer: People in the corridor whose nearest point of the line is on this leg.
  - `stops` MapRouteStop[]
    - `stopId` string
    - `alongMiles` number, nullable: Miles from the start of the line. `null` with no line.
    - `count` integer, nullable: People within the stop's reach. `null` when stops are not measured.
    - `nearestFeet` integer, nullable: Feet to the closest of them. `null` when there is none.
    - `markerIds` string[]: With `detail=full` when stops are measured: the marker and group ids within reach.
  - `markers` MapRouteMarker[]
    - `id` string: Marker id (`mk_…`). Opens with `GET /v1/map/records/{markerId}`. Works for 24 hours.
    - `lat` number
    - `lng` number
    - `precision` 'street'
    - `addressType` 'home' | 'work' | 'school' | 'other'
    - `distanceMiles` number: Straight-line miles from the address to the line.
    - `leg` integer: The leg the nearest point of the line is on, from 1.
    - `alongMiles` number: Miles from the start of the line to its nearest point.
    - `nearestStop` string: The `id` of the closest stop.
    - `stopDistanceFeet` integer: Straight-line feet to that stop.
  - `groups` MapRouteGroup[]
    - `groupId` string: Group id (`mg_…`) for `GET /v1/map/groups/{groupId}`.
    - `lat` number
    - `lng` number
    - `precision` 'street'
    - `count` integer: People at this address.
    - `distanceMiles` number
    - `leg` integer
    - `alongMiles` number
    - `nearestStop` string
    - `stopDistanceFeet` integer
  - `approximate` object: People mapped only to a ZIP code, city or county. Never in `total`.
    - `count` integer
    - `areas` MapRouteArea[]
      - `groupId` string: Group id (`mg_…`) for `GET /v1/map/groups/{groupId}`.
      - `lat` number
      - `lng` number
      - `precision` 'zip' | 'city' | 'county'
      - `place` string: The area's name.
      - `count` integer
  - `unplaced` MapUnplaced: People in the states this view touches who have no mappable address.
    - `count` integer
    - `states` string[]
  - `externalId` string: Your `externalId`, when sent.
  - `sandbox` boolean: Present and `true` on a test-mode answer.
  - `notice` string
  - `routeNotice` string: How distances and counts are measured, as a sentence to show.

## Other responses

- `304`: The same route was asked within the `ETag`'s life. No body, not billed.
- `401`: Missing or invalid credential.
- `403`: `map_not_enabled` — the Map API is off for this account. `map_paused` — paused by us. `origin_not_allowed` — a browser key used from a site not on its list.
- `422`: The route was refused, with nothing charged. `detail.code` is one of `invalid_route`, `invalid_path`, `invalid_polyline`, `invalid_profile`, `invalid_measure`, `invalid_corridor`, `invalid_radius`, `invalid_stops`, `invalid_detail`, `invalid_format`, `invalid_filter`, `route_too_long`, `route_too_many_points`, `route_too_many_stops`, `route_too_dense`, `route_too_many_people` (with `counts` and `maxMarkers`) or `end_user_required`.
- `429`: `map_sweep_limit` — the account's daily area budget is used; clusters still work. `map_end_user_limit` — one end user's daily area budget is used. `map_end_user_route_limit` — one end user has checked their daily number of different routes. `map_open_limit` — the daily limit on record opens. `map_busy` — too many map requests at once (`Retry-After: 1`). `overloaded` — the service is at capacity (`Retry-After` set).
- `503`: `map_index_not_ready`, `map_unavailable` or `map_not_configured`. Retry.

## Changes

- **2026-10-18** `ba0f53153e6e`: 1 info
  - endpoint added

[Operation history](https://skmtc.dev/offendersearch/apis/offendersearch-api/changes/v1/map/route/post.md)

---

[API](https://skmtc.dev/offendersearch/apis/offendersearch-api.md) · [All operations](https://skmtc.dev/offendersearch/apis/offendersearch-api/llms.txt) · [OpenAPI document](https://skmtc.dev/offendersearch/apis/offendersearch-api/revisions/9b2562318a07?raw)
