Skip to content

API documentation

Autocompletion, validation and geocoding of addresses in Hungary through a REST API, with JSON responses.

In brief

The Adatka API is available at https://adatka.hu over HTTPS and responds in JSON format, UTF-8 encoded.

EndpointWhat it is for
GET /suggestaddress suggestions while typing, also with step-by-step selection
GET /reverseaddress from coordinates
POST /cleanvalidation and standardisation of an address list, at most 1,000 rows per request
GET /healthstatus of the service

/suggest, /reverse and /clean return a uniform address object: the parts of the address, the administrative data, the coordinates, the match level and the sources used.

The service is currently available as an invitation-only beta, free of charge.

Quick start

The commands are written for a Linux or macOS terminal (bash, zsh). You can request an API key at the bottom of this page, in the “Access” section. During the beta, the service also responds without a key for the time being: if you do not have a key yet, skip entering it — the commands run anyway (details: API key).

If you have a key, enter it first: paste the line below and press Enter; after the prompt “Kulcs:” (Hungarian for “Key:”), paste the key and press Enter again. The key you type is not shown on the screen.

Entering the key
printf "Kulcs: "; read -rs ADATKA_KEY; export ADATKA_KEY; echo

With the first request you get three suggestions for the text entered:

First request
curl -sG https://adatka.hu/suggest -H "Authorization: Bearer $ADATKA_KEY" --data-urlencode "q=szeged tisza lajos krt 2" --data-urlencode "limit=3"

Expected result JSON; three addresses in the suggestions list, the first: 6720 Szeged, Tisza Lajos körút 2 ("match_level": "house").

Tip: the response is easier to read if you add this to the end of the command: | python3 -m json.tool.

API key

Send the key in a header of every request; the two forms are equivalent:

Headers
Authorization: Bearer <API-key>
X-API-Key: <API-key>

A key sent in the URL is ignored, because URLs remain in logs and in the browser history; such a request counts as a request without a key.

There are two kinds of key:

PropertyServer keyBrowser key
Where it can be called fromfrom your serverfrom a website, in the visitor’s browser
Endpoints/suggest, /reverse, /cleanonly /suggest
What we rejectrequests coming from a browser (those with an Origin header)requests from a website not assigned to the key (judged by the Origin header or, if it is missing, the Referer header)
Default limit120 requests per minute120 requests per minute and 2,000 per day, both per visitor (per IP address)

The server key is a secret: it must not end up in code sent to the browser (HTML, JavaScript), in a Git repository, in a URL or in a log. If it has fallen into the wrong hands, write immediately to info@adatka.hu, preferably from the email address to which we sent the key. We will revoke the key and issue a new one in its place. When requesting a browser key, give the exact web address of the website, including the https:// prefix; if the website also opens without www, give both variants.

The endpoints can also be called directly from a browser: responses carry the Access-Control-Allow-Origin: * header, and the preflight request allows the GET and POST methods and any request header. From a website, call with a browser key; the server key does not belong in the browser.

During the beta, the service also responds without a key for the time being, but it always rejects an invalid or revoked key (401). This makes it easy to check whether your key reaches us: the command below appends a letter (x) to the end of the key — you should get a 401 response.

Test with a broken key
curl -sG https://adatka.hu/suggest -H "Authorization: Bearer ${ADATKA_KEY:?nincs megadva}x" --data-urlencode "q=Szeged" -o /dev/null -w "%{http_code}\n"

Expected result 401. If you get 200 instead, the key does not reach us: check how the header is written. If you have not entered the key, the command does not run, and the terminal prints an error message ending with: ADATKA_KEY: nincs megadva (Hungarian for “not set”).

Send the key with every request from now on: this way we assign your requests to your key, and if the key becomes mandatory, you will not need to change anything. We will notify API key holders of this in advance, by email. You can request a key at the bottom of this page, in the “Access” section.

Address suggestions — GET /suggest

Address suggestions while typing, based on the text entered in the address field; the first suggestion is the best match. The text may be incomplete, without accents, abbreviated (“bp”, “krt”, “u.”) or mistyped, and the postal code may stand at the beginning or at the end.

ParameterDescription
qthe text entered; if it is empty and there is no step-by-step parameter, the list is empty too
limitat most this many suggestions, from 1 to 20; default: 5
postal_code, settlement, streetstep-by-step selection — details: Step-by-step selection

Response: {"query": …, "suggestions": [address object, …]}. If there is no match, the list is empty; this is not an error, the response code is 200.

Send parameter values URL-encoded: curl does this with the --data-urlencode option, the requests library (Python) with the params argument.

While the user is typing, do not send a request on every keystroke: wait until there is a short pause in the typing. Our demo, for example, sends the request 180 milliseconds after the last keystroke. This way you send fewer requests and do not hit the per-minute limit needlessly.

Wrong postal code in the address entered
curl -sG https://adatka.hu/suggest -H "Authorization: Bearer $ADATKA_KEY" --data-urlencode "q=9022 gyor baross gabor ut 12" --data-urlencode "limit=1"

Expected result 9021 Győr, Baross Gábor út 12, and the value of meta.postal_not_matched is "9022": the postal code entered does not belong to this address.

Step-by-step selection

If your form asks for the address step by step — postal code or settlement, street, house number — send the part already selected in a separate parameter, and in the q parameter only what the user types after it. Take the values from the fields of the selected suggestion.

ParametersWhat it returns
postal_code=6720the settlements belonging to the postal code
settlement=Szeged, q=Tiszathose streets of Szeged that match the text “Tisza”
settlement=Szeged, street=Tisza Lajos körút, q=2those house numbers of the street that match the text “2”
settlement=Budapest, settlement_part=Békásmegyerthe streets of Budapest, with those verifiably located in the settlement part first (for these, settlement_part is filled in), followed — when q is empty — by those closest to the centre of the part

postal_code can also be given together with settlement: it then narrows the matches. If the user has chosen a settlement part (the settlement_part field of the suggestion), send it in the settlement_part parameter alongside settlement; the same applies to house numbers: for a house verifiably located in the part, settlement_part is filled in; for a house outside the boundary of the part, the settlement_part_not_matched flag appears.

House numbers on one street
curl -sG https://adatka.hu/suggest -H "Authorization: Bearer $ADATKA_KEY" --data-urlencode "settlement=Szeged" --data-urlencode "street=Tisza Lajos körút" --data-urlencode "q=2"

Expected result five house numbers (2, 20, 21, 22 and 23), each with "match_level": "house".

Address from coordinates (reverse geocoding) — GET /reverse

The known addresses with a house number closest to the point, the closest first. (Coordinates from an address are given by /suggest and /clean: in the geo field of the address object; their precision is shown by geo.precision.)

ParameterDescription
lat, lonrequired; latitude and longitude in decimal degrees (WGS84), with a decimal point, for example 46.2557 and 20.1562
limitat most this many addresses, from 1 to 20; default: 1

Response: {"lat": …, "lon": …, "suggestions": [address object, …]}.

Address for a point in Szeged
curl -sG https://adatka.hu/reverse -H "Authorization: Bearer $ADATKA_KEY" --data-urlencode "lat=46.2557" --data-urlencode "lon=20.1562"

Expected result 6720 Szeged, Tisza Lajos körút 2 ("match_level": "house").

The response always gives the nearest known house in Hungary, but not the distance. If the point is far from houses — in a field, on water or beyond the national border — the address found may be far from the point; if this matters, calculate the distance from the geo.lat and geo.lon fields. If limit is greater than 1, the same address may appear more than once, because in the source one house may have several address points; filter out the repetitions before displaying them.

Address list validation — POST /clean

One address per row, at most 1,000 rows per request. In the response each row has exactly one address object, in the same order; the original row is in the input field.

The request body is JSON (Content-Type: application/json): {"records": ["…", "…"]}. Response: {"results": [address object, …]}.

Validating two rows
curl -s https://adatka.hu/clean -H "Authorization: Bearer $ADATKA_KEY" -H "Content-Type: application/json" -d '{"records": ["Szeged, Tisza Lajos krt. 2", "pecs kiraly u 999"]}'

Expected result two address objects in the results list; the first is 6720 Szeged, Tisza Lajos körút 2 ("quality_code": 0), the second Pécs, Király utca ("quality_code": 1, "house_not_found": "999").

quality_codeMeaningWhat to do
0house-level match (house), confidence at least 0.8can be used
1the match is incomplete or uncertain: street or settlement level, the house number is only known to exist (house_exists), or confidence is below 0.8look at the flags in meta and check if necessary
2we did not find an addresscheck manually
3the row contains no address: it is empty, or contains neither letters nor digits—

If you send more than 1,000 rows, the response is 413: split the list into parts of at most 1,000 rows — see the Python example.

Status — GET /health

For monitoring: whether the service is running, and with which dataset. No key is needed, and it does not count towards the limits.

Querying the status
curl -s https://adatka.hu/health

Expected result JSON containing "message": "adatka él!" (Hungarian for “adatka is alive!”) and (during the beta) "api_key_required": false.

FieldMeaning
message"adatka él!" if the service is running
api_key_requiredtrue if the key is mandatory; currently false during the beta
reference_datathe identifier of the dataset (run_id) and the time it went live (promoted_at_utc)

The other fields are internal operational data and not part of the documented interface; your program should not rely on them.

Address object

/suggest, /reverse and /clean return an object with the same structure (/clean also adds the input field). If a piece of data is not known, the field value is null. A real address object — the first suggestion in the /suggest response for the text “Szeged Tisza Lajos körút 2”:

Address object
{
  "country_code": "HU",
  "postal_code": "6720",
  "settlement": "Szeged",
  "settlement_part": null,
  "street": "Tisza Lajos körút",
  "house_number": "2",
  "sub_premise": {
    "building": null,
    "staircase": null,
    "floor": null,
    "door": null,
    "verified": false
  },
  "admin": {
    "county": "Csongrád-Csanád",
    "county_ksh": null,
    "district": "Szegedi",
    "district_ksh": "075 1",
    "city_district": null,
    "settlement_ksh": "33367",
    "iso_3166_2": null,
    "geoname_id": "715429"
  },
  "geo": {
    "lat": 46.255697,
    "lon": 20.156243,
    "precision": "house",
    "timezone": "Europe/Budapest"
  },
  "meta": {
    "match_level": "house",
    "confidence": 0.99,
    "quality_code": 0,
    "sources": [
      "OSM",
      "KSH",
      "GeoNames"
    ]
  }
}
FieldMeaning
country_codecountry code; currently always "HU"
postal_codepostal code. If several postal codes belong to the address and the house number does not decide which one applies: for a settlement-level match, the lowest and the highest ("6710 ... 6791"); for a street-level match, null
settlementthe official name of the settlement
streetthe name of the street together with its type ("Tisza Lajos körút")
house_numberhouse number as it appears in the source ("2/1", "13-15")
sub_premisebuilding, staircase, floor, door (building, staircase, floor, door), if the text entered contains them; verified is always false, because in the absence of a public source we do not check these
admin.countycounty (vármegye)
admin.district, admin.district_kshdistrict (járás) and its KSH code
admin.city_districtthe city district (kerület) of Budapest ("XIII. kerület")
admin.settlement_kshthe KSH code of the settlement
admin.geoname_idthe GeoNames ID of the settlement
geo.lat, geo.loncoordinates in decimal degrees (WGS84)
geo.precisionprecision of the coordinates: house, street, settlement_part or settlement
geo.timezonetime zone ("Europe/Budapest")
metathe level, reliability, sources and flags of the match — details: Match levels and flags

settlement_part is the settlement part: a city quarter, housing estate or other built-up area (for example Békásmegyer, Jereván-lakótelep, Felsőváros). A settlement part can also be a match in its own right ("match_level": "settlement_part"). For an address match, it gets a value if the request names the settlement part and the address found is verifiably in that part: it lies within the boundary of the part (where the boundary is known — in Budapest, for most city quarters), or it has a postal code that, within the settlement, belongs only to this part, or — for a house with its own coordinates — of all parts of the settlement, the centre of this part is the closest to it, at most 1 km away. If we cannot verify that the address belongs to the part, the field stays empty. Two fields are part of the schema but are currently not filled in: admin.county_ksh, admin.iso_3166_2. For a Budapest address, admin.county and admin.district are null, because the capital belongs to neither a county nor a district (járás); the city district (kerület) is given by admin.city_district.

Match levels and flags

meta tells you what we found and how certain the match is:

FieldMeaning
match_levelthe match level — see the table below
confidencethe reliability of the match, a number between 0 and 1
quality_code0–3; its meaning is given in the description of /clean. It may also appear in /suggest and /reverse responses, but there rely on the value of match_level.
sourcesthe sources used: "KSH", "GeoNames", "Magyar Posta", "Nemzeti Választási Iroda" and OpenStreetMap — named "OSM" for a house-level match and "OpenStreetMap" for a street-level match; details: Sources and licences
match_levelMeaning
housewe found the house number; the coordinates are those of the house
house_existsthe house number appears in the address dataset of the National Election Office (Nemzeti Választási Iroda), but we have no coordinates of our own for it; the precision of the coordinates is shown by geo.precision. In this case the meta.house_exists flag also appears.
streetwe found the street but not the house number — or the request contained no house number
settlement_partwe found the settlement part (city quarter, housing estate, other built-up area): the response contains the name of the part (settlement_part), the settlement, the postal code or postal code range belonging to the part, and the centre of the part; in Budapest also the district (admin.city_district)
settlementwe found only the settlement
noneno match (only in the /clean response)

If part of the text entered does not fit the address found, the response does not hide this: meta flags it in a separate field. The value of the flag is the part of the text entered (the city district in standardised form); the exception is house_exists, whose value is an object.

FlagWhen it appearsExample: entered → response
postal_not_matchedthe postal code entered does not belong to this address; the postal_code field contains the correct one“9022 gyor baross gabor ut 12” → 9021, "9022"
postal_aliasanother source assigns the postal code entered to the settlement; the postal_code field contains the one according to Magyar Posta“csömend 8700” → 8703, "8700"
house_not_foundthe house number entered is not in our data; the response is at street level“pecs kiraly u 999” → Király utca, "999"
house_existsthe house number appears in the address dataset of the National Election Office; the value is an object: source, dataset, extract_date (the date of the extract), street_matching (who matched the street name)“tiszafured petofi u 12” → Petőfi Sándor utca 12
street_not_foundwe did not find the street entered; the response is at settlement level“szeged nincsilyen utca 5” → Szeged, "nincsilyen utca"
settlement_not_matchedthe settlement name entered does not fit the address found“vaci ut 1 godol” → Budapest, Váci út 1, "godol"
kerulet_not_matchedthe city district (kerület) entered does not fit the address found“1136 hegedus gyula utca 4 xxi ker” → XIII. kerület, "XXI. kerület"
settlement_part_not_matchedthe address found is definitely not in the settlement part entered: the house lies outside the boundary of the part, or the address is in a different city district (kerület)“bekasmegyer andrassy ut 1” → Andrássy út (VI. kerület), "bekasmegyer"

The value of the house_exists flag for the request “tiszafured petofi u 12”:

Value of the house_exists flag
{
  "source": "Nemzeti Választási Iroda",
  "dataset": "Körzetállomány (szavazóköri címállomány)",
  "extract_date": "2026-01-16",
  "street_matching": "Adatka"
}

A missing match is not proof: if a house number does not appear in Adatka’s data sources, that does not mean the address does not exist. A street- or settlement-level response, or an empty one, should not by itself prevent an order, a registration or the handling of an administrative matter — your program should always offer a way to enter or check the address manually (Terms of service, in Hungarian).

New flags may also appear: your program should ignore what it does not recognise.

Error codes

For a rejected request, the response body is: {"detail": {"error": "…", "message": "…"}}. message is in Hungarian and meant for people; in your program, rely on the value of error. The bodies of 413 and 422 responses have a different form.

HTTP codeerrorWhenWhat to do
401missing_api_keythere is no key in the request, and the key is mandatorysend the key in a header
401invalid_api_keythe key is unknown or revoked — also during the betacheck the key
403server_key_in_browsera server key arrived from a browser (with an Origin header)a website needs a browser key
403endpoint_not_allowedthe /reverse or /clean endpoint was called with a browser keythese need a server key
403origin_not_allowedthe request sent with a browser key came from a website that is not assigned to the key, or it has neither an Origin nor a Referer headerif the website is not assigned to the key, send us its web address; if the request does not come from a browser, use a server key
413—a /clean request contains more than 1,000 rows; the body: {"detail": "Too many records: max 1000"}split the list
422—invalid parameter or body, for example: limit is not between 1 and 20, lat or lon is missing, records is missing; the detail list in the body tells you which field is wrong (loc, msg)correct the request
429rate_limitedtoo many requests: you have reached the limit without a key, the per-minute limit or (for a browser key) the daily limit — see Limits. Without a key, the message field of the body tells you which limit applies and how you can request a key; if a /clean request contains more rows than can be sent in one request without a key, the max_rows field of the body gives the maximum number of rowswait as many seconds as the Retry-After header (and the retry_after field of the body) specifies; do not retry more often than the header asks
5xx—an error on our siderepeat the request later, with increasingly long waits; if the error persists, write to info@adatka.hu

Limits

We state the limits for your key in the email in which we issue the key; if they differ from the above, the email prevails. The limits without a key are there to protect the service: one IP address should not be able to take capacity away from the others (Terms of service, section 5, in Hungarian). If you regularly hit the limit without a key, request an API key in the “Access” section: a key comes with a higher quota and priority. The limits without a key do not apply to operational requests sent from the server’s own machine.

Python example

A complete example with the requests library: it takes the key from the ADATKA_KEY environment variable, after a 429 response waits as long as Retry-After asks, and sends a long list in parts of 1,000 rows. Run it in the same terminal in which you entered the key.

Install the requests library into a virtual environment of your own — newer Linux systems do not allow pip install to install into the system Python:

Installing requests into a virtual environment
python3 -m venv adatka-venv && . adatka-venv/bin/activate && pip install requests

If python3 -m venv gives an error (“ensurepip is not available”), on Debian and Ubuntu first install the python3-venv package. In a new terminal, activate the environment again (. adatka-venv/bin/activate) and enter the key again.

Save the example as adatka_pelda.py:

adatka_pelda.py
import os, time
import requests  # pip install requests

API = "https://adatka.hu"
session = requests.Session()
session.headers["Authorization"] = "Bearer " + os.environ.get("ADATKA_KEY", "")  # in the beta it also runs without a key

def call(method, path, **kw):
    for attempt in range(3):
        r = session.request(method, API + path, timeout=30, **kw)
        if r.status_code == 429:                  # rate limit: wait as long as the response asks
            time.sleep(int(r.headers.get("Retry-After", "1")))
            continue
        r.raise_for_status()
        return r.json()
    raise RuntimeError("Adatka: still rate-limited after three attempts")

def clean_all(lines):                             # at most 1000 rows per request
    results = []
    for i in range(0, len(lines), 1000):
        results += call("POST", "/clean", json={"records": lines[i:i + 1000]})["results"]
    return results

hints = call("GET", "/suggest", params={"q": "Szeged Tisza Lajos körút 2", "limit": 5})["suggestions"]
rows = clean_all(["Szeged, Tisza Lajos krt. 2", "pecs kiraly u 999"])
print(hints[0]["postal_code"], [r["meta"]["quality_code"] for r in rows])
Run
python3 adatka_pelda.py

Expected result 6720 [0, 1] — the postal code of the first suggestion and the quality_code values of the two rows.

In other programming languages it works the same way: the key in the header, the parameters URL-encoded, the response in JSON.

Data protection in requests

Send only addresses or coordinates. Do not send names, email addresses, phone numbers, or client or order identifiers (Terms of service, section 5, in Hungarian); if the address field of an order also contains the recipient’s name or phone number, remove it before sending.

We do not log the text of requests. From GET /suggest and GET /reverse requests, only the path, the parameter names and the length of their values, and the response code go into the system log, without IP address or API key; we keep these entries for at most 14 days. The body of POST /clean is not logged. Details: Privacy notice.

Changes

6 October 2026: step-by-step selection with a settlement part — new settlement_part parameter alongside settlement (Step-by-step selection).

6 October 2026: for an address match, settlement_part gets a value only if membership of the part can be verified — from the boundary of the part, a postal code belonging only to the part, or the nearest part (Address object); the settlement_part_not_matched flag also appears when the house lies outside the boundary of the named part (Match levels and flags).

5 October 2026: settlement parts in search — city quarter, housing estate, other built-up area (“Békásmegyer”, “Jereván-lakótelep Sopron”, “szeged felsőváros”): new match level ("settlement_part"), the settlement_part field filled in for an address found within the postal codes of the part, new flag (settlement_part_not_matched); source: OpenStreetMap and KSH Gazetteer (Helységnévtár) (Match levels and flags, Sources and licences).

5 October 2026: limits without a key — an anti-abuse brake with immediate effect, a numerical quota from 5 November 2026; without a key, the body of the 429 response states the reason (Limits, Error codes).

5 October 2026: the documentation now describes how to call the API from a browser (CORS) (API key) and the rule for handling a missing match (Match levels and flags).

A new field, flag or endpoint may appear at any time; your program should ignore what it does not recognise. We will inform you of material changes to existing fields and endpoints in accordance with section 8 of the Terms of service (in Hungarian).

Access

The service is currently available as an invitation-only beta, free of charge; there is no self-service registration yet. Request access, and we will get in touch with you.

Prices