Skip to main content

World Cities API

REAL DATA

31,000+ world cities from a pinned GeoNames snapshot: coordinates, IANA timezone, elevation, population and capital flag — filter, search or rank by distance.

Authoritative reference data or standards computation

Base URL
/api/cities
Capabilities
3 routes
Last updated
Data sources · 4
+1 more
  • English country names joined from this project's ISO 3166-1 country dataset (Natural Earth + countries-list)

GET /api/cities

Returns matching places from the pinned 31,793-place GeoNames snapshot, ordered by population or name. A page holds at most 100 records; use offset to walk further.

Live requestRuns against the public API
No key required
GET/api/cities?count=10

Request parameters

Only cities in this country (ISO 3166-1 alpha-2, case-insensitive — dk and DK both work). A valid two-letter code with no cities in the set returns an empty list; anything that isn't two letters is a 400.

Only cities in this first-order division (state, province, region…), matched on the published GeoNames spelling ignoring case and diacritics. A division that is not in the snapshot returns an empty list with a warning.

Only cities whose GeoNames IANA time zone is this one, matched case-insensitively and echoed canonically. A real IANA zone that no place here uses returns an empty list with a warning; a string that is not a zone identifier is a 400.

Pin GeoNames' own classification: PPL (plain populated place), PPLC (capital of a political entity), PPLA–PPLA5 (seat of a first- to fifth-order administrative division), and the rarer PPLF/PPLG/PPLL/PPLR/PPLS/STLMT. any keeps every classification.

Only cities whose name or GeoNames ASCII alias contains this text — case-, diacritic- and apostrophe-insensitive (sao matches São Paulo, xian matches Xi’an).

Only cities whose GeoNames population is ≥ this value. Places with no published population are excluded, since an unknown figure cannot be shown to clear the bar.

Only cities whose MODELLED demElevation is ≥ this many metres. It filters demElevation, not the sparse source-stated elevation column, and places with no modelled value are excluded.

Only cities whose MODELLED demElevation is ≤ this many metres. Must be ≥ minDemElevation when both are given, or the request is a 400.

true = only places GeoNames codes PPLC — the capital of a political entity, which includes the capitals of dependent territories (Douglas, Tórshavn), not only sovereign states; false = only non-capitals; omit for both.

population = largest first, unknown populations last; name = A→Z (diacritic-insensitive).

Skip this many matches before count is applied, so you can page through large results (offset=100 with count=100 returns the second hundred).

Advanced response options6 options

Limit the number of returned records (1–100). Defaults to 25.

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Response format: json envelope, ndjson (one record per line) or csv.

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/cities?count=10"
const res = await fetch("https://randomapi.dev/api/cities?count=10");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/cities?count=10").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/cities?count=10"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 11
country string

Only cities in this country (ISO 3166-1 alpha-2, case-insensitive — dk and DK both work). A valid two-letter code with no cities in the set returns an empty list; anything that isn't two letters is a 400.

example: country=DK
admin1 string

Only cities in this first-order division (state, province, region…), matched on the published GeoNames spelling ignoring case and diacritics. A division that is not in the snapshot returns an empty list with a warning.

example: admin1=Bavaria
timezone string

Only cities whose GeoNames IANA time zone is this one, matched case-insensitively and echoed canonically. A real IANA zone that no place here uses returns an empty list with a warning; a string that is not a zone identifier is a 400.

example: timezone=Europe/Copenhagen
featureCode enum

Pin GeoNames' own classification: PPL (plain populated place), PPLC (capital of a political entity), PPLA–PPLA5 (seat of a first- to fifth-order administrative division), and the rarer PPLF/PPLG/PPLL/PPLR/PPLS/STLMT. any keeps every classification.

default: any
allowed: any | PPL | PPLA | PPLA2 | PPLA3 | PPLA4 | PPLA5 | PPLC | PPLF | PPLG | PPLL | PPLR | PPLS | STLMT
example: featureCode=PPLA
search string

Only cities whose name or GeoNames ASCII alias contains this text — case-, diacritic- and apostrophe-insensitive (sao matches São Paulo, xian matches Xi’an).

example: search=york
minPopulation int

Only cities whose GeoNames population is ≥ this value. Places with no published population are excluded, since an unknown figure cannot be shown to clear the bar.

allowed: ≥ 0
example: minPopulation=1000000
minDemElevation int

Only cities whose MODELLED demElevation is ≥ this many metres. It filters demElevation, not the sparse source-stated elevation column, and places with no modelled value are excluded.

allowed: -500 – 9000
example: minDemElevation=1000
maxDemElevation int

Only cities whose MODELLED demElevation is ≤ this many metres. Must be ≥ minDemElevation when both are given, or the request is a 400.

allowed: -500 – 9000
example: maxDemElevation=10
capital boolean

true = only places GeoNames codes PPLC — the capital of a political entity, which includes the capitals of dependent territories (Douglas, Tórshavn), not only sovereign states; false = only non-capitals; omit for both.

example: capital=true
sort enum

population = largest first, unknown populations last; name = A→Z (diacritic-insensitive).

default: population
allowed: population | name
example: sort=name
offset int

Skip this many matches before count is applied, so you can page through large results (offset=100 with count=100 returns the second hundred).

default: 0
allowed: 0 – 100000
example: offset=100
Universal parameters Shared response and formatting options 6
count int

Limit the number of returned records (1–100). Defaults to 25.

default: 25
allowed: 1 – 100
example: count=3
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=name,asciiName
exclude list

Return all fields except these (comma-separated).

example: exclude=isCapital
format enum

Response format: json envelope, ndjson (one record per line) or csv.

default: json
allowed: json | ndjson | csv
example: format=csv
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 13
name string

GeoNames place name — the common international form, diacritics included.

example: Copenhagen

asciiName string

The same name transliterated to plain ASCII by GeoNames (São Paulo → Sao Paulo). Equal to name when it is already ASCII.

example: Copenhagen

country string

English country name, joined from the ISO 3166-1 country dataset.

example: Denmark

countryCode string

ISO 3166-1 alpha-2 country code.

example: DK

admin1 string nullable

First-order administrative division (state, province, region…) in GeoNames' published spelling, diacritics included (`Vlorë County`); null where GeoNames publishes no first-order division for the place.

example: Capital Region

latitude float

GeoNames point latitude (WGS84, 4 decimals).

example: 55.6759

longitude float

GeoNames point longitude (WGS84, 4 decimals).

example: 12.5655

timezone string (IANA)

The IANA timezone identifier GeoNames records for the place.

example: Europe/Copenhagen

population integer nullable

GeoNames population figure — an APPROXIMATE administrative/city-proper count of mixed vintage, not a metropolitan total and not a census value. null when GeoNames publishes no figure.

example: 1153615

elevation integer nullable

Elevation in metres as STATED by the GeoNames source record. It is a sparse column — published for only 4,185 of the 31,793 places (13.2%) — and is null everywhere else. It is never back-filled from the modelled value.

example: 10

demElevation integer nullable

Elevation in metres MODELLED at the point coordinate from a digital elevation model (SRTM3, or GTOPO30 above 60°N). Present for 31,734 places (99.8%); GeoNames' -9999 void marker is exposed as null, never as a depth. This is a raster sample, not a survey of the settlement.

example: 14

featureCode string

GeoNames feature classification, verbatim: PPL is a plain populated place, PPLC a capital of a political entity, PPLA…PPLA5 the seat of a first- to fifth-order administrative division.

example: PPLC

isCapital boolean

True when GeoNames codes the place PPLC (capital of a political entity). GeoNames marks at most one capital per country.

example: true

Documented examples

Build-generated requests and complete responses
11
The 10 most populous places in the set
GET /api/cities?count=10
{
  "data": [
    {
      "name": "Shanghai",
      "asciiName": "Shanghai",
      "country": "China",
      "countryCode": "CN",
      "admin1": "Shanghai",
      "latitude": 31.2222,
      "longitude": 121.4581,
      "timezone": "Asia/Shanghai",
      "population": 24874500,
      "elevation": null,
      "demElevation": 12,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "Chongqing",
      "asciiName": "Chongqing",
      "country": "China",
      "countryCode": "CN",
      "admin1": "Chongqing",
      "latitude": 29.5603,
      "longitude": 106.5577,
      "timezone": "Asia/Shanghai",
      "population": 22000000,
      "elevation": null,
      "demElevation": 289,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "Chengdu",
      "asciiName": "Chengdu",
      "country": "China",
      "countryCode": "CN",
      "admin1": "Sichuan",
      "latitude": 30.6667,
      "longitude": 104.0667,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Every Danish city in the snapshot
GET /api/cities?country=dk&count=100
{
  "data": [
    {
      "name": "Copenhagen",
      "asciiName": "Copenhagen",
      "country": "Denmark",
      "countryCode": "DK",
      "admin1": "Capital Region",
      "latitude": 55.6759,
      "longitude": 12.5655,
      "timezone": "Europe/Copenhagen",
      "population": 1153615,
      "elevation": null,
      "demElevation": 14,
      "featureCode": "PPLC",
      "isCapital": true
    },
    {
      "name": "Århus",
      "asciiName": "Arhus",
      "country": "Denmark",
      "countryCode": "DK",
      "admin1": "Central Jutland",
      "latitude": 56.1567,
      "longitude": 10.2108,
      "timezone": "Europe/Copenhagen",
      "population": 285273,
      "elevation": null,
      "demElevation": 10,
      "featureCode": "PPLA2",
      "isCapital": false
    },
    {
      "name": "Odense",
      "asciiName": "Odense",
      "country": "Denmark",
      "countryCode": "DK",
      "admin1": "South Denmark",
      "latitude": 55.3959,
      "longitude": 10.3883,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
German cities above one million
GET /api/cities?country=de&minPopulation=1000000
{
  "data": [
    {
      "name": "Berlin",
      "asciiName": "Berlin",
      "country": "Germany",
      "countryCode": "DE",
      "admin1": "State of Berlin",
      "latitude": 52.5244,
      "longitude": 13.4105,
      "timezone": "Europe/Berlin",
      "population": 3426354,
      "elevation": 74,
      "demElevation": 43,
      "featureCode": "PPLC",
      "isCapital": true
    },
    {
      "name": "Hamburg",
      "asciiName": "Hamburg",
      "country": "Germany",
      "countryCode": "DE",
      "admin1": "Hamburg",
      "latitude": 53.5507,
      "longitude": 9.993,
      "timezone": "Europe/Berlin",
      "population": 1973896,
      "elevation": null,
      "demElevation": 9,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "Munich",
      "asciiName": "Munich",
      "country": "Germany",
      "countryCode": "DE",
      "admin1": "Bavaria",
      "latitude": 48.1374,
      "longitude": 11.5755,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
National capitals, alphabetically
GET /api/cities?capital=true&sort=name&count=100
{
  "data": [
    {
      "name": "Abu Dhabi",
      "asciiName": "Abu Dhabi",
      "country": "United Arab Emirates",
      "countryCode": "AE",
      "admin1": "Abu Dhabi",
      "latitude": 24.4512,
      "longitude": 54.397,
      "timezone": "Asia/Dubai",
      "population": 1807000,
      "elevation": null,
      "demElevation": 6,
      "featureCode": "PPLC",
      "isCapital": true
    },
    {
      "name": "Abuja",
      "asciiName": "Abuja",
      "country": "Nigeria",
      "countryCode": "NG",
      "admin1": "FCT",
      "latitude": 9.0579,
      "longitude": 7.4951,
      "timezone": "Africa/Lagos",
      "population": 2690000,
      "elevation": null,
      "demElevation": 476,
      "featureCode": "PPLC",
      "isCapital": true
    },
    {
      "name": "Accra",
      "asciiName": "Accra",
      "country": "Ghana",
      "countryCode": "GH",
      "admin1": "Greater Accra",
      "latitude": 5.556,
      "longitude": -0.1969,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Find São Paulo without typing diacritics
GET /api/cities?search=sao+paulo
{
  "data": [
    {
      "name": "São Paulo",
      "asciiName": "Sao Paulo",
      "country": "Brazil",
      "countryCode": "BR",
      "admin1": "São Paulo",
      "latitude": -23.5475,
      "longitude": -46.6361,
      "timezone": "America/Sao_Paulo",
      "population": 12400232,
      "elevation": null,
      "demElevation": 769,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "São Paulo de Olivença",
      "asciiName": "Sao Paulo de Olivenca",
      "country": "Brazil",
      "countryCode": "BR",
      "admin1": "Amazonas",
      "latitude": -3.3783,
      "longitude": -68.8725,
      "timezone": "America/Manaus",
      "population": 40073,
      "elevation": null,
      "demElevation": 73,
      "featureCode": "PPL",
      "isCapital": false
    },
    {
      "name": "São Paulo de Frades",
      "asciiName": "Sao Paulo de Frades",
      "country": "Portugal",
      "countryCode": "PT",
      "admin1": "Coimbra",
      "latitude": 40.2468,
      "longitude": -8.394,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Bavaria's largest places
GET /api/cities?country=de&admin1=Bavaria&count=25
{
  "data": [
    {
      "name": "Munich",
      "asciiName": "Munich",
      "country": "Germany",
      "countryCode": "DE",
      "admin1": "Bavaria",
      "latitude": 48.1374,
      "longitude": 11.5755,
      "timezone": "Europe/Berlin",
      "population": 1505005,
      "elevation": null,
      "demElevation": 524,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "Nuremberg",
      "asciiName": "Nuremberg",
      "country": "Germany",
      "countryCode": "DE",
      "admin1": "Bavaria",
      "latitude": 49.4542,
      "longitude": 11.0775,
      "timezone": "Europe/Berlin",
      "population": 515543,
      "elevation": null,
      "demElevation": 300,
      "featureCode": "PPLA3",
      "isCapital": false
    },
    {
      "name": "Augsburg",
      "asciiName": "Augsburg",
      "country": "Germany",
      "countryCode": "DE",
      "admin1": "Bavaria",
      "latitude": 48.3715,
      "longitude": 10.8985,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Every city on Europe/Copenhagen time
GET /api/cities?timezone=Europe/Copenhagen&count=100
{
  "data": [
    {
      "name": "Copenhagen",
      "asciiName": "Copenhagen",
      "country": "Denmark",
      "countryCode": "DK",
      "admin1": "Capital Region",
      "latitude": 55.6759,
      "longitude": 12.5655,
      "timezone": "Europe/Copenhagen",
      "population": 1153615,
      "elevation": null,
      "demElevation": 14,
      "featureCode": "PPLC",
      "isCapital": true
    },
    {
      "name": "Århus",
      "asciiName": "Arhus",
      "country": "Denmark",
      "countryCode": "DK",
      "admin1": "Central Jutland",
      "latitude": 56.1567,
      "longitude": 10.2108,
      "timezone": "Europe/Copenhagen",
      "population": 285273,
      "elevation": null,
      "demElevation": 10,
      "featureCode": "PPLA2",
      "isCapital": false
    },
    {
      "name": "Odense",
      "asciiName": "Odense",
      "country": "Denmark",
      "countryCode": "DK",
      "admin1": "South Denmark",
      "latitude": 55.3959,
      "longitude": 10.3883,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Cities above 2,000 m in the elevation model
GET /api/cities?minDemElevation=2000&count=50
{
  "data": [
    {
      "name": "Mexico City",
      "asciiName": "Mexico City",
      "country": "Mexico",
      "countryCode": "MX",
      "admin1": "Mexico City",
      "latitude": 19.4285,
      "longitude": -99.1277,
      "timezone": "America/Mexico_City",
      "population": 12294193,
      "elevation": null,
      "demElevation": 2240,
      "featureCode": "PPLC",
      "isCapital": true
    },
    {
      "name": "Bogotá",
      "asciiName": "Bogota",
      "country": "Colombia",
      "countryCode": "CO",
      "admin1": "Bogota D.C.",
      "latitude": 4.6097,
      "longitude": -74.0817,
      "timezone": "America/Bogota",
      "population": 7674366,
      "elevation": null,
      "demElevation": 2582,
      "featureCode": "PPLC",
      "isCapital": true
    },
    {
      "name": "Addis Ababa",
      "asciiName": "Addis Ababa",
      "country": "Ethiopia",
      "countryCode": "ET",
      "admin1": "Addis Ababa",
      "latitude": 9.025,
      "longitude": 38.7469,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Seats of a first-order division in India
GET /api/cities?country=in&featureCode=PPLA&count=50
{
  "data": [
    {
      "name": "Mumbai",
      "asciiName": "Mumbai",
      "country": "India",
      "countryCode": "IN",
      "admin1": "Maharashtra",
      "latitude": 19.0728,
      "longitude": 72.8826,
      "timezone": "Asia/Kolkata",
      "population": 12691836,
      "elevation": null,
      "demElevation": 8,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "Delhi",
      "asciiName": "Delhi",
      "country": "India",
      "countryCode": "IN",
      "admin1": "Delhi",
      "latitude": 28.6519,
      "longitude": 77.2315,
      "timezone": "Asia/Kolkata",
      "population": 11034555,
      "elevation": null,
      "demElevation": 227,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "Bengaluru",
      "asciiName": "Bengaluru",
      "country": "India",
      "countryCode": "IN",
      "admin1": "Karnataka",
      "latitude": 12.9719,
      "longitude": 77.5937,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
The second hundred US places by population
GET /api/cities?country=us&count=100&offset=100
{
  "data": [
    {
      "name": "Irving",
      "asciiName": "Irving",
      "country": "United States",
      "countryCode": "US",
      "admin1": "Texas",
      "latitude": 32.814,
      "longitude": -96.9489,
      "timezone": "America/Chicago",
      "population": 236607,
      "elevation": 147,
      "demElevation": 151,
      "featureCode": "PPL",
      "isCapital": false
    },
    {
      "name": "Boise",
      "asciiName": "Boise",
      "country": "United States",
      "countryCode": "US",
      "admin1": "Idaho",
      "latitude": 43.6135,
      "longitude": -116.2035,
      "timezone": "America/Boise",
      "population": 235684,
      "elevation": 823,
      "demElevation": 834,
      "featureCode": "PPLA",
      "isCapital": false
    },
    {
      "name": "Chesapeake",
      "asciiName": "Chesapeake",
      "country": "United States",
      "countryCode": "US",
      "admin1": "Virginia",
      "latitude": 36.819,
      "longitude": -76.2749,
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Name + timezone reference table
GET /api/cities?sort=name&count=100&fields=name,countryCode,timezone
{
  "data": [
    {
      "name": "6th of October City",
      "countryCode": "EG",
      "timezone": "Africa/Cairo"
    },
    {
      "name": "A Coruña",
      "countryCode": "ES",
      "timezone": "Europe/Madrid"
    },
    {
      "name": "A Estrada",
      "countryCode": "ES",
      "timezone": "Europe/Madrid"
    },
    {
      "name": "A Yun Pa",
      "countryCode": "VN",
      "timezone": "Asia/Ho_Chi_Minh"
    },
    {
      "name": "Aabenraa",
      "countryCode": "DK",
      "timezone": "Europe/Copenhagen"
    },
    {
      "name": "Aachen",
      "countryCode": "DE",
      "timezone": "Europe/Berlin"
    },
    {
      "name": "Aalborg",
      "countryCode": "DK",
      "timezone": "Europe/Copenhagen"
    },
    {
      "name": "Aalen",
      "countryCode": "DE",
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}

GET /api/cities/nearest

Ranks the pinned 31,793-place snapshot by great-circle distance on the mean-Earth sphere. A bounding-box prefilter narrows the candidates before any trigonometry, and optional country, size and radius filters apply before count. At most 100 records come back.

Live requestRuns against the public API
No key required
GET/api/cities/nearest?lat=48.8566&lng=2.3522&maxDistanceKm=100&count=100

Request parameters

Search-point latitude in WGS84 decimal degrees (-90 to 90).

Search-point longitude in WGS84 decimal degrees (-180 to 180).

Optional maximum great-circle distance in kilometers. Omit it to rank outward from the point with no limit until count is satisfied.

Only cities in this country (ISO 3166-1 alpha-2, case-insensitive — dk and DK both work). A valid two-letter code with no cities in the set returns an empty list; anything that isn't two letters is a 400.

Optional floor on the GeoNames population, so you can ask for the nearest sizeable city rather than the nearest village. Places with no published figure are excluded.

true = rank only places GeoNames codes PPLC — capitals of political entities, dependent territories included, so the nearest one to a North Sea point is Douglas on the Isle of Man; false = exclude them; omit for both.

Advanced response options6 options

Limit the number of returned records (1–100). Defaults to 10.

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

Return all fields except these (comma-separated).

Response format: json envelope, ndjson (one record per line) or csv.

Pretty-print the JSON response.

Drop the envelope: return the raw array/object without data/meta wrapper.

Response

Example parameters are ready. Send the request to inspect the live response.

Route reference

Code samples Ready-to-copy requests in 4 languages
Choose a code sample language
curl "https://randomapi.dev/api/cities/nearest?lat=48.8566&lng=2.3522&maxDistanceKm=100&count=100"
const res = await fetch("https://randomapi.dev/api/cities/nearest?lat=48.8566&lng=2.3522&maxDistanceKm=100&count=100");
const { data, meta } = await res.json();
import requests

data = requests.get("https://randomapi.dev/api/cities/nearest?lat=48.8566&lng=2.3522&maxDistanceKm=100&count=100").json()["data"]
$json = json_decode(file_get_contents(
  "https://randomapi.dev/api/cities/nearest?lat=48.8566&lng=2.3522&maxDistanceKm=100&count=100"
), true);
$data = $json["data"];
Parameters Route-specific request inputs 6
lat float required

Search-point latitude in WGS84 decimal degrees (-90 to 90).

allowed: -90 – 90
example: lat=48.8566
lng float required

Search-point longitude in WGS84 decimal degrees (-180 to 180).

allowed: -180 – 180
example: lng=2.3522
maxDistanceKm float

Optional maximum great-circle distance in kilometers. Omit it to rank outward from the point with no limit until count is satisfied.

allowed: 0 – 20020
example: maxDistanceKm=100
country string

Only cities in this country (ISO 3166-1 alpha-2, case-insensitive — dk and DK both work). A valid two-letter code with no cities in the set returns an empty list; anything that isn't two letters is a 400.

example: country=DK
minPopulation int

Optional floor on the GeoNames population, so you can ask for the nearest sizeable city rather than the nearest village. Places with no published figure are excluded.

allowed: ≥ 0
example: minPopulation=500000
capital boolean

true = rank only places GeoNames codes PPLC — capitals of political entities, dependent territories included, so the nearest one to a North Sea point is Douglas on the Isle of Man; false = exclude them; omit for both.

example: capital=true
Universal parameters Shared response and formatting options 6
count int

Limit the number of returned records (1–100). Defaults to 10.

default: 10
allowed: 1 – 100
example: count=3
fields list

Return only these fields (comma-separated). Mutually exclusive with 'exclude'.

example: fields=name,asciiName
exclude list

Return all fields except these (comma-separated).

example: exclude=radiusMeters
format enum

Response format: json envelope, ndjson (one record per line) or csv.

default: json
allowed: json | ndjson | csv
example: format=csv
pretty boolean

Pretty-print the JSON response.

default: false
example: pretty=true
unwrap boolean

Drop the envelope: return the raw array/object without data/meta wrapper.

default: false
example: unwrap=true
Response schema Fields returned in each record 16
name string

GeoNames place name — the common international form, diacritics included.

example: Copenhagen

asciiName string

The same name transliterated to plain ASCII by GeoNames (São Paulo → Sao Paulo). Equal to name when it is already ASCII.

example: Copenhagen

country string

English country name, joined from the ISO 3166-1 country dataset.

example: Denmark

countryCode string

ISO 3166-1 alpha-2 country code.

example: DK

admin1 string nullable

First-order administrative division (state, province, region…) in GeoNames' published spelling, diacritics included (`Vlorë County`); null where GeoNames publishes no first-order division for the place.

example: Capital Region

latitude float

GeoNames point latitude (WGS84, 4 decimals).

example: 55.6759

longitude float

GeoNames point longitude (WGS84, 4 decimals).

example: 12.5655

timezone string (IANA)

The IANA timezone identifier GeoNames records for the place.

example: Europe/Copenhagen

population integer nullable

GeoNames population figure — an APPROXIMATE administrative/city-proper count of mixed vintage, not a metropolitan total and not a census value. null when GeoNames publishes no figure.

example: 1153615

elevation integer nullable

Elevation in metres as STATED by the GeoNames source record. It is a sparse column — published for only 4,185 of the 31,793 places (13.2%) — and is null everywhere else. It is never back-filled from the modelled value.

example: 10

demElevation integer nullable

Elevation in metres MODELLED at the point coordinate from a digital elevation model (SRTM3, or GTOPO30 above 60°N). Present for 31,734 places (99.8%); GeoNames' -9999 void marker is exposed as null, never as a depth. This is a raster sample, not a survey of the settlement.

example: 14

featureCode string

GeoNames feature classification, verbatim: PPL is a plain populated place, PPLC a capital of a political entity, PPLA…PPLA5 the seat of a first- to fifth-order administrative division.

example: PPLC

isCapital boolean

True when GeoNames codes the place PPLC (capital of a political entity). GeoNames marks at most one capital per country.

example: true

distanceKm float

Great-circle distance from the search point to the GeoNames point coordinate, on the mean-Earth sphere; rounded to 3 decimals.

example: 0

model string

Always "mean-earth-sphere" — the same surface /api/geodesy documents. Not an ellipsoid, not a road or flight distance.

example: mean-earth-sphere

radiusMeters float

The IUGG mean Earth radius used for every distance in this response, in metres.

example: 6371008.8

Documented examples

Build-generated requests and complete responses
5
Cities within 100 km of Paris
GET /api/cities/nearest?lat=48.8566&lng=2.3522&maxDistanceKm=100&count=100
{
  "data": [
    {
      "name": "Paris 04 Hôtel-de-Ville",
      "asciiName": "Paris 04 Hotel-de-Ville",
      "country": "France",
      "countryCode": "FR",
      "admin1": "Île-de-France",
      "latitude": 48.8601,
      "longitude": 2.3507,
      "timezone": "Europe/Paris",
      "population": 27332,
      "elevation": null,
      "demElevation": 44,
      "featureCode": "PPL",
      "isCapital": false,
      "distanceKm": 0.404,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "Paris",
      "asciiName": "Paris",
      "country": "France",
      "countryCode": "FR",
      "admin1": "Île-de-France",
      "latitude": 48.8534,
      "longitude": 2.3488,
      "timezone": "Europe/Paris",
      "population": 2138551,
      "elevation": null,
      "demElevation": 42,
      "featureCode": "PPLC",
      "isCapital": true,
      "distanceKm": 0.434,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "Paris 01 Louvre",
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Nearest half-million-plus city to Zurich
GET /api/cities/nearest?lat=47.3769&lng=8.5417&minPopulation=500000&count=5
{
  "data": [
    {
      "name": "Stuttgart",
      "asciiName": "Stuttgart",
      "country": "Germany",
      "countryCode": "DE",
      "admin1": "Baden-Wurttemberg",
      "latitude": 48.7823,
      "longitude": 9.177,
      "timezone": "Europe/Berlin",
      "population": 612663,
      "elevation": null,
      "demElevation": 252,
      "featureCode": "PPLA",
      "isCapital": false,
      "distanceKm": 163.243,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "Milan",
      "asciiName": "Milan",
      "country": "Italy",
      "countryCode": "IT",
      "admin1": "Lombardy",
      "latitude": 45.4643,
      "longitude": 9.1895,
      "timezone": "Europe/Rome",
      "population": 1371498,
      "elevation": 122,
      "demElevation": 127,
      "featureCode": "PPLA",
      "isCapital": false,
      "distanceKm": 218.39,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "Munich",
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
US cities within 200 km of New York
GET /api/cities/nearest?lat=40.7128&lng=-74.006&country=US&maxDistanceKm=200&count=100
{
  "data": [
    {
      "name": "New York City",
      "asciiName": "New York City",
      "country": "United States",
      "countryCode": "US",
      "admin1": "New York",
      "latitude": 40.7143,
      "longitude": -74.006,
      "timezone": "America/New_York",
      "population": 8804190,
      "elevation": 10,
      "demElevation": 57,
      "featureCode": "PPL",
      "isCapital": false,
      "distanceKm": 0.167,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "Hoboken",
      "asciiName": "Hoboken",
      "country": "United States",
      "countryCode": "US",
      "admin1": "New Jersey",
      "latitude": 40.744,
      "longitude": -74.0324,
      "timezone": "America/New_York",
      "population": 53635,
      "elevation": 2,
      "demElevation": 5,
      "featureCode": "PPL",
      "isCapital": false,
      "distanceKm": 4.121,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "Jersey City",
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
Nearest Danish city to Hamburg
GET /api/cities/nearest?lat=53.5511&lng=9.9937&country=DK&count=1
{
  "data": [
    {
      "name": "Sønderborg",
      "asciiName": "Sonderborg",
      "country": "Denmark",
      "countryCode": "DK",
      "admin1": "South Denmark",
      "latitude": 54.909,
      "longitude": 9.7892,
      "timezone": "Europe/Copenhagen",
      "population": 27766,
      "elevation": null,
      "demElevation": 15,
      "featureCode": "PPLA2",
      "isCapital": false,
      "distanceKm": 151.576,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    }
  ],
  "meta": {
    "endpoint": "cities",
    "route": "/nearest",
    "count": 1,
    "params": {
      "lat": 53.5511,
      "lng": 9.9937,
      "country": "DK"
    },
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}
The three capital cities nearest the North Sea
GET /api/cities/nearest?lat=56&lng=3&capital=true&count=3
{
  "data": [
    {
      "name": "Amsterdam",
      "asciiName": "Amsterdam",
      "country": "Netherlands",
      "countryCode": "NL",
      "admin1": "North Holland",
      "latitude": 52.374,
      "longitude": 4.8897,
      "timezone": "Europe/Amsterdam",
      "population": 741636,
      "elevation": null,
      "demElevation": 13,
      "featureCode": "PPLC",
      "isCapital": true,
      "distanceKm": 421.482,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "Douglas",
      "asciiName": "Douglas",
      "country": "Isle of Man",
      "countryCode": "IM",
      "admin1": "Douglas",
      "latitude": 54.15,
      "longitude": -4.4833,
      "timezone": "Europe/Isle_of_Man",
      "population": 26218,
      "elevation": null,
      "demElevation": 31,
      "featureCode": "PPLC",
      "isCapital": true,
      "distanceKm": 518.556,
      "model": "mean-earth-sphere",
      "radiusMeters": 6371008.8
    },
    {
      "name": "London",
    …
    "generatedAt": "2026-09-15T19:47:18.000Z"
  }
}

About this API

Coverage & behavior

A pinned snapshot of the GeoNames cities15000 dump covering 31,793 populated places across 245 countries and territories, including 240 capital cities (GeoNames' PPLC, the capital of a political entity — dependent territories included, so Douglas, Tórshavn and The Valley are here next to London and Copenhagen), 2,806 first-order divisions and 361 IANA time zones. Records in the bundled dumps were last modified upstream on 2026-09-14; the exact files are pinned by SHA-256 and regenerated by a committed script, never hand-edited.

What is in the set — an explicit, reproducible rule rather than an editor's taste:

  1. every populated place in GeoNames' cities15000 tier (its own cut at a population of 15,000 or more, which also carries sub-threshold capitals);
  2. plus the five most populous places of every country, taken from the far deeper cities500 tier, so a country whose largest town is below the tier floor is represented instead of dropped for being small;
  3. plus every place GeoNames codes PPLC (capital of a political entity), so a capital is never missing because it is tiny — Valletta (~6,800) and Ngerulmud are both here.

Rules 2 and 3 exist because cities15000 is a population tier, not a superset of the cities500-derived set this endpoint used to serve. Because of them, 240 of the 31,793 places here sit below the 15,000 mark — 40 of them capitals — instead of the set stopping dead at it. The refresh script recomputes the retired cities500-only policy from the same dump on every run and refuses to write a snapshot that drops any of it, so the selection RULE is a strict superset of the one it replaced.

That guard cannot cover upstream churn, and a snapshot bump is therefore a data change, not a pure addition. At the 2026-09-14 re-pin, diffing the previous committed snapshot (records last modified 2026-07-28) against this one showed 7 of its 6,301 places no longer matching a row of the same name, country and division. Two were division-spelling changes upstream (Vienna, Salzburg), one a rename (Jinghong → Yunjinghong, same population 3 km away), and four were gone outright: Seria (BN, 30,097), Bohuniya (UA, 147,324), Nghi Xuân (VN, 118,000) and the 1.3-million Gorakhpur row GeoNames used to file under Haryana, whose only surviving namesake is the Uttar Pradesh city (674,246). The refresh script reports this diff on every run so the next bump states its own churn instead of inheriting this paragraph. Everything else the endpoint served before is still served, and most queries now return far more rows; three fields (elevation, demElevation, featureCode) are new.

What is deliberately out: sections of populated places (GeoNames PPLX, i.e. neighbourhoods), historical/abandoned/destroyed places, and country codes outside officially assigned ISO 3166-1 alpha-2 — which drops GeoNames' user-assigned XK.

Honest caveats, all inherited from the upstream data:

  • Population is a GeoNames figure: an administrative/city-proper count of mixed vintage, not a metropolitan total. Paris reads ~2.1 million (the commune), not the ~11 million metro area. Use it for ordering and rough sizing, never as a census input. A handful of places have no published figure and return population: null.
  • The two elevation fields are two different measurements and are never merged. elevation is what the source record states — sparse, published for 13.2% of places and null for the rest. demElevation is a digital-elevation-model sample at the point coordinate (SRTM3, GTOPO30 above 60°N), present for 99.8%. Coalescing them would publish a modelled number as a stated one, so they stay apart — and the elevation filters name the column they act on.
  • isCapital mirrors PPLC exactly. GeoNames designates at most one capital per country, so in multi-capital states only its choice is flagged (Pretoria, not Cape Town), and a few entries — Israel and Western Sahara among them — have no capital row at all.
  • GeoNames records many urban subdivisions as populated places in their own right, so they sit next to their parent city: New York City and Brooklyn, Paris and its arrondissements, Montreal's boroughs, Shanghai's districts. Sections explicitly coded PPLX are dropped, but these are not coded that way upstream — so /nearest around the Île de la Cité legitimately answers with the arrondissement whose GeoNames point is closest — Paris 04 Hôtel-de-Ville (0.404 km) — then the Paris commune row itself (0.434 km), then the rest of the twenty (Paris 01 Louvre, Paris 03 Temple, Paris 02 Bourse…) before it reaches Montreuil. Raise minPopulation or pin featureCode when you want one row per agglomeration: ?lat=48.8566&lng=2.3522&minPopulation=1000000&count=1 returns the Paris commune alone. Without the count (or a maxDistanceKm bound) the filter only changes which places the ranking is drawn from, so the rest of the page is the next-nearest million-plus cities — Brussels, London, Köln…
  • Where GeoNames holds two records with the same name in the same first-order division, only the more populous one is kept.

All filters genuinely filter:

  • country takes an ISO 3166-1 alpha-2 code (case-insensitive). A well-formed code with no cities returns an empty list, never another country's. Malformed values are a 400.
  • timezone takes an IANA identifier. Zones the snapshot uses are matched case-insensitively and echoed canonically; a real zone that no place here uses (UTC, America/Adak) returns an empty list with a warning rather than a false error, and a string that is not a zone at all is a 400.
  • admin1 matches a first-order division on its published spelling, ignoring case and diacritics — bavaria, Bavaria and BAVARIA all work.
  • featureCode pins GeoNames' own classification: PPL (populated place), PPLA (seat of a first-order administrative division), PPLA2 (seat of a second-order administrative division), PPLA3 (seat of a third-order administrative division), PPLA4 (seat of a fourth-order administrative division), PPLA5 (seat of a fifth-order administrative division), PPLC (capital of a political entity), PPLF (farming village), PPLG (seat of government of a political entity), PPLL (populated locality), PPLR (religious populated place), PPLS (populated places (a cluster)), STLMT (israeli settlement).
  • minDemElevation / maxDemElevation bound the modelled demElevation column — the near-complete one — so a height filter does not silently hide the 86.8% of places with no stated elevation. Places with no modelled value are excluded, and min > max is a 400.
  • search matches the name and the GeoNames ASCII alias, ignoring case, diacritics and apostrophes — sao paulo finds São Paulo, wroclaw finds Wrocław and xian finds Xi’an.
  • minPopulation keeps only places at or above the given figure; places with an unknown population are excluded, because "unknown" cannot be proven to clear the bar.
  • capital=true narrows to the 240 PPLC rows — capitals of political entities across the 245 countries and territories in the set, dependent territories included — and capital=false excludes them.
  • sort=population (default) lists the largest first with unknown populations last; sort=name is alphabetical.
  • count caps a page at 100 records and offset skips ahead, so large result sets are pageable.

Two ranked routes sit next to the filtered list:

  • /search?q=roch is autocomplete-shaped: everything whose name starts with the query first, then everything that merely contains it, each group ordered by population — so roch reaches Rochester before Rochefort-sur-Mer, and La Rochelle after both.
  • /nearest?lat=48.8566&lng=2.3522&maxDistanceKm=100 ranks by great-circle distance on the mean-Earth sphere. It never geocodes and never invents a place that is not in the snapshot; each record carries model and radiusMeters so the approximation is auditable.

Use it for

  • Populate a city picker or autocomplete with real names, regions, countries and coordinates
  • Seed demo maps and dashboards with correctly geocoded markers at country or continent density
  • Test timezone-aware scheduling against real IANA zone names per city
  • Resolve the nearest real city to a coordinate for map, locale and timezone prototypes
  • Build a capitals-only reference list straight from the GeoNames PPLC classification
  • Generate altitude-aware test fixtures from the modelled elevation of real settlements

Frequently asked questions

Which cities are included?

Every place in GeoNames' cities15000 tier (population 15,000 and up), plus the five largest places of every country from the deeper cities500 tier, plus every GeoNames-designated capital — 31,793 places across 245 countries and territories.

Are the population figures metro-area numbers?

No. They are GeoNames figures, which are administrative/city-proper counts of mixed vintage. Paris reads about 2.1 million (the commune), not the roughly 11 million metropolitan area, and a few places return null because GeoNames publishes no figure.

Why are there two elevation fields?

Because they are two different measurements. elevation is the figure the source record states and is published for only 13.2% of places; demElevation is sampled from a digital elevation model at the point coordinate and covers 99.8%. They are never merged, and minDemElevation/maxDemElevation filter the modelled column by name.

How is /search different from the search filter on the list?

/search ranks: names that start with your query come first, names that merely contain it come second, and both groups are ordered by population. The list route's search param is a plain contains-filter that keeps whatever sort order you asked for.

Why do Brooklyn and the Paris arrondissements appear as separate cities?

Because GeoNames classifies them as populated places, not as sections of one. Rows explicitly coded PPLX are excluded, but these are not, so they sit alongside their parent city. Raise minPopulation if you want one row per agglomeration.

Is South Africa's capital Cape Town or Pretoria here?

Pretoria. isCapital mirrors the GeoNames PPLC feature code exactly, and GeoNames marks at most one capital per country, so multi-capital states show only its choice.

Standards & references