API CEIDG: jak dostać token i pobierać nowe firmy (v3, krok po kroku)
API CEIDG nie jest publiczne. Adres dane.biznes.gov.pl/api/ceidg/v3
odpowiada 401 Unauthorized,
dopóki nie wyślesz tokenu — a token dostaniesz tylko po założeniu konta, potwierdzeniu go
Profilem Zaufanym, zaakceptowaniu oświadczenia i złożeniu wniosku o dostęp. Poniżej cała
ta ścieżka, sposób wysłania tokenu, obsługa błędów i pułapka z PKD, która psuje filtry.
$ curl -i https://dane.biznes.gov.pl/api/ceidg/v3
HTTP/2 401
{"message":"Unauthorized",
"http_status_code":401}
Ta sama odpowiedź wraca dla /swagger/index.html —
czyli nie da się przeczytać specyfikacji „z ulicy”. To jest powód, dla którego w Google
prawie nie ma polskich przewodników po tym API.
Rejestracja w Hurtowni Danych CEIDG — sześć kroków do tokenu
Hurtownia Danych (dane.biznes.gov.pl) nie ma własnego loginu i hasła. Logowanie idzie przez login.gov.pl, czyli przez Profil Zaufany albo bankowość — i to jest pierwsza niespodzianka: bez potwierdzonego profilu nie wejdziesz, nawet mając konto.
- 1 Wejdź na dane.biznes.gov.pl i wybierz rejestrację — wypełniasz wniosek o dostęp.
- 2 Zaakceptuj oświadczenie o ochronie i przetwarzaniu danych osobowych. Bez tego kroku dostęp nie zostanie nadany.
- 3 Potwierdź tożsamość Profilem Zaufanym (login.gov.pl). Jeśli go nie masz — założenie zajmuje chwilę przez bankowość albo e-dowód, ale trzeba to zrobić poza tym serwisem.
- 4 Zaloguj się do Hurtowni Danych i poczekaj na nadanie dostępu do zasobów.
- 5 W panelu wygeneruj token API i zapisz go w miejscu, z którego nie wycieknie — do zmiennej środowiskowej albo menedżera sekretów, nigdy do repozytorium.
- 6
Sprawdź, że działa: wyślij pierwsze zapytanie z nagłówkiem
Authorization: Bearer …. Jeśli dalej dostajesz 401, problem jest w tokenie, nie w zapytaniu.
Gdzie wpisuje się token i jak wygląda nagłówek
Token idzie w nagłówku Authorization,
poprzedzony słowem Bearer.
To nie jest parametr w adresie — jeśli wkleisz token do query stringa, skończy się to w
logach pośredników i w historii przeglądarki.
# Każde zapytanie bez tokenu kończy się tak samo:
curl -i "https://dane.biznes.gov.pl/api/ceidg/v3/firmy"
# HTTP/2 401
# {"message":"Unauthorized","http_status_code":401} # Token idzie w nagłówku Authorization jako Bearer
curl -i -H "Authorization: Bearer $CEIDG_TOKEN" \
"https://dane.biznes.gov.pl/api/ceidg/v3/firmy?nip=1234567890" Jak obsługiwać błędy, żeby nie zgubić danych i nie zablokować się na dobre
Każdy kod odpowiedzi wymaga innej reakcji — potraktowanie ich jednakowo jest najczęstszym błędem w integracjach. Poniższa tabela to nie teoria, a kolejność decyzji w kodzie.
| Kod | Znaczenie | Co robi klient | Czego nie robić |
|---|---|---|---|
| 401 / 403 | Token zły, wygasły albo brak dostępu do zasobu | Zatrzymaj się, odśwież token, zaloguj ponownie | Nie ponawiaj w pętli — zablokujesz się i zaśmiecisz logi |
| 429 | Przekroczony limit zapytań | Ponów z rosnącym opóźnieniem (backoff), kolejkuj zapytania | Nie wysyłaj natychmiast ponownie — pogorszysz sytuację |
| 5xx | Błąd po stronie usługi | Backoff i ponowienie, maksymalnie kilka prób | Nie traktuj jak „brak danych” — to nieprawda |
| 200 | Poprawna odpowiedź (bywa niepełna — paginacja) | Zapisuj i przechodź do kolejnej strony, aż skończą się dane | Nie zakładaj, że pierwsza strona to całość |
import os, time, requests
BASE = "https://dane.biznes.gov.pl/api/ceidg/v3"
TOKEN = os.environ["CEIDG_TOKEN"] # nigdy nie trzymaj tokenu w repo
S = requests.Session()
S.headers["Authorization"] = f"Bearer {TOKEN}"
def get(path, **params):
"""Jedno miejsce, w którym obsługujemy błędy i ponawianie."""
for attempt in range(5):
r = S.get(f"{BASE}{path}", params=params, timeout=30)
if r.status_code == 200:
return r.json()
if r.status_code in (401, 403):
# token wygasł / nieprawidłowy / brak dostępu do zasobu
raise SystemExit(f"Brak autoryzacji ({r.status_code}) — odśwież token")
if r.status_code == 429:
# przekroczony limit — czekaj coraz dłużej (backoff)
time.sleep(2 ** attempt)
continue
if 500 <= r.status_code < 600:
time.sleep(2 ** attempt) # błąd po stronie API — ponów
continue
r.raise_for_status()
raise RuntimeError("API nie odpowiedziało poprawnie po 5 próbach")
# Kształt odpowiedzi sprawdź w dokumentacji po zalogowaniu —
# poniżej zapisujemy to, co zwróciło wywołanie, do pliku do dalszej obróbki.
import json
data = get("/firmy", page=1)
json.dump(data, open("ceidg-batch.json", "w"), ensure_ascii=False)
Token czytany z CEIDG_TOKEN — nie z kodu. Ścieżkę do listy firm i nazwy
parametrów uzupełnij z dokumentacji, do której dostaniesz dostęp po zalogowaniu; cała
reszta (autoryzacja, backoff, zapis) jest gotowa.
Co realnie dostajesz w odpowiedzi — i co z tym zrobić
Rekord z CEIDG to dane ewidencyjne plus to, co przedsiębiorca zdecydował się ujawnić. W arkuszu, który budujemy z tego źródła, wychodzi z tego 22 kolumny — poniżej grupy, które mają znaczenie w sprzedaży, a nie w ewidencji.
- • nazwa i NIP (klucz do deduplikacji)
- • REGON, status wpisu
- • data rozpoczęcia działalności — najważniejsze pole dla prospecting
- • imię i nazwisko przedsiębiorcy
- • e-mail i telefon — o ile ujawnione
- • adres i WWW, jeśli podane
- • kody PKD (2025 dla nowych wpisów, 2007 dla starszych)
- • opis działalności
- • dodatkowe kody i zawody, jeśli wpisane
- • danych o przychodzie i zadłużeniu
- • spółek z KRS (inny rejestr)
- • zgody marketingowej — jawność nią nie jest
Pułapka PKD 2025 ↔ 2007, która psuje filtry w API
Nowe wpisy używają klasyfikacji PKD 2025 (Dz.U. 2024 poz. 1936), starsze zostały na PKD 2007. Jeśli filtrujesz zapytanie po jednym zestawie kodów, dostajesz tylko część rynku — zwykle gubisz właśnie te firmy, które są nowe. Praktyczna reguła: normalizuj kody przy zapisie, nie przy odczycie, i trzymaj w rekordzie obie wartości.
Pełne mapowanie i wyszukiwarkę kodów znajdziesz na stronie PKD 2025 — wyszukiwarka i mapowanie .
Jeśli dane mają służyć do dzwonienia, a nie do budowania produktu
API jest darmowe, ale nie jest bezpłatne: płacisz dniem pracy na integrację i utrzymaniem jej w kolejnych latach — odświeżaniem tokenu, obsługą limitów, deduplikacją i mapowaniem PKD. Jeśli Twoje zadanie brzmi „chcę dzwonić do nowych firm od poniedziałku”, ta inwestycja się nie zwróci.
Dlatego równolegle prowadzimy arkusz: te same dane z CEIDG, dopisywane trzy razy dziennie, w 22 kolumnach ułożonych pod sprzedaż. Bez rejestracji, bez tokenu, bez kodu.
Najczęstsze pytania o API CEIDG
Czy API CEIDG jest publiczne?
Nie. Bez tokenu dostajesz 401, a dokumentacja jest za logowaniem. Dostęp jest bezpłatny, ale imienny — przez konto w Hurtowni Danych i Profil Zaufany.
Token czy klucz API?
Token, wysyłany w nagłówku Authorization: Bearer ….
Nie w adresie zapytania.
Co po przekroczeniu limitu?
Błąd zamiast danych — trzeba kolejkować zapytania i ponawiać z rosnącym opóźnieniem. Wysokość limitu sprawdź w dokumentacji po zalogowaniu; nie zgadujemy jej tutaj.
Czy API zwraca e-maile i telefony?
Tak, ale tylko ujawnione we wniosku CEIDG-1. Nie ma kontaktu do firm, które go nie podały — pokrycie zależy od branży.
Czy jest API v4?
Wersja v3 jest tą, na której pracujemy. Czy poza nią udostępniono nowszą — sprawdź w panelu po zalogowaniu; nie potwierdzamy tego bez źródła.
Czy trzeba API, żeby mieć dane?
Nie. Jeśli dane są do sprzedaży, a nie do produktu, szybszy jest gotowy arkusz .