DocsGeocoding

Geocoding

The Geocoding API converts between addresses and coordinates. It runs on the global OpenStreetMap dataset - continuously updated by millions of contributors - so coverage is worldwide and improves over time without any action on your part.

By default responses are plain JSON with named "lat" and "lon" string fields - no coordinate-order ambiguity. If you prefer GeoJSON (FeatureCollection with geometry.coordinates), add format=geojson to any request. In that case coordinates follow the GeoJSON standard: [longitude, latitude].

All geocoding endpoints require an X-Api-Key header. Get your key from the dashboard - it's the same key used for all PickPoint APIs.

Forward geocoding

Address or name → coordinates. Returns a JSON array of candidates ranked by importance - a score that combines how well-known the place is (derived from Wikipedia article link counts across languages) and how closely it matches the query text. The Eiffel Tower scores ~0.81; a village named Paris in rural Texas scores ~0.25.

In most cases the first result is what you want. For ambiguous queries - "Moscow" matches Russia, Idaho, and several other places - either show the top few candidates or constrain the search with countrycodes.

curl "https://api.pickpoint.io/v2/geocode/forward?q=Eiffel+Tower,+Paris&limit=1" \
  -H "X-Api-Key: YOUR_KEY"
[
  {
    "place_id":   5013364969,
    "osm_type":   "node",
    "osm_id":     5013364969,
    "lat":        "48.8583701",
    "lon":        "2.2944813",
    "class":      "tourism",
    "type":       "attraction",
    "place_rank": 30,
    "importance": 0.8142,
    "addresstype":"attraction",
    "name":       "Eiffel Tower",
    "display_name": "Eiffel Tower, Champ de Mars, Paris, Île-de-France, France",
    "address": {
      "attraction":  "Eiffel Tower",
      "road":        "Champ de Mars",
      "suburb":      "7th arrondissement",
      "city":        "Paris",
      "postcode":    "75007",
      "country":     "France",
      "country_code":"fr"
    },
    "boundingbox": ["48.8572","48.8596","2.2933","2.2956"]
  }
]

Key fields in the response:

  • lat / lon - coordinates as strings. Parse to float when you need arithmetic.
  • display_name - full human-readable label, ready to show to users.
  • importance - relevance score 0–1. The array is already sorted by this; higher = more likely to be the intended result.
  • place_rank - administrative level: 4 = country, 8 = state, 14 = city, 26 = street, 30 = POI.
  • osm_type + osm_id - stable OSM identifiers. Combine as N123 (node), W123 (way), or R123 (relation) for the Lookup endpoint.
  • address - structured components: road, suburb, city, postcode, country. The POI name appears under its own category key (e.g. "attraction": "Eiffel Tower").
  • boundingbox - [min_lat, max_lat, min_lon, max_lon] for the matched feature.

Handling ambiguity

Without constraints, "Paris" returns the French capital first - but it also matches Paris, Texas. "High Street" matches over 5,000 streets in the UK alone. Two parameters fix this:

  • countrycodes=fr - restrict to specific countries (ISO 3166-1 alpha-2, comma-separated).
  • viewbox + bounded=1 - restrict to a geographic bounding box. Pass the user's visible map area.
# Only results strictly inside Paris bounding box
curl "https://api.pickpoint.io/v2/geocode/forward?q=Musée&countrycodes=fr&viewbox=2.25,48.81,2.42,48.91&bounded=1&limit=5" \
  -H "X-Api-Key: YOUR_KEY"

Reverse geocoding

Coordinates → address. Returns a single JSON object (not an array). The zoom parameter controls how specific the result is: 18 (default) returns a full postal address, 10 returns the city, 3 returns only the country.

curl "https://api.pickpoint.io/v2/geocode/reverse?lat=48.8584&lon=2.2945&zoom=18" \
  -H "X-Api-Key: YOUR_KEY"
{
  "place_id":   5013364969,
  "osm_type":   "node",
  "osm_id":     5013364969,
  "lat":        "48.8583701",
  "lon":        "2.2944813",
  "display_name": "Eiffel Tower, Champ de Mars, 7th arrondissement, Paris, 75007, France",
  "address": {
    "attraction":  "Eiffel Tower",
    "road":        "Champ de Mars",
    "suburb":      "7th arrondissement",
    "city":        "Paris",
    "state":       "Île-de-France",
    "postcode":    "75007",
    "country":     "France",
    "country_code":"fr"
  },
  "boundingbox": ["48.8572","48.8596","2.2933","2.2956"]
}

Lower zoom levels are useful when you want a city or region label regardless of coordinate precision - e.g. labelling GPS tracks on a zoomed-out map. Zoom scale: 3 = country · 8 = county · 10 = city · 14 = suburb · 16 = street · 18 = building.

Address search (autocomplete)

Accepts partial queries and is optimised for low latency - fast enough to call on each keystroke. Returns an array in the same format as forward geocoding. Debounce to ~250 ms on the client and cancel in-flight requests when the query changes to avoid stale responses overwriting fresh ones.

# As the user types "Baker St" in a UK app
curl "https://api.pickpoint.io/v2/address/search?q=Baker+St&countrycodes=gb&limit=5&viewbox=-0.18,51.49,-0.12,51.53" \
  -H "X-Api-Key: YOUR_KEY"

Place lookup

Fetch full details for a known OSM object by its osm_type and osm_id. The prefix encodes the type: N = node, W = way, R = relation. Pass up to 50 IDs in a single request.

# Fetch details for a known osm_type + osm_id
curl "https://api.pickpoint.io/v2/geocode/lookup?osm_ids=N5013364969" \
  -H "X-Api-Key: YOUR_KEY"

This avoids repeating a text search when you've already stored the identifiers. Useful for displaying up-to-date place details from a previously saved result.

Language and script support

Add a language BCP 47 tag to get display_name and address fields in a specific language. OSM contains place name translations in 100+ languages, so coverage is generally good worldwide. Non-Latin scripts work in both queries and responses - Arabic, Chinese, Cyrillic, Japanese, Korean. Transliteration also works: "Moskva" finds Moscow, "Köln" and "Cologne" both find the same city.

Response formats

By default the API returns plain JSON. Pass format= to get any Nominatim-compatible output format:

format=ShapeCoordinatesNotes
json (default)Array of objectslat, lon stringsFlat structure, easy to use. Named fields, no coordinate-order ambiguity.
geojsonGeoJSON FeatureCollection[lon, lat] in geometry.coordinatesSame shape as Address Search output. Use for GeoJSON-native pipelines.
jsonv2Array of objectslat, lon stringsExtended JSON with category, type, place_rank and additional metadata.
geocodejsonGeocodeJSON FeatureCollection[lon, lat]Open geocoding standard with a structured geocoding object per feature.
xmlXML documentlat/lon attributesNominatim-compatible XML for legacy system integrations.

Things worth knowing before you ship

  • An empty array is not an error. [] is a valid 200 response - the query simply didn't match. Prompt the user to refine their input rather than silently failing.
  • Specific queries win. "221B Baker Street, London, UK" is vastly more reliable than "baker street". Include city and country whenever you know them.
  • lat and lon are strings. Parse them with parseFloat() or equivalent before doing any arithmetic or passing them to a map library.
  • Cache aggressively. Geocoding output for a given address is stable. Store coordinates in your database and treat geocoding as a one-time normalisation step.
  • Never expose your key in the browser. Proxy all calls through your backend.
  • Postcodes geocode too. Pass a postcode alone - "SW1A 2AA", "10001" - to get a centroid for that postal district.

API Reference ↗RoutingDevice TrackingUnder the Hood →