teryt24.pl

teryt24.pl · API reference

Postal codes API

Three lookup modes: by code or prefix (q=), the codes serving one locality (locality=SYM), and the nearest codes for coordinates (lat+lon). Every row carries the TERC hierarchy and — when it resolves to a single locality — its SYM, kind and population.

The /v1/postal-codes/{code} detail adds the PRG (GUGiK) aggregates: address-point count, streets at the buildings, and the area centroid. POST /v1/postal-codes/bulk takes up to 100 codes at once — data cleaning without a round-trip festival.

GET /v1/postal-codes

Digits and dashes are interchangeable ('00-950', '00950', prefix '00-9'). format=geojson returns PRG points.

Try it live: /v1/postal-codes?q=00-002

Parameters
NameRequiredDescription
q—Postal code in any form: '00-950', '00950', or a prefix of either ('00-9', '009'); non-digits are ignored. Required unless locality or lat+lon is given.
locality—Locality SYM (7 digits, as returned by /v1/localities): the postal codes serving it — PRG official set first, then the PNA name ladder; one row per code, named for the requested locality (synthesized from the registry when GeoNames never paired it). Mutually exclusive with q and lat+lon; sym/type/population always describe the requested locality.
lat—WGS84 latitude (-90..90). Together with lon triggers nearest mode: the codes whose official PRG centroids are closest, distance-sorted (each with distanceKm, centroidLat/centroidLon, addressCount, streetCount). Mutually exclusive with q and locality. A blank value ('?lat=') is treated as absent — it does not trigger the mode.
lon—WGS84 longitude (-180..180). Must be given together with lat.
limit—Maximum results (1–50).
offset—Skip the first N results (0-based, max 10000) to page past the limit.
format—'geojson' answers an RFC 7946 FeatureCollection (row points — the PRG centroids in nearest mode — in [lon,lat] order) instead of the JSON envelope.

Example

Lookup by code (q=)

curl "https://teryt24.pl/v1/postal-codes?q=00-002"

Response:

{
  "postalCodes": [
    { "code": "00-002", "city": "Warszawa", "province": "MAZOWIECKIE", "county": "Warszawa", "municipality": "Warszawa", "municipalityKind": "gmina miejska, miasto stołeczne", "lat": 52.2358, "lon": 21.0101, "sym": "0988796", "citySlug": null, "type": "95", "typeLabel": "dzielnica m.st. Warszawy", "population": 1702139 }
  ],
  "meta": { "total": 1, "offset": 0, "limit": 10 }
}
Responses
StatusDescription
200Successful response — the row shape depends on the mode: the q/locality DTO for prefix and locality lookups, the nearest DTO (code, distanceKm, centroid, counts) for lat+lon.
400Invalid query parameters.
429Rate 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.
500Unexpected server failure (e.g. the database is unreachable). The body is deliberately generic — error detail lives in the server logs, never in the response.
503Postal-code dataset not available (generate data/pna CSV via pnpm fetch:pna); the nearest mode additionally requires the PRG ingest.

GET /v1/postal-codes/{code}

The full code record: every locality (PNA) plus the PRG aggregates — 404 for a code outside the register.

Try it live: /v1/postal-codes/00-002

Parameters
NameRequiredDescription
code path✓Postal code in the display ('59-700') or digits ('59700') form.

Example

Code 00-002 (Warszawa)

curl "https://teryt24.pl/v1/postal-codes/00-002"

Response:

{
  "code": "00-002",
  "rows": [
    { "code": "00-002", "city": "Warszawa", "province": "MAZOWIECKIE", "county": "Warszawa", "municipality": "Warszawa", "municipalityKind": "gmina miejska, miasto stołeczne", "lat": 52.2358, "lon": 21.0101, "sym": "0988796", "citySlug": null, "type": "95", "typeLabel": "dzielnica m.st. Warszawy", "population": 1702139 }
  ],
  "prg": { "addressCount": 1, "streetCount": 1, "centroidLat": 52.23579285110347, "centroidLon": 21.010129613434586, "streets": ["ul. Świętokrzyska"] }
}
Responses
StatusDescription
200Successful response.
400Invalid query parameters.
404Unknown postal code.
429Rate 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.
500Unexpected server failure (e.g. the database is unreachable). The body is deliberately generic — error detail lives in the server logs, never in the response.
503Postal-code dataset not available (generate data/pna CSV via pnpm fetch:pna).

POST /v1/postal-codes/bulk

A bulk row is byte-for-byte the single GET /v1/postal-codes/{code} answer; an unknown code returns as a status:error row carrying the HTTP status the single GET would have answered.

Request body (JSON)

NameRequired/typDescription
codesarray (1–100)Codes in the display ('59-700') or digits ('59700') form.

Example

Two codes in one request

curl -X POST "https://teryt24.pl/v1/postal-codes/bulk" \
  -H "Content-Type: application/json" \
  -d '{"codes":["00-002","59-700"]}'
{"codes":["00-002","59-700"]}

Response (truncated — first rows shown):

{
  "results": [
    { "code": "00-002", "status": "ok", "rows": [ { "code": "00-002", "city": "Warszawa", "province": "MAZOWIECKIE", "county": "Warszawa", "municipality": "Warszawa", "municipalityKind": "gmina miejska, miasto stołeczne", "lat": 52.2358, "lon": 21.0101, "sym": "0988796", "citySlug": null, "type": "95", "typeLabel": "dzielnica m.st. Warszawy", "population": 1702139 } ], "prg": { "addressCount": 1, "streetCount": 1, "centroidLat": 52.23579285110347, "centroidLon": 21.010129613434586, "streets": ["ul. Świętokrzyska"] } },
    { "code": "59-700", "status": "ok", "rows": [ { "code": "59-700", "city": "Bolesławice", "province": "DOLNOŚLĄSKIE", "county": "bolesławiecki", "municipality": "Bolesławiec", "municipalityKind": "gmina wiejska", "lat": 51.2798, "lon": 15.5485, "sym": "0188937", "citySlug": null, "type": "01", "typeLabel": "wieś", "population": 876 } ] }
  ]
}
Responses
StatusDescription
200Per-code results in request order: `status:"ok"` rows carry the detail endpoint's body (code, rows, prg); `status:"error"` rows carry the error the single GET would have answered with.
400Invalid query parameters.
429Rate 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.
500Unexpected 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

Every postal code has an info page with its localities and PRG data:

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.

Attribution is a condition of use. When you present results in an application, website, map or report, display: 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.