What to draw for one map view — clusters, pins or named pins
You draw the map; this returns what to draw for one view. Send the view as bbox, or as center with radiusMiles — one or the other, not both.
The detail returned depends on the effective zoom. That is the zoom you send, or — when you send none — the zoom at which the box is about four tiles wide. If the box covers more than 64 tiles at that zoom, the zoom is lowered until it fits, never below 3. The response states the zoom used.
| Effective zoom | mode | Returned |
|---|---|---|
| 3–12 | clusters | A count per grid cell |
| 13–14 | pins | One pin per address: position only, no name |
| 15+ | markers | Pins with a name label and basic fields |
A view at zoom 13 or closer that holds more than 300 pins is answered as clusters on a finer grid (mode: "clusters"). With detail=count the mode is count.
Billing. One map request per answer, whatever the view holds. Clusters and pins are never charged per person. A 304, test mode and any error response are free.
Caching. Every answer carries Cache-Control: private, max-age=300 and an ETag. Send the ETag back in If-None-Match: an unchanged view answers 304 with no body and is not billed. The ETag changes when the data changes, and at least every 12 hours.
Test mode. sandbox=true returns made-up people (every label starts with "Sample") around eight US cities, in the real response shape. Group and marker ids from a test-mode response open test-mode data. It needs no plan, is never billed and counts against no budget. The response carries "sandbox": true.
Auth. A secret API key from any server, a dashboard session token, or a map browser key (os_map_pk_…) sent from a site on that key's list.
Request
- Base URL: https://api.offendersearch.app
- URL: https://api.offendersearch.app/v1/map/viewport
- Auth: one of:
- API key in header X-API-Key
- HTTP bearer
Query parameters
west,south,east,north in degrees. Any size. A box crossing the date line has west greater than east.
Instead of bbox: lat,lng in degrees. Goes together with radiusMiles.
With center: the radius in miles, 0.1 to 100.
Optional. The map's current zoom, 0 to 22. Fractions are floored.
json (default) or geojson.
full (default) or count (numbers only).
Keep only people with this housing status. One or more of housed, homeless, incarcerated, comma-separated.
street keeps only people with an exact street address.
true answers in test mode.
Headers
Optional. Any id you use for the end user behind this request. The daily area budget is then also counted per end user (2,000 distinct areas a day), so one heavy user is limited before the account is.
The ETag from an earlier answer for the same view. An unchanged view answers 304 with no body and is not billed.
Response
The answer for this view.
Example response
{
"mode": "clusters",
"zoom": 9,
"bbox": [
-83.5,
39.6,
-82.4,
40.3
],
"datasetVersion": "2026-10-12",
"total": 1840,
"breakdown": {
"street": 1502,
"housed": 310,
"homeless": 96,
"incarcerated": 41
},
"clusters": [
{
"id": "c9_551_775",
"lat": 39.9612,
"lng": -82.9988,
"count": 412,
"bbox": [
-83.06,
39.91,
-82.97,
39.98
],
"expansionZoom": 11,
"breakdown": {
"street": 350,
"housed": 80,
"homeless": 22,
"incarcerated": 9
}
}
],
"markers": [],
"areas": [],
"unplaced": {
"count": 96,
"states": [
"OH"
]
},
"notice": "A pin shows a registered address, not a person's current location."
}Changes
No recorded changes to this operation across all 1 revision of this API.