# Sex offender map API reference

> Every Offender Map API endpoint with its request and response fields, and every object it returns: clusters, pins, groups, areas, the record and the plan.

- **HTML:** https://offendersearch.app/docs/map/api-reference
- **Base URL (live):** https://api.offendersearch.app — live keys (`os_live_…`)
- **Base URL (sandbox):** https://sandbox.offendersearch.app — test keys (`os_test_…`), never billed; see https://offendersearch.app/docs/map/sandbox.md
- **Authentication:** `X-API-Key` request header
- **Map API reference as markdown:** https://offendersearch.app/docs/map.md

Nine endpoints and the objects they send and return. Each endpoint below links to its Request and Response tables, and each object to the one table that defines it; every other page links to the same tables, so a field is described in one place.

All nine take a secret key in `X-API-Key`. The seven map read routes (viewport, area, route, routes, groups, records and status) also take a map browser key from a site on that key’s list (see [Access & keys](https://offendersearch.app/docs/map/access.md)); on the route routes a browser key also sends `X-End-User`. `sandbox=true` answers the viewport, area and route routes in [test mode](https://offendersearch.app/docs/map/test-mode.md), and the ids a test-mode answer returns keep the groups and records routes in test mode. The opened record is the same object the search API returns: [The Record object](https://offendersearch.app/docs/record-object.md).

## Sex offender map API endpoints

Every Map API route, with what it does. Each one opens its Request and Response tables: every field, its type, default and an example.

| Endpoint | What it does |
| --- | --- |
| [`GET /v1/map/viewport`](https://offendersearch.app/docs/map/viewport#reference-get-v1-map-viewport) | **Map view.** What to draw for one map view: clusters, pins or named pins of registered sex offenders. Send the view as `bbox`, or as `center` with `radiusMiles`. One map request per answer, whatever the view holds; a `304`, test mode and errors are free. |
| [`POST /v1/map/area`](https://offendersearch.app/docs/map/drawn-areas#reference-post-v1-map-area) | **Drawn area.** Everyone inside a drawn shape: a polygon, or a route with a buffer either side. The answer is the viewport answer for the shape's bounding box, limited to what is inside the shape, plus `shape`. One map request per answer; test mode and errors are free. An area answer carries no `ETag`. |
| [`POST /v1/map/route`](https://offendersearch.app/docs/map/routes#reference-post-v1-map-route) | **Route.** Exact counts and nameless pins along one route: within a corridor either side of a line, within a radius of each stop, or both, per leg and per stop. Billed as route units, each one map request; `detail=count` costs the same; a `304`, test mode and errors are free. Never partial: a route is answered whole or refused with nothing charged. |
| [`POST /v1/map/routes`](https://offendersearch.app/docs/map/routes#reference-post-v1-map-routes) | **Routes in a batch.** Up to 50 routes in one call, answered all or nothing: any refused route refuses the batch, with its `routeIndex`, and nothing is billed. Billed as the sum of the routes' units. Every marker shares one response, so a person near several routes is one record open. |
| [`GET /v1/map/groups/{groupId}`](https://offendersearch.app/docs/map/clusters-and-markers#reference-get-v1-map-groups) | **Group members.** One page of the people behind a many-people pin or an approximate-area pin. One map request per page; test mode and errors are free. |
| [`GET /v1/map/records/{markerId}`](https://offendersearch.app/docs/map/open-a-record#reference-get-v1-map-records) | **Open a record.** The complete record behind a marker or a saved reference. One record open per person per map response, at the account's rate ($0.035 by default): the same marker id again is free, and so is a reference within 24 hours of an open. `record_no_longer_listed`, test mode and errors are not billed. |
| [`GET /v1/map/status`](https://offendersearch.app/docs/map/turn-it-on#reference-get-v1-map-status) | **Plan and usage.** The Map API plan, rates, limits and this month's usage. Free, and it answers for an account whose Map API is off: it is how a client finds out that it is. |
| [`POST /v1/map/enable`](https://offendersearch.app/docs/map/turn-it-on#reference-post-v1-map-enable) | **Turn it on.** Turn the Map API on. Any paying business account can, with a secret key or an account admin's dashboard session. The monthly minimum is charged to the card at that moment and covers the current calendar month; if the charge fails, nothing is turned on. On an account that is already on it changes nothing and charges nothing. |
| [`POST /v1/map/disable`](https://offendersearch.app/docs/map/turn-it-on#reference-post-v1-map-disable) | **Turn it off.** Turn the Map API off. Free. The map routes stop within seconds; test mode keeps working. The month stays a minimum month, a minimum already paid is not refunded, and turning it on again in the same month charges nothing more. |

## Sex offender map API objects

Every object the Map API returns, defined once. A field whose type is one of these links here.

| Object | What it is |
| --- | --- |
| [`MapBreakdown`](https://offendersearch.app/docs/map/clusters-and-markers#object-mapbreakdown) | Four counts of the people in a view or a cluster. They are not a split of the total: one person counts in `street` and in a housing number. A person whose registry states no housing status is in `total` and in none of the three housing counts. |
| [`MapCluster`](https://offendersearch.app/docs/map/clusters-and-markers#object-mapcluster) | A count for one grid cell, returned in `clusters` mode (zoom 3 to 12, and closer views holding more than 300 pins). Draw it as a circle with `count` inside. |
| [`MapMarker`](https://offendersearch.app/docs/map/clusters-and-markers#object-mapmarker) | One person at one exact street address, in `markers[]`. In `pins` mode (zoom 13 and 14) it is a position and nothing that identifies anyone. In `markers` mode (zoom 15 and closer) it also carries `label`, `housingStatus`, `hasPhoto` and `registryState`. A person with two mapped addresses has two pins; `total` counts that person once. |
| [`MapMember`](https://offendersearch.app/docs/map/clusters-and-markers#object-mapmember) | One person behind a many-people pin or an approximate-area pin: in `members[]` of a groups response, and inline on a many-people pin at zoom 15 and closer. `label`, `housingStatus` and `hasPhoto` are present only when the group came from a view at zoom 15 or closer (`named: true`); otherwise a member is `id` and `addressType` only. |
| [`MapGroupPin`](https://offendersearch.app/docs/map/clusters-and-markers#object-mapgrouppin) | Several people at one exact street address, drawn as one pin in `markers[]`. Tell it apart from a single pin by `id: null` and a `groupId`. List the people with `GET /v1/map/groups/{groupId}`. |
| [`MapArea`](https://offendersearch.app/docs/map/clusters-and-markers#object-maparea) | People known only to the middle of a ZIP code, a city or a county, in `areas[]`. People in custody are always here, as are people without a fixed address whose registered address has no street number. An area is never drawn as an exact pin: draw it so it does not look like an address. |
| [`MapUnplaced`](https://offendersearch.app/docs/map/clusters-and-markers#object-mapunplaced) | People in the states this view touches who have no mappable address. They are on a registry and they are not on the map: show the count next to the map so a short list of pins is not read as the whole list. The count is for whole states, not for the box. |
| [`MapGeoJson`](https://offendersearch.app/docs/map/clusters-and-markers#object-mapgeojson) | The same answer as a GeoJSON `FeatureCollection` of points, returned with `format=geojson` and content type `application/geo+json`. It goes straight into a map library's GeoJSON source. A route answer with `format: "geojson"` has the same shape: one point per marker (`kind: "marker"`), group (`kind: "group"`) and approximate area (`kind: "area"`), with the rest of the route answer under `meta`. |
| [`MapRouteStopInput`](https://offendersearch.app/docs/map/routes#object-maproutestopinput) | One stop in `stops[]` of a route request. A bare `[lng, lat]` pair is accepted too, and gets the id `s1`, `s2`, … by its position. |
| [`MapRouteLeg`](https://offendersearch.app/docs/map/routes#object-maprouteleg) | The line between two stops, in `legs[]`. With fewer than two stops the whole line is one leg. Each person in the corridor counts on the leg of their nearest point of the line, so the leg counts add up to `corridorTotal`. |
| [`MapRouteStop`](https://offendersearch.app/docs/map/routes#object-maproutestop) | One stop, as answered, in `stops[]`, in the order sent. |
| [`MapRouteMarker`](https://offendersearch.app/docs/map/routes#object-maproutemarker) | One person at one exact street address near the route, in `markers[]`. A position, its place on the route and an id. Never a name, on any plan. |
| [`MapRouteGroup`](https://offendersearch.app/docs/map/routes#object-maproutegroup) | Several people registered at one exact street address near the route, as one pin in `groups[]`. The people behind it open with `GET /v1/map/groups/{groupId}` (one map request per page, no names). |
| [`MapRouteArea`](https://offendersearch.app/docs/map/routes#object-maproutearea) | People mapped only to the centre of a ZIP code, city or county, in `approximate.areas[]`. Their distance to the route is not known, so they are listed here and never counted in `total`. |
| [`MapRouteProfile`](https://offendersearch.app/docs/map/routes#object-maprouteprofile) | The limits of one route profile, as `GET /v1/map/status` reports them under `routes.profiles`. |
| [`MapBilling`](https://offendersearch.app/docs/map/open-a-record#object-mapbilling) | Whether this record open was charged, and why. Every `GET /v1/map/records/{markerId}` answer carries it. |
| [`MapError`](https://offendersearch.app/docs/map/limits-and-errors#object-maperror) | The error body of every `/v1/map/*` route, with three exceptions that carry [the Error object](https://offendersearch.app/docs/errors#object-error) instead: a missing or invalid key (`401`, a plain `detail` string), an account with no active subscription and no active free trial (`402`, a plain `detail` string), and a `POST /v1/map/area` or route body whose fields have the wrong JSON types (`422`, the standard validation `detail` list). Switch on `detail.code`; show `detail.message` to a developer. No error response is billed. |

---

## Related

- Previous: [Limits & errors](https://offendersearch.app/docs/map/limits-and-errors.md)
- Index: [Map API reference](https://offendersearch.app/docs/map.md)
