Skip to content

Data updates

We update each country's data about once a month. This page explains how to check the date of the data you are reading, and what changes between updates.

Check the data date

last_refreshed is the date of a country's data. GET /v1/stats?country=GB returns it with the dataset counts.

bash

curl -H "Authorization: Bearer $POI_API_KEY" \
  "$POI_BASE/v1/stats?country=GB"

json

{
  "total": 4718600,
  "by_source_count": {
    "0": 325706,
    "1": 2600429,
    "2": 1313982,
    "3": 478483
  },
  "by_category_group": {
    "business_and_services": 1582720,
    "shopping": 773775,
    "food_and_drink": 498492,
    "uncategorised": 482308,
    "health_and_wellness": 395708,
    "transportation": 328060,
    "automotive": 244425,
    "sports": 159259,
    "culture": 111606,
    "lodging": 111543,
    "finance": 110285,
    "geographical_areas": 83377,
    "education": 79706,
    "entertainment_and_recreation": 55936,
    "government": 48168,
    "places_of_worship": 47146
  },
  "last_refreshed": "2026-09-13T11:42:22+00:00"
}

total is the number of places in the country. by_source_count splits them by source_count. Public transport stations count as 1, and a place only a register lists as 0. Places with more than three sources are in the 3 bucket. by_category_group counts a place once in each group it belongs to. last_refreshed is null when the date cannot be read. Treat a null date as unknown.

GET /v1/catalog returns last_refreshed for every country in one request.

bash

curl -H "Authorization: Bearer $POI_API_KEY" \
  "$POI_BASE/v1/catalog"

The public transport dataset has its own date. GET /v1/pt/meta returns it as data_version. See Public transport.

bash

curl -H "Authorization: Bearer $POI_API_KEY" \
  "$POI_BASE/v1/pt/meta?country=GB"

json

{
  "country_code": "GB",
  "station_count": 325706,
  "line_count": 18623,
  "data_version": "2026-09-13T11:42:22+00:00",
  "line_stops_row_count": 977800
}

Full response shapes are in the API reference.

How often data updates

We update each country about once a month. An update replaces the whole of a country's data at once. You never see part old and part new data. Between updates the data does not change, so the same request returns the same response.

What changes between updates

  • Places. New places appear and closed places go. The total moves by about 0.5% to 2% a month. A place's sources, source_count, verified and closed can change when a source or register adds or drops it. A place listed by two sources can become a one-source place, which moves it out of the default results. See Points of interest.
  • Public transport. Station counts rarely change. A new line or station shows up in the update after it opens. Frequencies change when seasonal timetables start.
  • Green space. Polygon boundaries change slowly. See Green space.

IDs change between updates

Place ids are assigned at each update. Do not store a place id across updates. Store the name and coordinate instead, or look the place up again when last_refreshed moves. See Get one place.

Public transport ids stay the same across updates. A link to a station or a line keeps working. Division ids come from OpenStreetMap and polygon ids from Overture, so they stay the same for as long as the source keeps them.

Caching and data dates

We recommend you key your cache on last_refreshed. Read it once and keep it. Refresh your cache when a later GET /v1/stats or GET /v1/catalog response shows a new value. Do not poll for it. It changes about once a month.

Most GET responses carry a Cache-Control header. GET /v1/stats and GET /v1/catalog are fresh for 1 hour. GET /v1/pois/near is fresh for 5 minutes. A few endpoints send no Cache-Control at all: GET /v1/h3/population (the endpoint Population recommends for a viewport heatmap), GET /v1/divisions, GET /v1/countries, and GET /v1/polygons. Cache those responses at your own TTL if you need to.

GET /v1/pt/*, GET /v1/h3/transport/*, GET /v1/catalog and GET /v1/benchmark set a weak ETag header that changes when the data does. No endpoint reads If-None-Match, so a conditional request returns a full 200, never a 304.

If you show the data to your users, show its date too. last_refreshed is the date to show.