GeoNames APIgeonames.org ↗
Access GeoNames geographic data via API: place search, reverse geocoding, postal codes, timezone lookup, and administrative hierarchy for locations worldwide.
What is the GeoNames API?
The GeoNames API exposes 6 endpoints covering place search, postal code lookup, reverse geocoding, and timezone resolution for geographic locations worldwide. The search_places endpoint returns toponyms filtered by name, bounding box, country, and fuzzy match factor, while timezone resolves any latitude/longitude pair to an IANA timezone ID, GMT/DST offsets, and local sunrise/sunset times.
curl -X GET 'https://api.parse.bot/scraper/5c4ebe03-64d2-491a-aead-fb7fccb55c42/search_places?lang=en&name=Paris&limit=5&query=London&style=SHORT&offset=0' \ -H 'X-API-Key: $PARSE_API_KEY'
Typed, relational, agent-ready
A generated client with real types, enums, and the links between objects — the structure a flat JSON response can't carry. Autocompletes in your editor and reads cleanly to coding agents.
- Fully typed · autocompletes
- Objects link to objects
- Typed errors & pagination
Typed Python client. Set up the SDK in your uv project, then pull this API’s typed client:
uv add parse-sdk uv run parse init uv run parse add --marketplace geonames-org-api
uv run parse add --marketplace pulls a pinned snapshot of this canonical API — it won’t change underneath you. To customize it, subscribe and swap to your own copy.
"""GeoNames API — search places, get details, find nearby, postal codes, timezones."""
from parse_apis.geonames_api import GeoNames, FeatureClass, Style, Sort, PlaceNotFound
client = GeoNames()
# Search for populated places matching "London", capped at 3 results
for place in client.places.search(query="London", feature_class=FeatureClass.P, limit=3):
print(place.name, place.countryCode, place.population)
# Drill into the first result for full details
summary = client.places.search(query="Paris", limit=1).first()
if summary:
detail = summary.details()
print(detail.name, detail.continentCode, detail.timezone.timeZoneId)
# Find nearby places from coordinates (Paris center)
for nearby in client.places.find_nearby(lat=48.8566, lng=2.3522, radius=1.0, limit=3):
print(nearby.name, nearby.distance, nearby.fcode)
# Postal code lookup
for pc in client.postalcodes.search(postalcode="90210", country="US", limit=3):
print(pc.postalCode, pc.placeName, pc.countryCode)
# Timezone lookup
tz = client.timezones.lookup(lat=40.7128, lng=-74.006)
print(tz.timezoneId, tz.gmtOffset, tz.dstOffset)
# Typed error handling on a bad ID
try:
client.places.get(geoname_id=9999999999)
except PlaceNotFound as exc:
print(f"Place not found: {exc.geoname_id}")
print("exercised: places.search / details / places.get / find_nearby / postalcodes.search / timezones.lookup")
Search for geographic places/toponyms by name, country, feature class, bounding box, or coordinates. Returns paginated results ordered by relevance by default. At least one search parameter (query, name, or name_equals) should be provided for meaningful results; combining with country or featureClass narrows the result set. Offset-based pagination: pass offset to advance through pages of results.
| Param | Type | Description |
|---|---|---|
| east | number | Bounding box east longitude |
| lang | string | Language for place names (ISO-639) |
| name | string | Place name to search for |
| west | number | Bounding box west longitude |
| fuzzy | number | Fuzzy matching factor (0-1) |
| limit | integer | Maximum number of results to return |
| north | number | Bounding box north latitude |
| query | string | General search query for place names |
| south | number | Bounding box south latitude |
| style | string | Response verbosity: SHORT, MEDIUM, LONG, FULL |
| offset | integer | Offset for pagination (number of items to skip) |
| country | string | ISO-3166 country code to filter by |
| orderby | string | Order results by: relevance, population, elevation |
| featureCode | string | GeoNames feature code (e.g. PPLC, ADM1, PPL) |
| name_equals | string | Exact place name match |
| featureClass | string | GeoNames feature class: A, H, L, P, R, S, T, U, V |
| continentCode | string | Continent code: AF, AS, EU, NA, OC, SA, AN |
{
"type": "object",
"fields": {
"geonames": "array of place summary objects with geonameId, name, toponymName, lat, lng, countryCode, countryName, population, fcode, fcl, adminName1, adminCode1",
"totalResultsCount": "integer total matching places"
}
}About the GeoNames API
Place Search and Detail
The search_places endpoint accepts a free-text name or query, optional bounding box coordinates (north, south, east, west), and a fuzzy factor between 0 and 1 to control approximate matching. Results return an array of place objects — each with lat, lng, countryCode, population, fcode (feature code), and adminName1 — plus a totalResultsCount for pagination. For deeper detail on any result, pass its geonameId to get_place_by_id, which returns alternateNames in multiple languages, a bbox boundary object, timezone offsets, and the full administrative hierarchy.
Postal Code Endpoints
postal_code_search accepts postalcode, placename, or their prefix variants (postalcode_startsWith, placename_startsWith), plus an ISO country filter. Each result in the postalCodes array includes the code, placeName, countryCode, lat/lng, and first-level administrative area fields. postal_code_country_info requires no inputs and returns per-country statistics: numPostalCodes, minPostalCode, and maxPostalCode — useful for validating user input ranges before running a search.
Reverse Geocoding and Timezone
reverse_geocode_find_nearby takes a lat/lng pair and optional radius (km) and limit, returning nearby toponyms sorted by distance with their fcode and geonameId. The timezone endpoint accepts the same coordinate inputs and returns timezoneId (IANA format), gmtOffset, dstOffset, rawOffset, and time (current local time string), along with sunrise and sunset timestamps for that location's date.
The GeoNames API is a managed, monitored endpoint for geonames.org — not a raw scraper you maintain. Every endpoint is automatically health-checked on a schedule, and when geonames.org changes and a check fails, the API is automatically queued for repair and re-verified. It is built to keep working as the site underneath it changes.
This isn't an official geonames.org API — it's an independent, maintained REST wrapper over public data. Where the source has no official API (or only a limited one), Parse gives you a stable contract over a source that never promised one, and keeps it current. Need a new endpoint or field? You can revise it yourself in plain English and the agent rebuilds it against the live site in minutes — contributing the change back to the shared API is free.
Will this API break when the source site changes?+
Is this an official API from the source site?+
Can I fix or extend this API myself if I need a new endpoint or field?+
What happens if I call an endpoint that has an issue?+
- Resolve a user-submitted address to coordinates and timezone using
search_placesandtimezonetogether - Validate and normalize postal codes at checkout using
postal_code_searchwith a country filter - Display local time and UTC offset for any map click using the
timezoneendpoint'stimezoneIdandgmtOffsetfields - Find all populated places within a geographic bounding box for regional analytics using
search_placeswithnorth/south/east/westparams - Reverse-geocode device GPS coordinates to the nearest named feature using
reverse_geocode_find_nearby - Audit postal code coverage by country before building a shipping zone matrix using
postal_code_country_info - Fetch alternate-language place names for multilingual UIs via
get_place_by_idwith thealternateNamesarray
| Tier | Price | Credits/month | Rate limit |
|---|---|---|---|
| Free | $0/mo | 100 | 5 req/min |
| Hobby | $30/mo | 1,000 | 20 req/min |
| Developer | $100/mo | 5,000 | 100 req/min |
One credit = one API call regardless of which marketplace API you call. Exceeding the rate limit returns a 429 response. Authenticate with the X-API-Key header.
Does GeoNames have an official developer API?+
What does `get_place_by_id` return beyond basic coordinates?+
geonameId returns the place's full bounding box (bbox with east/west/north/south), a timezone object with gmtOffset, dstOffset, and timeZoneId, population, and an alternateNames array where each entry has a name and lang field. The style parameter controls verbosity: SHORT omits alternateNames, FULL includes them.Does the API return elevation data for places?+
How should I structure postal code searches for reliable results?+
postal_code_search endpoint works best when you supply at least one of postalcode, placename, postalcode_startsWith, or placename_startsWith together with a country ISO code. Without a country filter, results may span multiple countries and hit the default limit quickly. Use postal_code_country_info first to confirm a country has coverage before querying.Does the API expose administrative boundary polygons or GeoJSON shapes?+
bbox) from get_place_by_id or as a point (lat/lng) across all endpoints. You can fork this API on Parse and revise it to add an endpoint that returns GeoJSON boundaries if your use case requires polygon data.