Entur Developer
Geocoder

Migrating to Geocoder v3

Geocoder v3 is a new version of Entur's geocoding API with cleaner parameter names, structured response objects, and unambiguous IDs. This guide maps every v2 parameter and response field to its v3 equivalent. Geocoder v1/v2 was deprecated as of 12.06.2026.

See also the Geocoder v3 documentation.

Parameter changes

Common (autocomplete + reverse)

v2v3Notes
sizelimit
langlangunchanged; also accepted on /place
layerslayerssee layers
sourcessourcessee sources
boundary.countrycountriescomma-separated
boundary.county_idscountiescomma-separated
boundary.locality_idslocalitiescomma-separated
tariff_zone_ids(removed)use fareZones instead
(new in v3)fareZonescomma-separated; refs must be FareZone-shaped (AUTH:FareZone:ID).
tariff_zone_authorities(removed)use fareZoneAuthorities instead
fare_zone_authoritiesfareZoneAuthoritiescomma-separated
multiModalmultimodalvalues: parent (default), child, all; see multimodal
categories (v2 reverse only)stopPlaceTypesNeTEx stop place types; see below

stopPlaceTypes takes NeTEx stop place types (railStation, airport, ...). On its own it restricts results to stop places of those types and excludes other layers - same semantics as v2 categories. The v2 layer-like category values (street, vegadresse, GroupOfStopPlaces, poi) map to layers instead.

Combine stopPlaceTypes with an explicit layers filter to mix mode-filtered stop places with whole layers in one request. The two compose as a union: the type filter constrains only the stopPlace layer, while any other requested layer is returned additively. To get rail stations together with groups of stop places (v2's categories OR behaviour, in a single request):

Code
?q=oslo&layers=stopPlace,groupOfStopPlaces&stopPlaceTypes=railStation

If layers is given but does not include stopPlace, the type filter has no stopPlace layer to constrain and is ignored.

Autocomplete (/v3/autocomplete)

v2v3Notes
textqoptional in v3: omitting q with at least one filter lists all matching places
focus.point.latlatfocus point latitude
focus.point.lonlonfocus point longitude
focus.scaleradiusfocus radius in km (default 50, decimals accepted); see default differs from v2
focus.weightweight0-1 (default 0.5); see weight semantics
focus.function(removed)v2's focus.function (linear, exp, etc.) is removed; v3 behaves roughly like v2's exp
(new in v3)bboxrestrict results to minLon,minLat,maxLon,maxLat - a hard filter, unlike the focus point's soft bias

Reverse (/v3/reverse)

v2v3Notes
point.latlatquery point latitude
point.lonlonquery point longitude
boundary.circle.radiusradiuskm in both v2 and v3 (decimals accepted)
(new in v3)distanceSortsort by distance from the query point (default true) or by relevance when false

Place (/v3/place)

v2v3Notes
idsidscomma-separated; ID shape differs between v2/v3 (see ID format)

layers

The v3 layer values are the same indexed data v2 already returned, just labelled precisely - in v2 venue held NSR stop places and everything else fell under address:

v2 layersv3 layersdata origin
addressaddressmatrikkel addresses
addressstreetmatrikkel streets
venuestopPlaceNSR stop places
addressgroupOfStopPlacesNSR group of stop places
addresspoiOSM POIs; custom-poi (new in v3)
addressplacekartverket-stedsnavn (cities, districts)

Default behaviour (no layers filter): same result set as v2 - only the layer value changed. All layers are eligible, with one exclusion: addresses are hidden from autocomplete unless the query text contains a digit or sources includes kartverket-matrikkelenadresse. Reverse hides addresses unless the caller opts in via sources=kartverket-matrikkelenadresse or layers=address.

sources

The source values are reorganised rather than replaced, and with one exception the data behind them is not new. v2's values are Pelias-legacy labels that say nothing about where a result came from, so there is no clean 1:1 mapping - note that openstreetmap is valid in both versions but means something else in each:

v2 sourcewhat it actually heldv3
openstreetmapNSR multimodal parent stopsnsr (+ multimodal=parent)
geonamesNSR multimodal child stopsnsr (+ multimodal=child)
whosonfirststandalone NSR stops, stedsnavn places, matrikkel streets, OSM POIsnsr, kartverket-stedsnavn, kartverket-matrikkelenadresse (+ layers=street), openstreetmap
openaddressesmatrikkel addresses (with house number)kartverket-matrikkelenadresse (+ layers=address)

So nsr and kartverket-stedsnavn are new labels for data v2 already returned - stedsnavn places came back as source: "whosonfirst", layer: "address". Only custom-poi is a data set with no v2 counterpart.

To reproduce v2 results, omit sources - the v3 default returns the same data set. Carrying a v2 sources value across gives wrong results either way, and neither case errors:

  • whosonfirst, geonames and openaddresses are not v3 values, so they match nothing. sources=openaddresses silently drops every address and street.
  • openstreetmap is a valid v3 value with a different meaning: in v2 it selected NSR multimodal parent stops, in v3 it selects OSM POIs. The filter keeps working and returns the wrong data.

To narrow the result set in v3, use layers and multimodal instead; sources is only useful for picking a data origin.

Weight semantics (changed)

weight is renamed straight across from focus.weight, but the math is different. In v2 it was an open-ended scalar fed through a curve (default ~15). In v3 it is a linear blend between importance ranking (0) and pure location preference (1) - avoid the extremes unless that is what you want:

  • weight=0 - no focus bias, results ranked purely on text relevance and importance.
  • weight=1 - pure location preference: importance is ignored entirely, only proximity counts.
  • weight=0.5 (default) - balanced: importance and proximity contribute roughly equally to ranking.

The v3 default tilts toward importance more than v2 does, so far-away major cities can still win against near-focus same-prefix streets (e.g. "Bergen" from Oslo still returns Bergen, not Bergensgata). If you tuned focus.weight in v2 do not just copy the number across.

Default radius differs from v2

Do not copy your v2 focus.scale value into v3 radius. v2 saturates large values (anything past ~300 km behaves the same, so the v2 default of 2500 was effectively ~120 km); v3 treats the number as a literal focus radius, so radius=2500 disables the bias entirely. If you used v2's default or any large focus.scale, use radius in the 50-150 km range.

Focus parameters are a bundle

lat, lon, radius, and weight on /v3/autocomplete belong together. Sending any of them without both lat and lon is a 400 error.

multimodal

Applies to /v3/autocomplete and /v3/reverse.

An NSR multimodal stop groups several stop places (e.g. a bus terminal + train station hub) under a parent. Most NSR stop places are monomodal - standalone, not part of any such group - and those always appear in results regardless of this parameter. multimodal only decides whether multimodal parents, children, or both come through alongside them.

  • parent (default) - monomodal stops + multimodal parents; multimodal children hidden.
  • child - monomodal stops + multimodal children; multimodal parents hidden.
  • all - monomodal stops + multimodal parents + multimodal children.

The role of each returned stop is reported per feature in the stopPlaceRole response field (parent / child / standalone), so you no longer need to infer it from source as in v2.

ID format

v3 uses canonical, fully-qualified IDs. v2 uses legacy/abbreviated forms for backwards compatibility.

Entityv2 IDv3 ID
Stop placeNSR:StopPlace:NNSR:StopPlace:N
Group of stop placesNSR:GroupOfStopPlaces:NNSR:GroupOfStopPlaces:N
OSM POIOSM:TopographicPlace:NOSM:TopographicPlace:N
Matrikkel addressbare numeric (e.g. 225678815)KVE:PostalAddress:N
Matrikkel streetKVE:TopographicPlace:KOMNR-NAMEKVE:TopographicPlace:KOMNR-NAME (unchanged)
Stedsnavn placebare numeric (e.g. 434810)KVE:PlaceName:N
Boundary filter (kommune/fylke code)bare numeric (e.g. 0301, 03)KVE:TopographicPlace:N
Grunnkrets (in address.boroughId)whosonfirst:borough:NKVE:Borough:N (N = 8-digit grunnkretsnummer: KOMNR + 4-digit sequence, e.g. 34200205)

In v2 bare numerics on the wire are ambiguous - they can be stedsnavn places or postal addresses. v3 removes the ambiguity by giving each entity a fully-qualified namespace.

Response format

Both v2 and v3 return a GeoJSON FeatureCollection. High-level shape changes:

  • Feature properties use structured objects (names, address, transportModes) instead of v2's flat fields.
  • A metadata object at the top level replaces v2's geocoding block. It carries the echoed query, resultCount, and an ISO 8601 timestamp. Errors come back as HTTP 4xx with an application/problem+json body rather than under geocoding.errors.
  • /v3/reverse responses include distance on each feature, in kilometres with 3-decimal precision (same units as v2).
  • Features with a real extent (streets, groups of stop places) carry a GeoJSON bbox ([minLon, minLat, maxLon, maxLat]); point features omit it.

The per-property table below is authoritative; see layers and sources for value-set changes on layer and source.

Property mapping (properties.*)

Field-by-field migration. Anything not listed is unchanged; anything marked _(removed)_ has no v3 equivalent.

v2v3notes
ididID shape differs - see ID format
namenames.default
labelnames.displayformatted display name with locality context
popular_namenames.labelcolloquial name; rarely populated today
housenumberaddress.houseNumber
streetaddress.streetName
postalcodeaddress.postalCode
country_a / countrycodeaddress.countryCodev2 was ISO 3166-1 alpha-3 ("NOR") on country_a; countrycode was declared but never populated. v3 collapses both into countryCode as alpha-2 lowercase ("no"). Case-sensitive client comparisons will break silently.
countyaddress.county
county_gidaddress.countyIdv2 prefixed whosonfirst:county:; v3 returns the raw indexed ID (e.g. KVE:TopographicPlace:03)
localityaddress.locality
locality_gidaddress.localityIdv2 prefixed whosonfirst:locality:; v3 returns the raw indexed ID
boroughaddress.borough
borough_gidaddress.boroughIdv2 returns whosonfirst:borough:N; v3 returns KVE:Borough:N where N is the grunnkretsnummer (Norwegian sub-municipal statistical unit)
cityaddress.localityv2 carried both city and locality for the same value; v3 keeps only locality
layerlayernew enum values; see layers
sourcesourceNSR stops normalised: v2 returned "openstreetmap" (multimodal parent), "geonames" (child), or "whosonfirst" (standalone); v3 always returns "nsr". The parent/child/standalone role v2 encoded here is now exposed explicitly in the new stopPlaceRole field (next row). openaddresses -> kartverket-matrikkelenadresse. See sources.
(new in v3)stopPlaceRoleStop place hierarchy role: parent / child / standalone. Replaces inferring it from the v2 source (openstreetmap/geonames/whosonfirst). Set on stopPlace features; parent/child both mean multimodal.
categorystopPlaceTypes + categoriesNeTEx stop place types (e.g. railStation) split out from OSM tags (e.g. restaurant)
modetransportModesarray of { mode, subMode } objects instead of pair-encoded JSON
tariff_zonesfareZonesnot a straight rename; see below
distancedistancereverse only; kilometres with 3-decimal precision in both v2 and v3
descriptiondescriptionper-language description. v2 shape: [{lang: text}, ...] (array of singleton maps). v3 shape: {lang: text, ...} (flat object keyed by ISO 639-2 alpha-3 code)
accuracy(removed)Pelias-ism (point/centroid); not meaningful here
gid(removed)the Pelias source:layer:id triple; use id
source_id(removed)duplicate of id
type (in properties)(removed)always "Feature" on the feature itself; the duplicate inside properties is gone

fareZones is not a straight rename of tariff_zones. v3 fareZones carries only AUTH:FareZone:ID-shaped refs, while v2's tariff_zones merged both TariffZone and FareZone refs for backwards compatibility. TariffZone refs are no longer surfaced in v3 responses, and TariffZone-shaped values sent as filter input do not match anything.

Autocomplete example

v2 request:

Code
GET /v2/autocomplete?text=Nationaltheatret&lang=no&size=1&layers=venue

v2 response:

JSONCode
{ "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [10.7335, 59.9144] }, "properties": { "id": "NSR:StopPlace:337", "layer": "venue", "source": "openstreetmap", "name": "Nationaltheatret", "label": "Nationaltheatret, Oslo", "category": ["railStation", "metroStation"] } }] }

v3 request:

Code
GET /v3/autocomplete?q=Nationaltheatret&lang=no&limit=1&layers=stopPlace

v3 response:

JSONCode
{ "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [10.73350, 59.91440] }, "properties": { "id": "NSR:StopPlace:337", "names": { "default": "Nationaltheatret", "display": "Nationaltheatret, Oslo" }, "layer": "stopPlace", "address": { "locality": "Oslo", "county": "Oslo", "countryCode": "no" }, "transportModes": [{ "mode": "rail" }, { "mode": "metro", "subMode": "metro" }], "stopPlaceTypes": ["railStation", "metroStation"], "source": "nsr" } }], "bbox": [10.73350, 59.91440, 10.73350, 59.91440], "metadata": { "query": { "text": "Nationaltheatret", "limit": 1, "lang": "no", "filters": { "layers": ["stopPlace"] } }, "resultCount": 1, "timestamp": "2025-03-04T11:00:00Z" } }

Reverse geocode example

v2 request:

Code
GET /v2/reverse?point.lat=59.9110&point.lon=10.7522&boundary.circle.radius=0.5&size=1

v3 request:

Code
GET /v3/reverse?lat=59.9110&lon=10.7522&radius=0.5&limit=1

v3 response (abbreviated):

JSONCode
{ "type": "FeatureCollection", "features": [{ "type": "Feature", "geometry": { "type": "Point", "coordinates": [10.75220, 59.91100] }, "properties": { "id": "NSR:StopPlace:337", "names": { "default": "Nationaltheatret", "display": "Nationaltheatret, Oslo" }, "layer": "stopPlace", "source": "nsr", "distance": 0.012 } }], "metadata": { "query": { "lat": 59.9110, "lon": 10.7522, "limit": 1, "lang": "no" }, "resultCount": 1, "timestamp": "2025-03-04T11:00:00Z" } }
Last modified on
Did you find what you were looking for?