Bulk Geocoding¶
Free
Starter
Standard
Professional
The bulk geocoding (search) endpoint lets you do many forward and structured searches in a single API call. While asynchronous I/O with an HTTP/2 connection pool can achieve similar results, this endpoint is great for the following scenarios:
- Throughput is a primary concern (we can make requests to internal backends faster)
- Connection latency is high or unpredictable
- Your development environment makes it difficult to leverage async I/O and connection pools (ex: PHP, legacy networking libraries, and shell scripting)
Endpoint: https://api.stadiamaps.com/geocoding/v1/search/bulk
How many credits will I use?
This API internally makes requests to other geocoding endpoints on your behalf. You will be charged for each request in the batch. For example, if your bulk request includes 200 forward geocodes and 300 structured geocodes, you will be charged for 200 forward geocodes and 300 structured geocodes accourding to the current credit schedule.
This endpoint is available on our Standard, Professinoal, and Enterprise plans.
Example Code¶
Installation Instructions
The Stadia Maps JavaScript/TypeScript SDK is available for any package manager that supports the npm registry.
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.searchBulk({
bulkRequest: [
{ endpoint: "/v1/search", query: { text: "Põhja pst 27" } },
{
endpoint: "/v1/search/structured",
query: {
address: "Kursi tänav 3",
country: "EE",
layers: ["coarse", "address"],
},
},
],
});
- 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.
pip install 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_bulk([
stadiamaps.BulkRequest(endpoint="/v1/search",
query=stadiamaps.BulkRequestQuery(stadiamaps.SearchQuery(text="Põhja pst 27"))),
stadiamaps.BulkRequest(endpoint="/v1/search/structured",
query=stadiamaps.BulkRequestQuery(stadiamaps.SearchStructuredQuery(
address="Kursi tänav 3",
country="EE",
layers=[
stadiamaps.PeliasLayer.COARSE,
stadiamaps.PeliasLayer.ADDRESS]))),
])
except ApiException as e:
# Add your error handling here
print("Exception when calling the Stadia Maps API: %s\n" % e)
- 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.
dependencies {
val retrofitVersion = "2.11.0"
// API package
implementation("com.stadiamaps:api:3.2.1")
// Dependencies
implementation("com.squareup.moshi:moshi-kotlin:1.14.0")
implementation("com.squareup.moshi:moshi-adapters:1.14.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.10.0")
implementation("com.squareup.retrofit2:retrofit:$retrofitVersion")
implementation("com.squareup.retrofit2:converter-moshi:$retrofitVersion")
implementation("com.squareup.retrofit2:converter-scalars:$retrofitVersion")
}
dependencies {
def retrofitVersion = "2.11.0"
// API package
implementation 'com.stadiamaps:api:3.2.1'
// Dependencies
implementation 'com.squareup.moshi:moshi-kotlin:1.15.1'
implementation 'com.squareup.moshi:moshi-adapters:1.15.1'
implementation 'com.squareup.okhttp3:logging-interceptor:4.10.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
.
<properties>
<retrofit.version>2.9.0</retrofit.version>
</properties>
<dependencies>
<!-- API package -->
<dependency>
<groupId>com.stadiamaps</groupId>
<artifactId>api</artifactId>
<version>3.2.1</version>
</dependency>
<!-- Dependencies -->
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi-kotlin</artifactId>
<version>1.15.1</version>
</dependency>
<dependency>
<groupId>com.squareup.moshi</groupId>
<artifactId>moshi-adapters</artifactId>
<version>1.15.1</version>
</dependency>
<dependency>
<groupId>com.squareup.okhttp3</groupId>
<artifactId>logging-interceptor</artifactId>
<version>4.10.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.apis.*
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 reqs = listOf(
BulkRequestFactory.searchRequest(SearchQuery(text = "Põhja pst 27")),
BulkRequestFactory.searchStructuredRequest(SearchStructuredQuery(address = "Kursi tänav 3", country = "Estonia"))
)
val res = service.searchBulk(reqs).execute()
if (res.isSuccessful) {
println("Found result: ${res.body()}")
} else {
println("Request failed with error code ${res.code()}")
}
- 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.searchBulk(bulkRequest: [
BulkRequest(endpoint: .search, query: .typeSearchQuery(SearchQuery(text: "Põhja pst 27"))),
BulkRequest(endpoint: .searchSlashStructured, query: .typeSearchStructuredQuery(SearchStructuredQuery(address: "Kursi tänav 3", country: "EE", layers: [.address, .coarse]))),
])
// Do something with the response...
print(res)
}
- Learn how to get an API key in our authentication guide.
Installation Instructions
Composer
To install the package via Composer,
add stadiamaps/stadiamaps-api-php
to your composer.json
:
{
"require": {
"stadiamaps/stadiamaps-api-php": "1.*"
}
}
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 {
$requests = array(
new BulkRequest(array(
"endpoint" => "/v1/search",
"query" => new SearchQuery(array("text" => "Põhja pst 27")))),
new BulkRequest(array(
"endpoint" => "/v1/search/structured",
"query" => new SearchStructuredQuery(array("address" => "Kursi tänav 3", "country" => "EE", "layers" => ["coarse", "address"]))))
);
$result = $apiInstance->searchBulk($requests);
} catch (Exception $e) {
// Add your error handling here
echo 'Exception when calling the Stadia Maps API: ', $e->getMessage(), PHP_EOL;
}
- Learn how to get an API key in our authentication guide.
curl -X 'POST' \
'https://api.stadiamaps.com/geocoding/v1/search/bulk?api_key=YOUR-API-KEY' \
-H 'accept: application/json' \
-H 'Content-Type: application/json' \
-d '[
{
"endpoint": "/v1/search",
"query": {
"text": "Põhja pst 27"
}
},
{
"endpoint": "/v1/search/structured",
"query": {
"address": "Kursi tänav 3",
"country": "EE",
"layers": ["coarse", "address"]
}
}
]'
Can I Store Geocoding API Results?
Permanently storing results, in part or in whole, (e.g. in a database) from this API for future use requires an active Standard, Professional, or Enterprise subscription. See our terms of service for the full legal terms.
Request Format¶
This endpoint expects a JSON array of requests. Each request is JSON object with two properties:
Parameter | Type | Required | Description |
---|---|---|---|
endpoint |
string | yes | The endpoint to call internally. Valid values are /v1/search and /v1/search/structured . |
query |
object | yes | The query parameters for the request. These are the same as those for the original GET endpoints, but multi-values may be sent as JSON arrays if desired. |
Search Parameters¶
These parameters may be included with a search query (forward geocode).
Parameter | Type | Required | Description | Default | Example |
---|---|---|---|---|---|
text |
string | yes | The place name (address, venue name, etc.) to search for. | none | Union Square |
Structured Search Parameters¶
These parameters may be included with a structured search query.
Parameter | Type | Required | Description | Default | Example |
---|---|---|---|---|---|
address |
string | no | A street name, optionally with a house number. | none | 11 Wall Street |
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 |
Common Parameters¶
These parameters MAY be included with any query.
Parameter | Type | Required | Description | Default | Example |
---|---|---|---|---|---|
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 to limit the search to. | none | GBR,FRA |
boundary.gid |
Pelias GID | no | The Pelias GID of a region to limit the search to. | 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 |
Response Format¶
The bulk geocoding results will be a JSON array of responses
in the same order as your request array.
Each item in the array includes a status
.
Successful responses will include a response
key which conforms to the common response format
shared by other geocoding endpoints.
A msg
will be included for serious failures.
Example Response¶
[
{
"response": {
"bbox": [
25.584235,
58.373151,
25.584235,
58.373151
],
"features": [
{
"geometry": {
"coordinates": [
25.584235,
58.373151
],
"type": "Point"
},
"properties": {
"accuracy": "point",
"confidence": 1,
"country": "Estonia",
"country_a": "EST",
"country_code": "EE",
"country_gid": "whosonfirst:country:85633135",
"county": "Viljandi",
"county_gid": "whosonfirst:county:1713305641",
"gid": "openstreetmap:address:way/224094258",
"housenumber": "27",
"id": "way/224094258",
"label": "27 Põhja pst, Viljandi, Estonia",
"layer": "address",
"localadmin": "Viljandi",
"localadmin_gid": "whosonfirst:localadmin:1713312917",
"locality": "Viljandi",
"locality_gid": "whosonfirst:locality:101815089",
"match_type": "exact",
"name": "27 Põhja pst",
"postalcode": "71016",
"region": "Viljandi",
"region_a": "VD",
"region_gid": "whosonfirst:region:85682985",
"source": "openstreetmap",
"source_id": "way/224094258",
"street": "Põhja pst"
},
"type": "Feature"
}
],
"geocoding": {
"attribution": "https://stadiamaps.com/attribution/",
"engine": {
"author": "Mapzen",
"name": "Pelias",
"version": "1.0"
},
"query": {
"lang": {
"defaulted": false,
"iso6391": "en",
"iso6393": "eng",
"name": "English",
"via": "header"
},
"parsed_text": {
"housenumber": "27",
"street": "põhja pst"
},
"parser": "libpostal",
"private": false,
"querySize": 20,
"size": 1,
"text": "Põhja pst 27"
},
"timestamp": 1723801833612,
"version": "0.2"
},
"type": "FeatureCollection"
},
"status": 200
}
]
Notes and tips¶
- Be sure to read Determining Result Quality and our best practices.
- The response array will maintain the same order as your inputs.
- We will stream the results back to you as they arrive! Note that in order to take advantage of this, you will need a streaming JSON decoder.
- Wanting to do a LOT of queries at once? Check our service limits for the maximum request size.
Service Limits¶
Bulk geocoding requests may contain up to 5,000 queries.