Skip to content

Structured Geocoding

Free

Starter

Standard

Professional

The structured geocoding endpoint is purpose-built for finding addresses and administrative places. Rather than passing a single string and leaving the rest up to natural language parsing, you provide the components directly, reducing ambiguity. This is a natural fit for data already broken into fields (e.g. from a database, spreadsheet, or a multi-field input form).

For points of interest, businesses, and other venues, use the forward search endpoint, which is tuned for free-form text queries.

Endpoint: https://api.stadiamaps.com/geocoding/v1/search/structured

Example Code

Installation Instructions

The Stadia Maps JavaScript/TypeScript SDK is available for any package manager that supports the npm registry.

NPM Downloads

npm install @stadiamaps/api
yarn add @stadiamaps/api
bun add @stadiamaps/api
import { GeocodingApi, Configuration } from '@stadiamaps/api';

// If you are writing for a backend application or can't use domain-based auth,
// then you'll need to add your API key like so:
// 
// const config = new Configuration({ apiKey: "YOUR-API-KEY" }); (1)
// You can also use our EU endpoint to keep traffic within the EU using the basePath option:
// const config = new Configuration({ basePath: "https://api-eu.stadiamaps.com" });
// const api = new GeocodingApi(config);
const api = new GeocodingApi();

const res = await api.searchStructured({ street: "Põhja pst", houseNumber: "27", locality: "Tallinn", country: "EE" });
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

The Stadia Maps Python SDK is available through any package manager that supports PyPi.

PyPI - Downloads

pip install stadiamaps
uv add stadiamaps
poetry add stadiamaps
import os
import stadiamaps
from stadiamaps.rest import ApiException

# You can also use our EU endpoint to keep traffic within the EU like so:
# configuration = stadiamaps.Configuration(host="https://api-eu.stadiamaps.com")
configuration = stadiamaps.Configuration()

# Configure API key authentication (ex: via environment variable). (1)
configuration.api_key['ApiKeyAuth'] = os.environ["API_KEY"]

with stadiamaps.ApiClient(configuration) as api_client:
    # Create an instance of the API class
    api_instance = stadiamaps.GeocodingApi(api_client)

    try:
        res = api_instance.search_structured(street="Põhja pst", house_number="27", locality="Tallinn", country="EE")
    except ApiException as e:
        # Add your error handling here
        print("Exception when calling the Stadia Maps API: %s\n" % e)
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

If aren't already using Maven Central, add the repository in your Gradle build script.

repositories {
    mavenCentral()
}

Then, add the API package and its dependencies.

build.gradle.kts
dependencies {
    val retrofitVersion = "2.12.0"

    // API package
    implementation("com.stadiamaps:api:7.1.0")

    // Dependencies
    implementation("com.squareup.moshi:moshi-kotlin:1.15.2")
    implementation("com.squareup.moshi:moshi-adapters:1.15.2")
    implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")
    implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
    implementation("com.squareup.retrofit2:converter-moshi:$retrofitVersion")
    implementation("com.squareup.retrofit2:converter-scalars:$retrofitVersion")
}
build.gradle
dependencies {
    def retrofitVersion = "2.12.0"

    // API package
    implementation 'com.stadiamaps:api:7.1.0'

    // Dependencies
    implementation 'com.squareup.moshi:moshi-kotlin:1.15.2'
    implementation 'com.squareup.moshi:moshi-adapters:1.15.2'
    implementation 'com.squareup.okhttp3:logging-interceptor:4.12.0'
    implementation "com.squareup.retrofit2:retrofit:${retrofitVersion}"
    implementation "com.squareup.retrofit2:converter-moshi:${retrofitVersion}"
    implementation "com.squareup.retrofit2:converter-scalars:${retrofitVersion}"
}

Our API package is available on Maven Central. All you need to do is add a few dependencies to your pom.xml.

pom.xml
<properties>
    <retrofit.version>2.12.0</retrofit.version>
</properties>

<dependencies>
    <!-- API package -->
    <dependency>
        <groupId>com.stadiamaps</groupId>
        <artifactId>api</artifactId>
        <version>7.1.0</version>
    </dependency>

    <!-- Dependencies -->
    <dependency>
        <groupId>com.squareup.moshi</groupId>
        <artifactId>moshi-kotlin</artifactId>
        <version>1.15.2</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.moshi</groupId>
        <artifactId>moshi-adapters</artifactId>
        <version>1.15.2</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.okhttp3</groupId>
        <artifactId>logging-interceptor</artifactId>
        <version>4.12.0</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>retrofit</artifactId>
        <version>${retrofit.version}</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>converter-moshi</artifactId>
        <version>${retrofit.version}</version>
    </dependency>
    <dependency>
        <groupId>com.squareup.retrofit2</groupId>
        <artifactId>converter-scalars</artifactId>
        <version>${retrofit.version}</version>
    </dependency>
</dependencies>
// Imports (at the top of your source file; we've used some wildcard imports for simplicity)
import com.stadiamaps.api.*
import com.stadiamaps.api.auth.ApiKeyAuth
import com.stadiamaps.api.infrastructure.*
import com.stadiamaps.api.models.*

// Set your API key (from an environment variable in this case) (1)
val apiKey = System.getenv("STADIA_API_KEY") ?: throw RuntimeException("API Key not set")

// Defining the host is optional and defaults to https://api.stadiamaps.com
// You can also use our EU endpoint to keep traffic within the EU like so:
// val client = ApiClient(baseUrl = "https://api-eu.stadiamaps.com")
val client = ApiClient()
client.addAuthorization("ApiKeyAuth", ApiKeyAuth("query", "api_key", apiKey))

// Configure a service for the group of APIs we want to talk to
val service = client.createService(GeocodingApi::class.java)

// Set up the request.
// Note: this code is blocking for demonstration purposes.
// If you're using Kotlin with coroutines,
// you can also use these asynchronously within suspend functions.
// Synchronous code can enqueue a callback to avoid blocking
// (you'll definitely want to do one of these instead when on the main thread of an app).
// See the docs for details: https://square.github.io/retrofit/2.x/retrofit/retrofit2/Call.html
val res = service.searchStructured(street = "Põhja pst", houseNumber = "27", locality = "Tallinn", country = "Estonia").execute()

if (res.isSuccessful) {
    println("Found result: ${res.body()}")
} else {
    println("Request failed with error code ${res.code()}")
}
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

Our Swift SDK is distributed using the Swift Package Manager (SPM). Apple's documentation shows how to add a Swift Package dependency to your Xcode project. On the Add Package screen, you can find our package by its repository URL: https://github.com/stadiamaps/stadiamaps-api-swift.

import StadiaMaps

// This setup code can go anywhere before you actually make an API call (typically in your app init)
func setupStadiaMapsAPI() {
    // Set your API key (1)
    StadiaMapsAPI.customHeaders = ["Authorization": "Stadia-Auth YOUR-API-KEY"]
    // Optionally use our EU endpoint to keep traffic within the EU
    // StadiaMapsAPI.basePath = "https://api-eu.stadiamaps.com"
}

// This function demonstrates how to call the Stadia Maps API.
// If you have not yet adopted async/await in your Swift codebase, you can use the Task API
// to call async functions in a non-async context: https://developer.apple.com/documentation/swift/task.
func myFunction() async throws {
    let res = try await GeocodingAPI.searchStructured(houseNumber: "27", street: "Põhja pst", locality: "Tallinn", country: "EE")

    // Do something with the response...
    print(res)
}
  1. Learn how to get an API key in our authentication guide.
Installation Instructions

Composer

To install the package via Composer, add stadiamaps/api to your composer.json:

{
  "require": {
    "stadiamaps/api": "5.*"
  }
}

Then run composer install.

Manual Installation

You can also download the files manually and include autoload.php in your scripts:

<?php
require_once('/path/to/OpenAPIClient-php/vendor/autoload.php');
<?php
// use or require, depending on your installation method.

// Configure API key authorization (replace with your Stadia Maps API key) (1)
$config = OpenAPI\Client\Configuration::getDefaultConfiguration()->setApiKey('api_key', 'YOUR-API-KEY');
// You can also use our EU endpoint to keep traffic within the EU using setHost:
// $config = Configuration::getDefaultConfiguration()->setApiKey('api_key', 'YOUR-API-KEY')->setHost('https://api-eu.stadiamaps.com');

$apiInstance = new OpenAPI\Client\Api\GeocodingApi(
    new GuzzleHttp\Client(),
    $config
);

try {
    // Named arguments (PHP 8+) keep the call readable when you only want to set a few fields.
    // IDEs like PhpStorm can help with argument labeling.
    $result = $apiInstance->searchStructured(street: 'Põhja pst', house_number: '27', locality: 'Tallinn', country: 'EE');
} catch (Exception $e) {
    // Add your error handling here
    echo 'Exception when calling the Stadia Maps API: ', $e->getMessage(), PHP_EOL;
}
  1. Learn how to get an API key in our authentication guide.
curl "https://api.stadiamaps.com/geocoding/v1/search/structured?street=P%C3%B5hja%20pst&house_number=27&locality=Tallinn&country=EE&api_key=YOUR-API-KEY"

Can I Store Geocoding API Results?

Unlike most vendors, we won't charge you 10x the standard fee per request to store geocoding results long-term! However, we do require an active Standard, Professional, or Enterprise subscription to permanently store results (e.g. in a database). Temporary storage in the normal course of your work is allowed on all plans. See our terms of service for the full legal terms.

Query String Parameters

Parameter Type Required Description Default Example
address string no A street name, optionally with a house number. Mutually exclusive with house_number, street, and unit. none 11 Wall Street
house_number string no A house or building number. Requires street. Mutually exclusive with address. none 11
street string no A street name. Mutually exclusive with address. none Wall Street
unit string no The apartment, suite, or unit number. Requires both house_number and street. Mutually exclusive with address. none 4B
neighbourhood string no Varies by area, but has a locally specific meaning (may not always be an administrative unit). none Financial District
borough string no A unit within a city (not widely used, but present in places such as NYC and Mexico City). none Manhattan
locality string no The city, village, town, etc. that the place / address is part of. none New York
county string no Administrative divisions between localities and regions. Not commonly used as input to structured geocoding. none New York County
region string no Typically the first administrative division within a country. For example, a US state or a Canadian province. none New York
postalcode string no A mail sorting code; format varies by area. none 10005
country string (full name, ISO 3116-1 alpha-2 or alpha-3) no A full name (ex: Canada), or a 2 or 3 character ISO code. Prefer ISO codes when possible. none United States
focus.point.lat float no The latitude of the point to focus the search on. This will bias results toward the focus point. Requires focus.point.lon none 48.581755
focus.point.lon float no The longitude of the point to focus the search on. This will bias results toward the focus point. Requires focus.point.lat none 7.745843
boundary.rect.min_lon float no Defines the min longitude component of a bounding box to limit the search to. Requires all other boundary.rect parameters to be specified. none 139.2794
boundary.rect.max_lon float no Defines the max longitude component of a bounding box to limit the search to. Requires all other boundary.rect parameters to be specified. none 140.1471
boundary.rect.min_lat float no Defines the min latitude component of a bounding box to limit the search to. Requires all other boundary.rect parameters to be specified. none 35.53308
boundary.rect.max_lat float no Defines the max latitude component of a bounding box to limit the search to. Requires all other boundary.rect parameters to be specified. none 35.81346
boundary.circle.lat float no The latitude of the center of a circle to limit the search to. Requires boundary.circle.lon. none 43.818156
boundary.circle.lon float no The latitude of the center of a circle to limit the search to. Requires boundary.circle.lat. none -79.186484
boundary.circle.radius float no Tho radius of the circle (in kilometers) to limit the search to. Requires the other boundary.circle parameters to take effect. 50 35
layers comma-delimited string array no A list of layers, to limit the search to. all layers address,venue
sources comma-delimited string array no A list of sources, to limit the search to. all sources openstreetmap,wof
boundary.country comma-delimited string array no A list of countries (ISO 2 or 3 character code) to limit the search to. none GBR,FRA
boundary.gid GID no The GID of a region to limit the search to (note that these are not stable for all datasets; OSM features can change ID, for example). none whosonfirst:locality:101748355
size integer no The maximum number of results to return. 10 3
lang string no A BCP47 language tag which specifies a preference for localization of results. none ko

Notes and tips

  • When you have the street name and house number as separate values, pass them as street and house_number (plus unit, if applicable). Use the combined address field when you only have a single pre-joined string.
  • While all fields are technically marked as optional, you will probably get the best results if you include the street (via street/house_number or address), region, postalcode, and country. Fine-grained administrative queries don't usually help with address geocoding.
  • If you are having trouble finding a street address, try your request again omitting the locality. In some cases, there is a complex relationship between physical geography and the locality (ex: city) written in the postal address.
  • Be sure to read Determining Result Quality and our best practices

Response format

All geocoding, autocomplete, and search endpoints share a common response format. See the response format documentation for details.

Next Steps