API reference
A point-in-polygon boundary API. Send a coordinate; get back the country, region and municipality that contain it, plus matches from your own uploaded boundary sets — in one call.
Reading this as an AI agent?
Fetch the machine-readable reference instead. It is plain Markdown, complete, and covers what an automated client cannot do as well as what it can.
https://atlasfetch.xyz/llms.txtBase URL
https://api.atlasfetch.xyz
Every path on this page is relative to it. Lookups go to https://api.atlasfetch.xyz/location/lookup — not to atlasfetch.xyz, which is the website.
When to use AtlasFetch
Reach for it when the question is “which place is this point in?”
- Reverse geocoding to administrative areas — a coordinate becomes the country, region (state, province) and municipality (city, district or county) that contain it, as names plus ISO 3166-1 / ISO 3166-2 codes. Worldwide, from OpenStreetMap boundaries.
- Geofencing against your own polygons — upload GeoJSON delivery zones, service areas or sales territories and test a point against them in the same call as the administrative layers.
- Jurisdiction and region checks — which country or region a user, order or device is in, for pricing, availability, tax or licensing rules.
- Enriching location data — tag GPS pings, orders or sign-ups with region codes, and optionally an H3 cell index or Google Plus Code.
- Privacy-sensitive workloads — looked-up coordinates are never stored.
Not a fit
- Street addresses, postcodes or place search. This is not forward geocoding, and reverse lookups stop at the municipality, not the street.
- Routing, distances or map tiles.
- Boundary geometry itself. It answers containment; it does not return the reference polygons.
- Many coordinates in one request. One request is one coordinate.
- Enter/exit events. It answers which zones contain a point now; tracking transitions between calls is up to your code.
Boundaries follow OpenStreetMap. For a legally binding jurisdiction decision, confirm against the authoritative source.
Authentication
Two mechanisms, and the difference decides what a program can do.
- API key —
Authorization: Bearer <key>. A 64-character hex string, no prefix. This is what a program uses. - Session cookie — issued by an interactive Google sign-in in a browser. An automated client cannot obtain one.
A key is enough for lookups and for managing boundary sets. It is not enough to mint keys, read usage, or manage billing.
Create a key on the dashboard, or call GET https://api.atlasfetch.xyz/demo/key for a shared public one — no signup, but its 1,000 lookups a month and its rate limit are pooled across every anonymous user. Use it to try things, not to ship.
The lookup
GET https://api.atlasfetch.xyz/location/lookup?lat=51.5072&lng=-0.1276 Authorization: Bearer <key>
curl -H "Authorization: Bearer $ATLASFETCH_KEY" \ "https://api.atlasfetch.xyz/location/lookup?lat=51.5072&lng=-0.1276"
| Parameter | Default | Meaning |
|---|---|---|
| lat | required | Latitude, −90 to 90 |
| lng | required | Longitude, −180 to 180 |
| base | all three | Comma list: country, region, municipal |
| set | none | Comma list of your own boundary sets |
| encode | none | Comma list: h3, pluscode |
| h3res | 9 | H3 resolution 0–15. r9 is ~400 m across |
| pluslen | 10 | Plus Code length: 2, 4, 6, 8, 10–15 |
{
"base": {
"country": { "code": "GB", "name": "United Kingdom" },
"region": { "code": "GB-ENG", "name": "England" },
"municipal": { "code": "GB-WSM", "name": "City of Westminster" }
},
"sets": {
"delivery_zones": [
{ "name": "Zone A", "properties": { "category": "express" } }
]
},
"errors": []
}Guarantees you can rely on
errors[]is always present, empty or not. Read it unconditionally.- A layer that matched nothing is
null, not absent. encodedis absent entirely unlessencodewas asked for.- Every response carries
X-Lookups-Remaining. - Boundaries are identified by codes, never OSM ids — ISO 3166-1 for country, ISO 3166-2 for region, and for municipal the official ISO code where OSM carries one, otherwise a generated
B-<country>-<n>. municipalis the finest unit available, not a consistent kind of thing. Los Angeles returns a city; rural Kansas returns Barton County. Where a country’s fine tier is patchy, a coarser complete tier answers instead — a county beatsnullfor most uses. Do not assume the value names a city.
B- codes are not yet stable across a full reseed. Treat them as display labels rather than durable keys. ISO codes are stable.One call, one lookup
A request is exactly one lookup regardless of how many layers, sets or grid codes it touches. Metering happens before matching, so a call that matches nothing still costs a lookup — the work was done either way. A request rejected with 400 or 429 is not billed.
Partial failure is still a 200
A set you cannot query does not fail the request. It is skipped, an entry is appended to errors[], and the status stays 200. A set is only queryable when it is marked available and granted to the key making the call.
"errors": [
{ "type": "access", "message": "Set 'zones' is not granted to key 'prod'" }
]type is access (a set was skipped) or usage (quota exhausted, mirroring a 402).
Grid codes
The looked-up point can be returned as a Google Plus Code and/or an H3 cell index. Not metered, not plan-gated.
GET https://api.atlasfetch.xyz/location/lookup?lat=51.5072&lng=-0.1276&encode=h3,pluscode
"encoded": { "h3": "89195da49b7ffff", "pluscode": "9C3XGV4C+VX" }They are output only
pluscode= and h3= are not accepted as a location; sending one returns 400. That is deliberate, not a missing feature.
A Plus Code and an H3 index name areas, not points. A length-4 Plus Code is a 111 km square; an H3 cell at resolution 4 is 52 km across. Accepting one as the location would mean picking a representative point inside it and returning whichever boundary contains that point as though it were the answer — one of several equally defensible answers, with no way for you to tell which situation you were in.
If you have a cell and want a lookup, decode it yourself and decide what its centre means for your use case. That keeps the judgement where the context is.
Picking a precision
| H3 | Width | Plus Code | Width |
|---|---|---|---|
| r4 | ~52 km | 4 | ~111 km |
| r6 | ~7.4 km | 6 | ~5.6 km |
| r8 | ~1.1 km | 8 | ~278 m |
| r9 (default) | ~402 m | 10 (default) | ~14 m |
| r11 | ~57 m | 11 | ~3 m |
| r15 | ~1 m | 12 | ~56 cm |
Plus Code widths are at the equator. pluslen=9 is invalid — 9 is not a Plus Code length.
Custom boundary sets
Your own polygons, grouped into named sets, matched in the same call as the reference layers. These endpoints accept an API key or a session.
| Method | Path | Purpose |
|---|---|---|
| GET | /boundaries/sets | List sets with counts and granted key ids |
| POST | /boundaries/sets | Create a set |
| PATCH | /boundaries/sets/:name | Toggle available, grant/revoke keys |
| DELETE | /boundaries/sets/:name | Delete the set and its contents |
| POST | /boundaries | Add a boundary (GeoJSON geometry) |
| GET | /boundaries/view?set= | Your own boundaries, with geometry |
| DELETE | /boundaries/:id | Remove one boundary |
available: false with no grants, so it matches nothing until you switch it on and grant it to a key. Grants are addressed by API key id, and the endpoint that lists ids needs a session — so a client holding only a raw key can create a set and upload into it, but cannot grant the set to itself. That step happens in the dashboard.Public endpoints
No authentication, no metering.
| Method | Path | Purpose |
|---|---|---|
| GET | /health | Liveness |
| GET | /demo/key | The shared public demo key |
| GET | /payments/plans | Plan catalogue with prices and caps |
| GET | /version | Which API build is serving |
| GET | /openapi.json | OpenAPI 3.1 spec — generate a client from it |
/explore/world and /explore/country/:code served simplified country outlines and were removed on 8 September 2026 — unauthenticated, uncached and expensive (243 KB and 16.8 s per call), they were the one lever an anonymous caller could pull against the database. AtlasFetch answers point-in-polygon questions; it does not hand out boundary geometry.Status codes
| Code | Meaning | Retry? |
|---|---|---|
| 200 | Success — check errors[] for per-set problems | — |
| 400 | Invalid parameters; error says what | No |
| 401 | Missing, malformed or revoked key | No |
| 402 | Monthly allowance exhausted | After reset |
| 403 | Plan does not include this, or a cap exceeded | No |
| 409 | Conflict, e.g. duplicate set name | No |
| 429 | Per-key rate limit — honour Retry-After | Yes |
Rate limiting is per key, per second. Quota is per account, per month.
Privacy and data
We do not store the coordinates you look up. Usage metering records the endpoint, the key and a timestamp — never the point.
Reference boundaries derive from OpenStreetMap under the ODbL. Attribution and share-alike obligations pass through to you — see data attribution. Your own uploaded boundaries are private to your account and are never returned to anyone else.
Try it without writing any code
The playground loads a demo key automatically and shows the exact request URL.
Open the playground