Address validation & geocoding
GET /v1/geocode confirms an address exists in the PRG register (GUGiK) and returns the building point: WGS84 coordinates, postal code and street id. Three calling forms — fielded (sym + number), by locality name (locality), or one free-text string (address) — plus POST /v1/geocode/batch for up to 50 addresses per call.
When the house number is unknown but the street exists, the response suggests neighbouring numbers; ambiguous locality and street names come back as short candidate lists to narrow with a follow-up query.
GET /v1/geocode
Three modes in one endpoint: fielded, by name, or one free-text string. format=geojson switches the response to RFC 7946.
Try it live: /v1/geocode?address=Warszawa,%20ul.%20Anilinowa%202
| Name | Required | Description |
|---|---|---|
address | — | Free-text Polish address ('Wrocław-Fabryczna, ul. Eugeniusza Horbaczewskiego 35'), parsed into locality/street/number internally — locality resolution reuses the exact+fuzzy name-search pipeline, so district strings ('Wrocław-Śródmieście') resolve to the same city. Mutually exclusive with sym, number, street, streetName, locality and postalCode; may only appear with limit. Additive `query` echo reports the parse (`cityResolved` distinguishes a bad split from an unknown address). |
sym | — | Locality SYM (7 digits, from /v1/localities). Required unless `address` or `locality` is given; mutually exclusive with locality. |
locality | — | Locality/city NAME (diacritics-insensitive) instead of a SYM — resolved through the locality index (exact matches all considered, fuzzy fallback otherwise). Several matches → result 'locality-ambiguous' with a population-ordered shortlist in `localities[]` (capped at 50, `localitiesTruncated` when cut); re-query fielded with sym=. Mutually exclusive with sym and address. |
postalCode | — | Optional narrowing hint for the locality mode: only localities the code officially serves (its PRG locality set, else the PNA name set) stay candidates — a code contradicting every name match answers result 'none'. Requires locality. |
number | — | House number ('21A'). Required unless `address` is given. |
street | — | Street SYM_UL (5 digits, from /v1/streets). Omit for rural 'locality + number' addresses. |
streetName | — | Street name prefix (diacritics-insensitive; 'rynek' finds 'ul. Rynek'), resolved via the ULIC registry. Mutually exclusive with street; several matches → result 'street-ambiguous' with candidates. |
limit | — | Maximum matches (1–50). |
format | — | 'geojson' answers an RFC 7946 FeatureCollection (every match a Feature) instead of the JSON envelope. |
Example
Free-text mode (address=)
curl "https://teryt24.pl/v1/geocode?address=Warszawa,%20ul.%20Anilinowa%202"Response:
{
"result": "exact",
"matches": [
{ "lat": 52.34742861543721, "lon": 20.945528669786594, "number": "2", "streetId": "00326", "postalCode": "03-149" }
],
"query": { "city": "Warszawa", "street": "Anilinowa", "number": "2", "numbers": ["2"], "range": false, "cityResolved": true }
}Fielded mode (sym + street + number)
curl "https://teryt24.pl/v1/geocode?sym=0983988&street=12400&number=8"Response:
{
"result": "exact",
"matches": [
{ "lat": 50.732269980089356, "lon": 16.640331777507814, "number": "8", "streetId": "12400", "postalCode": "58-200" }
]
}| Status | Description |
|---|---|
200 | Resolution result — 'exact' (building points), 'street' (number unknown, suggestions provided), 'street-ambiguous' (streetName matched several streets), 'locality-ambiguous' (the locality name matched several localities; shortlist in `localities[]`) or 'none'. Address- and locality-mode responses carry the `query` echo (cityResolved records whether the locality token resolved). |
400 | Invalid query parameters. |
429 | Rate limit exceeded (60 requests/min/IP) or a plan's monthly quota exhausted. Includes `Retry-After` and `X-RateLimit-*` headers; the body's `code` distinguishes the two kinds. |
500 | Unexpected server failure (e.g. the database is unreachable). The body is deliberately generic — error detail lives in the server logs, never in the response. |
503 | Address dataset not available (POST /admin/ingest-prg). |
POST /v1/geocode/batch
Up to 50 GET /v1/geocode queries in one call — one rate-limit slot, request order preserved, one bad address never discards the rest.
Request body (JSON)
| Name | Required/typ | Description |
|---|---|---|
requests | array (1–50) | Each item is a GET /v1/geocode query's fields (address, or sym/locality + number…), optionally with its own id. |
Example
Two addresses in one request
curl -X POST "https://teryt24.pl/v1/geocode/batch" \
-H "Content-Type: application/json" \
-d '{"requests":[{"id":"a","address":"Warszawa, ul. Anilinowa 2"},{"id":"b","sym":"0983988","number":"8"}]}'{"requests":[{"id":"a","address":"Warszawa, ul. Anilinowa 2"},{"id":"b","sym":"0983988","number":"8"}]}Response (truncated — first rows shown):
{
"results": [
{ "id": "a", "status": "ok", "result": "exact", "matches": [ { "lat": 52.34742861543721, "lon": 20.945528669786594, "number": "2", "streetId": "00326", "postalCode": "03-149" } ], "query": { "city": "Warszawa", "street": "Anilinowa", "number": "2", "numbers": ["2"], "range": false, "cityResolved": true } },
{ "id": "b", "status": "ok", "result": "exact", "matches": [ { "lat": 50.72964828838264, "lon": 16.649854908143396, "number": "8", "streetId": "05345", "postalCode": "58-200" } ] }
]
}| Status | Description |
|---|---|
200 | Successful response. |
400 | Invalid query parameters. |
429 | Rate limit exceeded (60 requests/min/IP) or a plan's monthly quota exhausted. Includes `Retry-After` and `X-RateLimit-*` headers; the body's `code` distinguishes the two kinds. |
500 | Unexpected server failure (e.g. the database is unreachable). The body is deliberately generic — error detail lives in the server logs, never in the response. |
Browse the data
The same data has browsable pages — locality and postal-code cards:
All /v1 endpoints return JSON, speak CORS and are covered by the openapi.json document. Interactive version of this reference: /en/docs.
Limits: 60 requests/min per IP without a key; an API key (the X-API-Key header) gets its own bucket. Over the limit the endpoints answer HTTP 429 with a Retry-After header. Details: limits & keys · usage policy.
Data: GUS TERYT, PRG address points (GUGiK), GeoNames postal codes — via teryt24.pl with a link to the usage policy. Server-side-only use is exempt.