API kodów pocztowych, TERYT i PRG
Darmowe REST API do danych adresowych Polski. Kody pocztowe, TERYT SIMC/ULIC, punkty adresowe PRG (GUGiK), geokodowanie WGS84, dopasowywanie i walidacja adresów. Odpowiedzi w JSON, bez rejestracji dla limitów testowych, klucz API dla produkcji.
Quickstart — pierwszy request w 30 sekund
Wszystkie endpointy są pod https://api.adresy.app/api/v1. Odpowiedzi to JSON kodowany UTF-8. Metoda GET dla odczytu, POST dla operacji wsadowych i dopasowywania.
curl -s "https://api.adresy.app/api/v1/match?q=Rynek+1,+Wrocław"
Przykładowa odpowiedź:
{
"results": [
{
"input": "Rynek 1, Wrocław",
"status": "found",
"match": {
"miejscowosc": "Wrocław",
"ulica_norm": "Rynek",
"nr_budynku": "1",
"kod_pocztowy": "50-106",
"teryt_simc": "0986283",
"teryt_ulic": "19357",
"gmina": "Wrocław",
"powiat": "Wrocław",
"wojewodztwo": "DOLNOŚLĄSKIE",
"lat": 51.10893,
"lon": 17.03262,
"score": 0.98
}
}
]
}
Najprostszy sposób — GET /api/v1/match?q= — przyjmuje dowolny „brudny" adres w jednym parametrze i zwraca dopasowanie z rejestru PRG.
Przykładowa odpowiedź (skrócona):
{
"kod": "50-079",
"found": true,
"total": 412,
"ulic": 7,
"results": [
{
"miejscowosc": "Wrocław",
"ulica": "Ruska",
"teryt_simc": "0986283",
"teryt_ulic": "18834",
"gmina": "Wrocław",
"powiat": "Wrocław",
"wojewodztwo": "dolnośląskie",
"liczba_adresow": 58,
"numery_przyklad": ["11","13","15","17","19","21","23","25","27","29"]
}
]
}
Uwierzytelnianie i limity
- Bez klucza API
- 3 zapytania / minutę (na IP). Wystarczające do szybkich testów.
- Klucz API (Free)
- 30 zapytań / minutę, 3 000 / miesiąc. Darmowe konto + klucz API.
- Klucz API (Business)
- 600 zapytań / minutę, 10 mln / miesiąc, SLA 99,9%.
- Enterprise
- Dedykowana infrastruktura, webhooki PRG, on-premise.
curl -s "https://api.adresy.app/api/v1/lookup/kod-pocztowy?kod=00-001" \
-H "X-API-Key: sk_live_xxxxxxxxxxxxxxxx"
Limit przekroczony? Odpowiedź 429 Too Many Requests z nagłówkiem Retry-After w sekundach. Szczegóły w artykule o limitach.
1. Wyszukiwanie po kodzie pocztowym
GET /api/v1/lookup/kod-pocztowy
Zwraca wszystkie ulice i grupy numerów budynków przypisane do danego kodu pocztowego. Dane pochodzą z rejestru PRG (GUGiK), agregowane per ulica.
Parametry
| Nazwa | Typ | Wymagane | Opis |
|---|---|---|---|
kod | string | tak | Kod pocztowy w formacie NN-NNN, np. 50-079. |
limit | int | nie | Maksymalna liczba ulic w odpowiedzi. Domyślnie 200, maksymalnie 500. |
Przykład — curl
curl -s "https://api.adresy.app/api/v1/lookup/kod-pocztowy?kod=00-001&limit=50"
Przykład — Python
import httpx
r = httpx.get(
"https://api.adresy.app/api/v1/lookup/kod-pocztowy",
params={"kod": "00-001"},
headers={"X-API-Key": "sk_live_xxx"},
timeout=10,
)
data = r.json()
print(f"Znaleziono {data['total']} adresów na {data['ulic']} ulicach")
Przykład — JavaScript (fetch)
const res = await fetch(
"https://api.adresy.app/api/v1/lookup/kod-pocztowy?kod=00-001",
{ headers: { "X-API-Key": "sk_live_xxx" } }
);
const data = await res.json();
2. Kod pocztowy dla adresu
GET /api/v1/lookup/kod-dla-adresu
Odwrotne zapytanie — podaj miejscowość, ulicę i numer, otrzymasz kod pocztowy (lub zakres kodów, jeśli ulica obejmuje kilka). Idealne do walidacji formularzy e-commerce.
curl -s "https://api.adresy.app/api/v1/lookup/kod-dla-adresu" \
--data-urlencode "miejscowosc=Wrocław" \
--data-urlencode "ulica=Rynek" \
--data-urlencode "nr=1" \
-G
{
"found": true,
"kod_pocztowy": "50-106",
"miejscowosc": "Wrocław",
"ulica": "Rynek",
"nr": "1",
"teryt_simc": "0986283",
"teryt_ulic": "19357"
}
3. TERYT — SIMC i ULIC
GET /api/v1/lookup/teryt
Zwraca kody TERYT (SIMC dla miejscowości, ULIC dla ulic) wraz z przynależnością administracyjną: gmina, powiat, województwo. Obsługuje wyszukiwanie po nazwie miejscowości, nazwie ulicy lub bezpośrednio po kodzie SIMC.
curl -s "https://api.adresy.app/api/v1/lookup/teryt" \
--data-urlencode "miejscowosc=Kraków" \
--data-urlencode "ulica=Floriańska" -G
{
"found": true,
"results": [{
"simc": "0950463",
"nazwa": "Kraków",
"typ": "miasto",
"gmina": "Kraków",
"powiat": "Kraków",
"wojewodztwo": "małopolskie",
"kody_admin": "12612011",
"ulice": [{
"ulic": "05123",
"cecha": "ul.",
"nazwa_1": "Floriańska",
"nazwa_pelna": "ul. Floriańska"
}]
}]
}
4. Dekodowanie TERYT
GET /api/v1/lookup/teryt/decode
Zamienia kody TERYT na pełne dane adresowe. Obsługuje automatyczną detekcję (SIMC — 7 cyfr, ULIC — 5 cyfr) i format złożony SIMC#ULIC#NR.
# Auto-detect kodu
curl -s "https://api.adresy.app/api/v1/lookup/teryt/decode?kod=0986283"
# Pełny adres
curl -s "https://api.adresy.app/api/v1/lookup/teryt/decode?kod=0986283%2318834%2315"
5. Adresy w pobliżu punktu (geokodowanie odwrotne)
GET /api/v1/lookup/blisko
Zwraca najbliższe punkty adresowe dla podanych współrzędnych WGS84. Silnik: PostGIS, indeks GiST, promień podajesz w metrach.
curl -s "https://api.adresy.app/api/v1/lookup/blisko?lat=51.1089&lon=17.0326&radius=200&limit=5"
{
"found": true,
"count": 5,
"results": [
{
"miejscowosc": "Wrocław",
"ulica": "Rynek",
"nr_budynku": "1",
"kod_pocztowy": "50-106",
"distance_m": 12.4,
"lat": 51.10893,
"lon": 17.03262
}
]
}
6. Szybkie dopasowanie adresu — GET /match?q=
GET /api/v1/match
Najprostszy endpoint — podaj adres jako tekst w parametrze q, otrzymasz dopasowanie z pełnym TERYT, kodem pocztowym i współrzędnymi. Idealny do integracji formularzy, walidacji adresów w locie i autouzupełniania.
Parametry
| Nazwa | Typ | Wymagane | Opis |
|---|---|---|---|
q | string | tak | Adres do dopasowania, np. Rynek 1, Wrocław lub ul. Marszalkowska 1 Warszawa. |
min_score | float | nie | Minimalny score dopasowania (0-1). Domyślnie 0.6. |
wojewodztwo | string | nie | Ograniczenie do województwa (np. dolnośląskie). |
Przykład — curl
curl -s "https://api.adresy.app/api/v1/match?q=Rynek+1,+Wrocław"
Przykład — JavaScript
const res = await fetch(
"https://api.adresy.app/api/v1/match?q=" + encodeURIComponent("Rynek 1, Wrocław"),
{ headers: { "X-API-Key": "sk_live_xxx" } }
);
const data = await res.json();
console.log(data.results[0].match.kod_pocztowy);
Odpowiedź
{
"results": [
{
"input": "Rynek 1, Wrocław",
"status": "found",
"match": {
"miejscowosc": "Wrocław",
"ulica_norm": "Rynek",
"nr_budynku": "1",
"kod_pocztowy": "50-106",
"teryt_simc": "0986283",
"teryt_ulic": "19357",
"gmina": "Wrocław",
"powiat": "Wrocław",
"wojewodztwo": "DOLNOŚLĄSKIE",
"lat": 51.10893,
"lon": 17.03262,
"score": 0.98,
"match_layer": "EXACT"
}
}
]
}
Pola status: found (jednoznaczne dopasowanie), ambiguous (kilka kandydatów, zwrócony najlepszy), not_found (brak dopasowania).
7. Dopasowywanie adresów — POST /match
POST /api/v1/match
Najmocniejszy endpoint. Bierze „brudny" adres (literówki, skróty, bez kodu) i dopasowuje go do rzeczywistego punktu PRG z pełnym TERYT, kodem pocztowym i współrzędnymi. Używa fuzzy-match (RapidFuzz) + heurystyk skrótów polskich.
curl -s -X POST "https://api.adresy.app/api/v1/match" \
-H "Content-Type: application/json" \
-H "X-API-Key: sk_live_xxx" \
-d '{
"adres": "ul. Marsz Pilsudskiego 5a, Wroclaw",
"min_score": 80
}'
{
"match": true,
"score": 94,
"result": {
"miejscowosc": "Wrocław",
"ulica_wejsciowa": "Marsz Pilsudskiego",
"ulica_dopasowana": "Marszałka Józefa Piłsudskiego",
"nr_budynku": "5A",
"kod_pocztowy": "50-033",
"teryt_simc": "0986283",
"teryt_ulic": "12873",
"gmina": "Wrocław",
"powiat": "Wrocław",
"wojewodztwo": "dolnośląskie",
"lat": 51.10012,
"lon": 17.03159,
"srid": 4326
},
"candidates": 3
}
8. Walidacja pliku CSV/XLSX
POST /api/v1/match/file
Prześlij plik z listą adresów (kolumny: miejscowosc, ulica, nr, kod), otrzymasz ten sam plik z dopisanymi kolumnami: dopasowanie, TERYT, współrzędne, score. Format wejściowy: CSV (UTF-8) lub XLSX, do 100 tys. wierszy na request.
curl -s -X POST "https://api.adresy.app/api/v1/match/file" \
-H "X-API-Key: sk_live_xxx" \
-F "[email protected]" \
-F "min_score=82" \
-o wynik.csv
Tryb streaming — wyniki lecą NDJSON zanim całość się zakończy:
curl -N -X POST "https://api.adresy.app/api/v1/match/stream" \
-H "X-API-Key: sk_live_xxx" \
-F "[email protected]"
Kody błędów
| Status | Znaczenie | Działanie |
|---|---|---|
200 | OK | — |
400 | Nieprawidłowe parametry | Sprawdź pole detail w JSON. |
401 | Brak / zły klucz API | Nagłówek X-API-Key. |
404 | Nie znaleziono | Pole found: false jest normą, nie błędem. |
429 | Rate limit | Odczytaj Retry-After, zwolnij. |
500 | Błąd serwera | Ponów z backoffem. Zgłoś przez /kontakt/. |
FAQ — najczęstsze pytania developerów
Czy API jest darmowe?
Skąd pochodzą dane adresowe?
Jak często aktualizowane są dane?
Czy mogę używać API komercyjnie?
Jak działa endpoint /match i kiedy go używać?
POST /api/v1/match przyjmuje „brudny" ciąg tekstowy adresu (literówki, polskie skróty typu „ul.", „pl.", brak kodu pocztowego) i dopasowuje go do kanonicznego rekordu PRG. Używa algorytmów fuzzy-match (RapidFuzz, odległość Levenshteina) plus heurystyk dla polskich skrótów. Używaj, gdy masz dane od użytkownika (formularz, import CSV, OCR). Dla czystych danych z wiarygodnego źródła szybszy jest /lookup/kod-dla-adresu.Jakie są limity batcha /match/file?
/api/v1/match/stream (NDJSON, streaming odpowiedzi — klient może przetwarzać wyniki równolegle z uploadem) lub podziel plik. Czas przetwarzania to ~200-500 wierszy na sekundę w zależności od jakości danych wejściowych.Czy zwracacie współrzędne w WGS84?
lat, lon są w układzie WGS84 (EPSG:4326). Wewnętrznie dane PRG przechowywane są w PUWG 1992 (EPSG:2180) i konwertowane w locie przez PyProj. Jeśli potrzebujesz natywnego układu polskiego, dodaj parametr srid=2180.Co zrobić przy 429 Too Many Requests?
Retry-After (liczba sekund), zaczekaj i ponów. Dla klienta produkcyjnego zaimplementuj wykładniczy backoff: 1s, 2s, 4s, 8s, 16s. Jeśli widzisz 429 przy normalnym obciążeniu, zwiększ plan lub rozważ cache lokalny — wiele zapytań o ten sam kod pocztowy można trzymać w Redis/memcached na 24h (dane zmieniają się rzadko).Czy jest OpenAPI / Swagger?
https://api.adresy.app/openapi.json, interaktywny Swagger UI pod /docs, Redoc pod /redoc. Możesz wygenerować klienta w dowolnym języku przez openapi-generator.Czy dane są zgodne z RODO?
Jak dodać obsługę adresów historycznych (np. poprzednie nazwy ulic)?
nazwa_2 w rekordzie ULIC zawiera poprzednią nazwę ulicy (gdy istnieje). Endpoint /lookup/teryt zwraca oba warianty. Aliasy historyczne (Stalingradu → Marszałkowska, etc.) przechowujemy osobno — dostępne w planie Business przez parametr historyczne=true.Mogę hostować API u siebie (on-premise)?
Następne kroki
- Wypróbuj endpoint w aplikacji — interaktywny UI bez pisania kodu.
- Weź klucz API — Starter bezpłatnie.
- Czym jest PRG? — kontekst danych źródłowych.
- Czym jest TERYT? — SIMC, ULIC, TERC w praktyce.
- Wszystkie narzędzia — wyszukiwarki gotowe do użycia.