Batch geocoding
Geocode many addresses in one call, billed per thousand points.
geo.batch
Stable
point_1k
How to call it
REST
POST
/v1/geo/forward/batch
POST
/v1/geo/reverse/batch
GraphQL
query
openGeoBatch
MCP
open_geo_batch
Geocode many addresses in one call. Billed per thousand points on what was attempted, not on what matched — a miss still costs a provider lookup.
Request schema
Generated from the same validation rules the endpoint runs, so a field cannot be documented without being validated.
POST /v1/geo/forward/batch
{
"type": "object",
"properties": {
"addresses": {
"type": "array",
"minItems": 1,
"maxItems": 1000,
"items": {
"type": "object",
"properties": {
"address1": {
"type": [
"string",
"null"
],
"maxLength": 255
},
"address2": {
"type": [
"string",
"null"
],
"maxLength": 255
},
"city": {
"type": [
"string",
"null"
],
"maxLength": 120
},
"country": {
"type": [
"string",
"null"
],
"maxLength": 120
},
"postcode": {
"type": [
"string",
"null"
],
"maxLength": 32
},
"province": {
"type": [
"string",
"null"
],
"maxLength": 120
}
}
}
}
},
"additionalProperties": false,
"required": [
"addresses"
]
}
Request example
{
"addresses": [
{
"address1": "1000 Rue De La Gauchetière O",
"city": "Montreal",
"country": "CA"
},
{
"address1": "290 Bremner Blvd",
"city": "Toronto",
"country": "CA"
}
]
}
POST /v1/geo/reverse/batch
{
"type": "object",
"properties": {
"language": {
"type": [
"string",
"null"
],
"maxLength": 8
},
"points": {
"type": "array",
"minItems": 1,
"maxItems": 1000,
"items": {
"type": "object",
"properties": {
"lat": {
"type": "number",
"minimum": -90,
"maximum": 90
},
"lng": {
"type": "number",
"minimum": -180,
"maximum": 180
}
},
"required": [
"lat",
"lng"
]
}
}
},
"additionalProperties": false,
"required": [
"points"
]
}
Request example
{
"points": [
{
"lat": 45.4985,
"lng": -73.5664
},
{
"lat": 43.6426,
"lng": -79.3871
}
]
}
Response
What a successful call returns: the schema of `data` and `meta`, with a description of each field, followed by an example response from a real call.
POST /v1/geo/forward/batch
Response schema
{
"description": "One result per address, in request order. Billed per thousand addresses sent, matched or not.",
"data": {
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"type": "integer",
"description": "Position of the address in the request, from 0."
},
"matched": {
"type": "boolean",
"description": "Whether a location was found. A miss is not an error and is still billed."
},
"reason": {
"type": "string",
"description": "Why nothing matched. Present only when `matched` is false."
},
"location": {
"type": "object",
"properties": {
"lat": {
"type": "number",
"description": "Latitude, WGS84."
},
"lng": {
"type": "number",
"description": "Longitude, WGS84."
}
},
"required": [
"lat",
"lng"
]
},
"address": {
"type": "object",
"description": "The matched address as the provider parsed it. Only the parts the provider returned are present; may be empty.",
"properties": {
"number": {
"type": "string",
"description": "House number."
},
"street": {
"type": "string",
"description": "Street name, normalized."
},
"city": {
"type": "string"
},
"province": {
"type": "string",
"description": "Province or state."
},
"country": {
"type": "string",
"description": "ISO 3166-1 alpha-2."
},
"postcode": {
"type": "string"
},
"unit": {
"type": "string",
"description": "Unit, suite or apartment."
}
}
},
"confidence": {
"type": [
"number",
"null"
],
"description": "0-1, as the provider reports it; null when the provider gives none."
},
"provider": {
"type": "string",
"description": "The provider that answered (see GET /v1/geo/coverage)."
}
}
},
"description": "One result per address, in request order."
},
"matched": {
"type": "integer",
"description": "Results with `matched: true`."
},
"total": {
"type": "integer",
"description": "Addresses sent."
}
}
}
}
Response example
{
"request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
"capability": "geo.batch",
"billing": {
"unit": "point_1k",
"quantity": 0.002,
"counted": true
},
"data": {
"results": [
{
"index": 0,
"matched": true,
"location": {
"lat": 45.4981126,
"lng": -73.56598129999999
},
"address": {},
"confidence": null,
"provider": "google"
},
{
"index": 1,
"matched": true,
"location": {
"lat": 43.642596,
"lng": -79.387089
},
"address": {
"number": "290",
"street": "bremner blvd",
"city": "Toronto",
"country": "CA"
},
"confidence": 1,
"provider": "internal"
}
],
"matched": 2,
"total": 2
}
}
POST /v1/geo/reverse/batch
Response schema
{
"description": "One address per point, in request order. Billed per thousand points sent.",
"data": {
"type": "object",
"properties": {
"results": {
"type": "array",
"items": {
"type": "object",
"properties": {
"index": {
"type": "integer",
"description": "Position of the point in the request, from 0."
},
"matched": {
"type": "boolean",
"description": "Whether an address was found."
},
"reason": {
"type": "string",
"description": "Why nothing matched. Present only when `matched` is false."
},
"address": {
"type": "object",
"properties": {
"address_1": {
"type": "string",
"description": "Street address."
},
"address_2": {
"type": "string",
"description": "Unit, suite or floor; empty when none."
},
"city": {
"type": "string"
},
"province": {
"type": "string",
"description": "Province or state, as the provider names it."
},
"country": {
"type": "string",
"description": "Country code, as the provider returns it."
},
"postcode": {
"type": "string"
},
"full_address": {
"type": "string",
"description": "The whole address on one line."
},
"country_code": {
"type": [
"string",
"null"
],
"description": "The country as an ISO 3166-1 alpha-2 code, the form forward geocoding answers with. Null when the provider named no country that maps to a code."
},
"province_code": {
"type": [
"string",
"null"
],
"description": "The province or state as its short code (QC, ON, NY), the form forward geocoding answers with; upper-cased as given when the country has no list of codes. Null when the provider named none."
}
}
},
"provider": {
"type": "string",
"description": "The provider that answered."
}
}
}
},
"matched": {
"type": "integer",
"description": "Results with `matched: true`."
},
"total": {
"type": "integer",
"description": "Points sent."
}
}
}
}
Response example
{
"request_id": "req_01k8zq3m5n7p9r1t3v5x7z9b2d",
"capability": "geo.batch",
"billing": {
"unit": "point_1k",
"quantity": 0.002,
"counted": true
},
"data": {
"results": [
{
"index": 0,
"matched": true,
"address": {
"address_1": "1000 Rue de La Gauchetière Ouest",
"address_2": "",
"city": "Montreal",
"province": "Quebec",
"country": "CAN",
"postcode": "H3B 4W5",
"full_address": "1000 Rue de La Gauchetière Ouest, Montreal, QC, Canada",
"country_code": "CA",
"province_code": "QC"
},
"provider": "internal"
},
{
"index": 1,
"matched": true,
"address": {
"address_1": "290 Bremner Boulevard",
"address_2": "",
"city": "Toronto",
"province": "Ontario",
"country": "CAN",
"postcode": "M5V 3L9",
"full_address": "CN Tower, Toronto, ON, Canada",
"country_code": "CA",
"province_code": "ON"
},
"provider": "internal"
}
],
"matched": 2,
"total": 2
}
}
What it costs
Thousands of points, charged fractionally.
Every billable response carries a billing block with the unit, the quantity and how the quantity was derived.
Errors it can return
| Status | Code | Description |
|---|---|---|
| 401 | TOKEN_INVALID |
Unknown or revoked API token. |
| 401 | TOKEN_MISSING |
No API token. Send Authorization: Bearer <your token>. |
| 402 | QUOTA_EXHAUSTED |
The included allowance for this capability is used up for the current period. |
| 403 | CAPABILITY_NOT_ENABLED |
This capability is not enabled for your account. See :doc to enable it. |
| 403 | CAPABILITY_NOT_GRANTED_TO_KEY |
Your account has this capability, but this API key was not granted it. |
| 403 | OPEN_API_DISABLED |
Open Platform access is not enabled for this account. |
| 422 | VALIDATION_FAILED |
The request failed validation. See details. |
| 429 | RATE_LIMITED |
Too many requests. Please retry after the indicated delay. |
| 500 | INTERNAL_ERROR |
An unexpected error occurred. Quote the request_id when contacting support. |
| 502 | ENGINE_UNAVAILABLE |
The routing engine is temporarily unreachable. Please retry. |