Documentation
Everything is a GET request to https://api.mygeocode.com/v1/ with query parameters (the bulk forms of forward geocoding, reverse geocoding and elevation also take a POST with a JSON body), answered with JSON. This page covers the parts every endpoint shares. The endpoint pages cover the parameters and fields of each one.
Your first request
No key is needed for the first 2,500 requests a day from an address. From any machine:
$ curl "https://api.mygeocode.com/v1/forward?q=Brandenburg+Gate,+Berlin&limit=1"{
"status": "ok",
"query": "Brandenburg Gate, Berlin",
"results": [
{
"formatted": "Brandenburg Gate, State of Berlin, Germany",
"lat": 52.516268,
"lon": 13.377692,
"type": "poi",
"precision": "house",
"confidence": 0.84,
"place_id": "jT9DvSQ2gMXhXRQ",
"components": { "poi": "Brandenburg Gate", "country": "Germany", "country_code": "de", "state": "State of Berlin" },
"bounds": { "north": 52.518271, "south": 52.514269, "east": 13.379691, "west": 13.375691 },
"timezone": {
"id": "Europe/Berlin",
"name": "Central European Summer Time",
"abbreviation": "CEST",
"utc_offset": "+02:00",
"utc_offset_seconds": 7200,
"dst": true,
"local_time": "2026-10-04T08:14:40+02:00"
},
"elevation_m": 36.0,
"country_info": {
"name": "Germany",
"official_name": "Germany",
"iso2": "DE",
"iso3": "DEU",
"iso_numeric": 276,
"continent": "EU",
"continent_name": "Europe",
"un_m49": {
"code": "276",
"world": { "code": "001", "name": "World" },
"region": { "code": "150", "name": "Europe" },
"subregion": { "code": "155", "name": "Western Europe" }
},
"groupings": ["MEDC"],
"capital": "Berlin",
"population": 82927922,
"area_km2": 357021.0,
"independent": true,
"un_member": true,
"landlocked": false,
"currency": {
"code": "EUR",
"name": "Euro",
"symbol": "€",
"alternate_symbols": [],
"html_entity": "€",
"iso_numeric": "978",
"subunit": "Cent",
"subunit_to_unit": 100,
"smallest_denomination": 1,
"symbol_first": true,
"decimal_mark": ",",
"thousands_separator": ".",
"minor_unit": 2
},
"calling_code": "+49",
"dial": { "calling_code": "49", "international_prefix": "00", "national_prefix": "0" },
"languages": ["de"],
"tld": ".de",
"flag": "🇩🇪",
"wikidata": "Q183",
"neighbours": ["CH", "PL", "NL", "DK", "BE", "CZ", "LU", "FR", "AT"]
},
"codes": {
"plus_code": "9F4MG98H+G3",
"geohash": "u33db2m36vfj",
"mgrs": "33UUU8991719698",
"maidenhead": "JO62qm53",
"dms": { "lat": "52° 30' 58.6\" N", "lon": "13° 22' 39.7\" E" },
"mapcode": "DEU 7J.LF",
"mapcode_international": "VJMM9.T0MV"
},
"sun": {
"sunrise": "2026-10-04T07:12:52+02:00",
"sunset": "2026-10-04T18:37:32+02:00",
"solar_noon": "2026-10-04T12:55:12+02:00",
"civil_dawn": "2026-10-04T06:38:57+02:00",
"civil_dusk": "2026-10-04T19:11:27+02:00"
},
"regions": {
"nuts": {
"nuts0": { "code": "DE", "name": "Deutschland" },
"nuts1": { "code": "DE3", "name": "Berlin" },
"nuts2": { "code": "DE30", "name": "Berlin" },
"nuts3": { "code": "DE300", "name": "Berlin" }
},
"admin": [
{
"level": "admin0",
"name": "Germany",
"official_name": "Federal Republic of Germany",
"country_code": "DE",
"iso": "DEU",
"id": "c-DE-germany",
"geonames_id": 2921044,
"population": 82927922,
"wikidata": "Q183"
},
{
"level": "admin1",
"name": "Berlin",
"country_code": "DE",
"iso": "DE-BE",
"id": "a1-a2d571daa3c5bd"
},
{
"level": "admin2",
"name": "Berlin",
"country_code": "DE",
"iso": "DE-BE",
"id": "a2-a62c81d81f840b"
},
{
"level": "admin3",
"name": "Berlin",
"country_code": "DE",
"iso": "DE-BE",
"id": "a3-683bc25e5eeba4"
},
{
"level": "admin4",
"name": "Berlin",
"country_code": "DE",
"iso": "DE-BE",
"id": "a4-fd465c1ab9ad47",
"geonames_id": 6547539,
"population": 3685265
}
]
}
}
]
}That request counted as 1 of the 2,500 free requests your address gets today. With a key it would count against the key instead, and the headers would add your credit and IP slot figures. The response headers tell you where you stand:
HTTP/2 200
content-type: application/json; charset=utf-8
x-quota-limit: 2500
x-quota-used: 88
x-quota-free-remaining: 2412
x-quota-reset: 1791158400
x-request-id: ec8de919e9a9a70fComing from another provider?
You may not need the rest of this page. If your code already talks to Google Maps, Bing Maps, HERE, Mapbox, Geocode.Farm, Nominatim, OpenCage, LocationIQ, Geoapify, TomTom, MapQuest, Geocodio, PositionStack, ip-api, ipinfo, ipstack or Open-Elevation, we run a host that speaks that provider's request and response format with our data behind it. Change the hostname, put your key where the old one went, and keep your parsing code. The same goes for the Google Maps JavaScript API, Bing Maps V8, HERE Maps for JavaScript, MapQuest.js, and the MapLibre, Mapbox GL and Leaflet geocoder plugins.
- Google Maps
- Bing Maps
- HERE
- Mapbox
- Geocode.Farm
- Nominatim
- OpenCage
- LocationIQ
- Geoapify
- TomTom
- MapQuest
- Geocodio
- PositionStack
- ip-api
- ipinfo
- ipstack
- Open-Elevation
- JavaScript map libraries
How the drop-ins work: the full host matrix, key mapping, error mapping and a migration checklist.
Base URL and endpoints
| Endpoint | Path | Required parameters |
|---|---|---|
| Forward geocoding | GET /v1/forward | q (or structured fields) |
| Reverse geocoding | GET /v1/reverse | lat, lon |
| Address autocomplete | GET /v1/autocomplete | q |
| IPv4 lookup | GET /v1/ipv4 | none (ip optional) |
| IPv6 lookup | GET /v1/ipv6 | none (ip optional) |
| IP lookup, either version | GET /v1/ip | none (ip optional) |
| Timezone lookup | GET /v1/timezone | lat, lon |
| Elevation lookup | GET /v1/elevation | lat, lon or locations |
| Postal code lookup | GET /v1/postcode | code |
Only HTTPS is served. Plain HTTP requests are refused with 400 rather than redirected, so that a key is never sent in the clear by accident. HTTP/2 and HTTP/3 are supported. Responses are compressed when the client accepts gzip or br.
The response envelope
Every response is a JSON object with a status of ok or error.
- On
ok, the payload follows:results(an array) for endpoints that can return several matches,result(an object ornull) for reverse geocoding, and flat fields for IP and timezone lookups. - On
error, there is anerrorobject with acodestring, amessagesentence and, when relevant, theparamthat caused it. The HTTP status matches. See errors.
A query that is valid but matches nothing is ok with an empty results array or a null result. That is not an error, and it counts as a request.
Parameters every endpoint accepts
| Parameter | Description |
|---|---|
key | Your API key, if you prefer a query parameter to the X-API-Key header. The header is better because query strings end up in logs. |
lang | ISO 639-1 language code for the response. Default en. A tag such as pt-BR counts by its language. Place, region and country names come in that language, and the street is translated or written in the language's script by how it sounds. The order of an address's parts follows the country's convention. |
pretty | 1 to indent the JSON. Handy in a browser; leave it off in code. |
Parameter names are case-sensitive and lower case. Unknown parameters are ignored, and empty parameters are treated as absent, so an HTML form can submit optional fields blank. Coordinates are decimal degrees; lat from -90 to 90 and lon from -180 to 180. Text is UTF-8 and should be URL-encoded.
Authentication in one paragraph
A key is optional: every address gets 2,500 free requests a day without one. A key is sent as the X-API-Key header, an Authorization: Bearer token or the key parameter; keys are free, and an account takes your name, an email address and a password. An account has 2,500 free requests a day, shared by all of its keys; past that, requests use the account's prepaid credit at €0.0001 each, or are free on a key that belongs to an Unlimited package (€50 per month). Requests without a key and requests with a key from the same network share one daily allowance. A pay-as-you-go key works from two IP addresses per rolling 24 hours, an Unlimited key from three; a browser key, made for scripts on one website, has no IP limit. The full rules are on the authentication page.
Quota headers
| Header | Meaning |
|---|---|
X-Quota-Limit | Free requests per day for this key's account (shared by all its keys), or for this network when no key was sent: 2,500. On an Unlimited key, -1. |
X-Quota-Used | Requests counted on this key today, including this one. Without a key: requests made today from this network without a key. |
X-Quota-Free-Remaining | Free requests left today for the account, or for the network when no key was sent. -1 on an Unlimited key. |
X-Quota-Network-Used | Free requests the same network has used today the other way (with a key when none was sent, without one when a key was sent). Only sent when it is not 0. |
X-Credits-Remaining | How many more paid requests the account's credit covers. |
X-Key-IPs-Used, X-Key-IPs-Limit | IP slots held on this key right now, and how many it has. Not sent for browser keys. |
X-Key-Grace-Until | Unix time when the grace period of an expired Unlimited package ends. Only sent during that period. |
X-Quota-Reset | Unix time of the next 00:00 UTC, when the daily counters reset. |
X-Request-Id | A unique ID for the request. Quote it when you write to support. |
A browser key is public, so its answers carry no account figures: only X-Quota-Reset and X-Request-Id are sent. A refusal given before the quota is worked out, such as 403 key_ip_limit, carries the IP slot headers but no quota figures.
Calling from browsers
CORS is enabled on every endpoint and the quota headers are exposed, so a web page can call the API directly with a browser key, which works only from your website and has no IP slots. A server key in page source is public and would exhaust its IP slots after a couple of visitors. See keys and browsers.
Versioning
The path prefix /v1/ is the version. Within a version we add fields and parameters but never remove or rename them, and never change the meaning of an existing field. If we ever need to break something, it goes in /v2/ and /v1/ keeps working for at least six months after the announcement. Additions are announced in the News section of the blog.
Your JSON parser should ignore fields it does not know. That is the only forward-compatibility requirement.