API CEIDG v3: token, endpointy, limity i przykłady kodu
Przewodnik po API CEIDG v3 dla programisty: bezpłatny klucz z Hurtowni danych, endpointy /firmy i /firma, filtry, pola JSON, limity i kod w curl, JS i Pythonie.
Krótka odpowiedź
API CEIDG to bezpłatny interfejs REST Hurtowni danych CEIDG i Biznes.gov.pl pod adresem https://dane.biznes.gov.pl/api/ceidg/v3. Klucz dostajesz po rejestracji w Hurtowni danych i wysyłasz go w nagłówku Authorization: Bearer. Lista /firmy filtruje jednoosobowe działalności po NIP, nazwie, adresie, PKD i dacie rozpoczęcia, ale PKD oraz e-mail i telefon (od 1.11.2026 tylko za zgodą przedsiębiorcy) zwraca dopiero /firma/{id}. Limity: 50 zapytań na 3 minuty i 1 000 na godzinę.
Opis opiera się na dokumentacji dla integratorów API v3 (wersja 1.1 z 14.01.2025), na zapytaniach bez klucza z 1.11.2026 i na naszej integracji z CEIDG w OutreachPilot.pl. Jeśli nie programujesz, a szukasz firm do sprzedaży, zacznij od tekstu CEIDG jako źródło leadów B2B albo poradnika o danych z CEIDG.
Co zwraca API CEIDG, a czego nie?
CEIDG to rejestr przedsiębiorców będących osobami fizycznymi: jednoosobowych działalności i wspólników spółek cywilnych. Spółek z o.o., akcyjnych ani jawnych tu nie ma, bo są w KRS, który ma osobne Open API KRS. Dostawcą API jest Ministerstwo Rozwoju i Technologii (pole schema:provider w każdej odpowiedzi).
| Dostaniesz | Nie dostaniesz |
|---|---|
| listę wpisów po NIP, REGON, nazwie, właścicielu, adresie, PKD, statusie i dacie rozpoczęcia | PKD i kontaktu na liście /firmy (są tylko w szczegółach) |
| szczegóły wpisu: kody PKD, daty zawieszenia i wykreślenia, adresy, upadłość i zakazy | numeru PESEL i daty urodzenia (art. 43 ust. 1 ustawy o CEIDG) |
| e-mail, telefon i www, gdy przedsiębiorca je podał (od 1.11.2026 także zgodził się na publikację) | kontaktu bez zgody przedsiębiorcy od 1.11.2026 |
liczbę wpisów pasujących do filtrów (count) w jednym zapytaniu | spółek z KRS, statusu VAT i rachunków (to API Białej listy VAT) |
identyfikatory wpisów zmienionych w danym okresie (/zmiana) | filtra „tylko kod przeważający” i danych finansowych |
Starsze poradniki opisują datastore.ceidg.gov.pl, które według Akademii Biznes.gov.pl zastępuje Hurtownia danych pod adresem dane.biznes.gov.pl.
Jak uzyskać token do API CEIDG?
Dostęp jest bezpłatny dla każdego zarejestrowanego użytkownika: według Akademii Biznes.gov.pl informacje o przedsiębiorcach są udostępniane „bezpłatnie, wg idei otwartych danych”. Kroki według stron odczytanych 1.11.2026:
- Konto na Biznes.gov.pl. Do Hurtowni danych logujesz się Profilem Zaufanym (strona Hurtowni danych).
- Wniosek o dostęp. Uprawnienia nadaje e-usługa „Wniosek o dostęp do raportów CEIDG”. Dostęp dostajesz po zaakceptowaniu oświadczenia o ochronie i przetwarzaniu danych osobowych.
- Klucz w mailu. Według strony dla integratorów (aktualizacja 11.09.2026) po rejestracji przychodzi mail z dostępem do aplikacji raportowej i kluczem do API Hurtowni. Dokumentacja nazywa go tokenem JWT i każe wysyłać w nagłówku
Authorization: Bearer {JWT-TOKEN}.
Okresu ważności klucza ani sposobu jego odnowienia w dokumentacji nie znaleźliśmy, więc ustaw alarm na serię odpowiedzi 401. Dokumentacja podaje za to, że dane użytkowników API są przechowywane 36 miesięcy.
Klucz trzymaj w zmiennej środowiskowej albo w menedżerze sekretów, nigdy w repozytorium. Pułapka z naszej integracji: klucz wklejony ze spacją na końcu albo z przedrostkiem Bearer dawał 401, choć sam był poprawny. Przykłady niżej czyszczą go przed użyciem.
Zapytanie bez klucza (nasz test z 1.11.2026, godz. 19:25):
curl -s -i "https://dane.biznes.gov.pl/api/ceidg/v3/firmy?miasto=Krak%C3%B3w&limit=1"
zwraca HTTP/2 401, content-type: application/json i treść {"message":"Unauthorized","http_status_code":401}. Nieprawidłowy klucz dał o 19:33 to samo. Środowisko testowe z dokumentacji (test-dane.biznes.gov.pl) nie odpowiedziało nam 1.11.2026 w ciągu 15 sekund.
Jakie endpointy ma API CEIDG v3?
Wszystkie metody to GET z tym samym nagłówkiem autoryzacji. Dokumentacja ostrzega, że wielkość liter ma znaczenie i w nazwach parametrów, i w ich wartościach, a poprawna notacja nazw to małe litery.
| Ścieżka | Zwraca | Klucz w JSON | Nasze doświadczenie |
|---|---|---|---|
/firmy?... | listę wpisów po filtrach, do 25 na stronę | firmy[], count, links | bez PKD i kontaktu (surowa odpowiedź z 8.10.2026) |
/firma?nip=... albo ?regon=... | pełne dane wpisów o tym NIP-ie lub REGON-ie | firma[] | jeden NIP bywa w kilku wpisach |
/firma/{id} | pełne dane jednego wpisu | firma[0] | źródło PKD, kontaktu i dat |
/firma?ids=...&ids=... | szczegóły kilku wpisów naraz | firma[] | jest w dokumentacji, nie testowaliśmy |
/zmiana?dataod=...&datado=... | identyfikatory wpisów zmienionych w okresie | identyfikatoryWpisow[] | dokumentacja zaleca okno do 5 dni; nie testowaliśmy |
/raporty?dataod=...&datado=... | listę gotowych raportów Hurtowni | raporty[] | nie testowaliśmy |
/raport/{id} | plik raportu | archiwum ZIP | nie testowaliśmy |
/zmiana przydaje się do synchronizacji przyrostowej: przyjmuje też datę z godziną (RRRR-MM-DD GG:MM:SS), a po każdy identyfikator idziesz do /firma/{id}.
Filtry listy /firmy
Filtry poza page, limit, dataod i datado można powtarzać (pkd=6201Z&pkd=6210B). W naszej integracji wartości jednego pola łączą się przez LUB, a różne pola przez ORAZ.
| Parametr | Format | Uwagi |
|---|---|---|
nip, regon | cyfry | NIP i REGON przedsiębiorcy; nip_sc i regon_sc to identyfikatory spółki cywilnej |
imie, nazwisko, nazwa | tekst | imię i nazwisko właściciela to osobne filtry |
miasto, wojewodztwo, powiat, gmina | nazwy jak w TERYT | powiat grodzki to nazwa miasta (powiat=Kraków), ziemski jego nazwa (powiat=tarnowski); oba działały 13.10.2026 |
kod, ulica, budynek, lokal | kod=31-000 | kod pocztowy z kreską |
pkd | 6201Z | kod bez kropek; wynik obejmuje firmy z tym kodem jako przeważającym albo pozostałym |
status | 5 wartości | AKTYWNY, ZAWIESZONY, WYKRESLONY, OCZEKUJE_NA_ROZPOCZECIE_DZIALANOSCI (taka pisownia, bez „L”), WYLACZNIE_W_FORMIE_SPOLKI |
dataod, datado | RRRR-MM-DD | data rozpoczęcia działalności, oba końce włącznie (sprawdzone 10.10.2026) |
page | liczba | strony liczone od zera |
limit | od 1 do 25 | więcej dało HTTP 400 NIEPOPRAWNY_ROZMIAR_STRONY (13.10.2026), choć przykład w dokumentacji ma limit=50 |
Trzech rzeczy dokumentacja nie mówi wprost:
- Bez
statusdostajesz wszystkie statusy, także wpisy wykreślone: adresy wlinksodpowiedzi bez tego filtra zawierają wszystkie pięć wartości. Do listy kontaktów ustawstatus=AKTYWNY. - Kolejności wyników dokumentacja nie opisuje. Najnowsze firmy wybierzesz przez
dataodidatado, a sortuj po swojej stronie. - Do końca 2026 r. w CEIDG są wpisy w obu klasyfikacjach PKD. W losowej próbie 465 aktywnych wpisów z 3.10.2026 kody PKD 2025 miało 49,5% (przedział 95%: od 44,9 do 54,0%, raport PKD 2025). Szukaj po obu: programiści to
6201Zw PKD 2007 oraz6210Ai6210Bw PKD 2025. Odpowiedniki sprawdzisz w wyszukiwarce PKD, terminy zmiany w tekście o PKD 2025.
Jak pobrać listę firm z CEIDG przez API?
Przykłady szukają aktywnych firm z kodem PKD programistów w Krakowie, które rozpoczęły działalność w październiku 2026 r., i pobierają szczegóły wpisów. Klucz jest w zmiennej CEIDG_API_TOKEN. W curl trzy zapytania: lista (--data-urlencode koduje polskie znaki), szczegóły wpisu o id z listy i wyszukiwanie po NIP, które od razu daje pełne dane, czasem kilku wpisów:
read -rs CEIDG_API_TOKEN && export CEIDG_API_TOKEN # wklej klucz, nie trafi do historii curl -s --get "https://dane.biznes.gov.pl/api/ceidg/v3/firmy" \ -H "Authorization: Bearer $CEIDG_API_TOKEN" -H "Accept: application/json" \ --data-urlencode "pkd=6201Z" --data-urlencode "pkd=6210A" --data-urlencode "pkd=6210B" \ --data-urlencode "miasto=Kraków" --data-urlencode "status=AKTYWNY" \ --data-urlencode "dataod=2026-10-01" --data-urlencode "datado=2026-10-31" \ --data-urlencode "page=0" --data-urlencode "limit=25" \ | jq '{count, id: .firmy[0].id, start: .firmy[0].dataRozpoczecia}' curl -s "https://dane.biznes.gov.pl/api/ceidg/v3/firma/$ID" \ -H "Authorization: Bearer $CEIDG_API_TOKEN" -H "Accept: application/json" \ | jq '.firma[0] | {pkdGlowny, rokPkd, status, maEmail: (.email != null)}' curl -s "https://dane.biznes.gov.pl/api/ceidg/v3/firma?nip=$NIP" \ -H "Authorization: Bearer $CEIDG_API_TOKEN" -H "Accept: application/json" \ | jq '[.firma[] | {id, status, dataRozpoczecia}]'
Puste wyjście i błąd jq zwykle oznaczają HTTP 204, czyli brak wpisów dla podanych filtrów.
Wersja dla Node 18 i nowszych. Funkcja ceidg() pilnuje odstępu 3,6 s między zapytaniami (zalecenie dokumentacji), po HTTP 429 wstrzymuje wszystkie zapytania procesu na 190 s, a błędy sieci i odpowiedzi HTML ponawia z rosnącym odstępem:
// ceidg.mjs, Node 18+. Klucz tylko ze zmiennej środowiskowej CEIDG_API_TOKEN. const BASE = "https://dane.biznes.gov.pl/api/ceidg/v3"; const TOKEN = (process.env.CEIDG_API_TOKEN ?? "").trim().replace(/^Bearer\s+/i, ""); if (!TOKEN) throw new Error("Ustaw zmienną CEIDG_API_TOKEN"); const ODSTEP_MS = 3_600; // dokumentacja: 50 zapytań na 3 min, czyli 1 co 3,6 s const BLOKADA_MS = 190_000; // 180 s od ostatniego zapytania i zapas const sleep = (ms) => new Promise((r) => setTimeout(r, ms)); export class BladTrwaly extends Error {} let nastepne = 0; // najwcześniejsza chwila kolejnego zapytania, wspólna dla procesu async function slot() { const teraz = Date.now(); const start = Math.max(teraz, nastepne); nastepne = start + ODSTEP_MS; await sleep(start - teraz); } export async function ceidg(sciezka, proby = 3) { for (let proba = 1; proba <= proby; proba++) { await slot(); let res, tekst; try { res = await fetch(BASE + sciezka, { headers: { Authorization: `Bearer ${TOKEN}`, Accept: "application/json" }, signal: AbortSignal.timeout(15_000), }); tekst = await res.text(); } catch (err) { // timeout albo zerwane połączenie („fetch failed”) if (proba === proby) throw err; await sleep(2_000 * 2 ** proba + Math.random() * 1_000); continue; } if (res.status === 204 || res.status === 404) return null; // brak danych if ([400, 401, 403].includes(res.status)) { throw new BladTrwaly(`HTTP ${res.status}: ${tekst.slice(0, 200)}`); } if (res.status === 429) { nastepne = Date.now() + BLOKADA_MS; // wszystkie kolejne zapytania czekają continue; } if (res.ok) { try { return JSON.parse(tekst); } catch { // strona HTML (przerwa serwisowa) albo urwany JSON: błąd przejściowy } } if (proba === proby) throw new Error(`CEIDG: HTTP ${res.status}, brak poprawnego JSON`); await sleep(2_000 * 2 ** proba + Math.random() * 1_000); } throw new Error("CEIDG: wyczerpane próby"); } // Lista: aktywne firmy z PKD programistów w Krakowie, start w październiku 2026 const q = new URLSearchParams(); for (const kod of ["6201Z", "6210A", "6210B"]) q.append("pkd", kod); // PKD 2007 i 2025 q.set("miasto", "Kraków"); q.set("status", "AKTYWNY"); q.set("dataod", "2026-10-01"); q.set("datado", "2026-10-31"); q.set("limit", "25"); const firmy = []; for (let page = 0; ; page++) { q.set("page", String(page)); const lista = await ceidg(`/firmy?${q}`); if (!lista?.firmy?.length) break; firmy.push(...lista.firmy); if (firmy.length >= lista.count || lista.firmy.length < 25) break; } // Szczegóły: osobne zapytanie na każdą firmę const pkdZKropkami = (kod) => kod?.replace(/^(\d{2})(\d{2})([A-Z])$/, "$1.$2.$3"); for (const { id } of firmy.slice(0, 5)) { const wpis = (await ceidg(`/firma/${id}`))?.firma?.[0]; console.log(id, pkdZKropkami(wpis?.pkdGlowny?.kod), wpis?.rokPkd, wpis?.email ? "e-mail jest" : "brak e-maila"); }
To samo w Pythonie z biblioteką requests:
"""ceidg.py, Python 3.9+ z biblioteką requests. Klucz tylko ze zmiennej CEIDG_API_TOKEN.""" import os import random import time import requests BASE = "https://dane.biznes.gov.pl/api/ceidg/v3" TOKEN = os.environ.get("CEIDG_API_TOKEN", "").strip().removeprefix("Bearer ").strip() if not TOKEN: raise SystemExit("Ustaw zmienną CEIDG_API_TOKEN") ODSTEP = 3.6 # s: 50 zapytań na 3 min BLOKADA = 190 # s po HTTP 429 _nastepne = 0.0 class BladTrwaly(Exception): pass def _slot(): global _nastepne teraz = time.monotonic() start = max(teraz, _nastepne) _nastepne = start + ODSTEP time.sleep(start - teraz) def ceidg(sciezka, params=None, proby=3): global _nastepne for proba in range(1, proby + 1): _slot() try: r = requests.get( BASE + sciezka, params=params, headers={"Authorization": f"Bearer {TOKEN}", "Accept": "application/json"}, timeout=15, ) except requests.RequestException: if proba == proby: raise time.sleep(2 * 2 ** proba + random.random()) continue if r.status_code in (204, 404): return None if r.status_code in (400, 401, 403): raise BladTrwaly(f"HTTP {r.status_code}: {r.text[:200]}") if r.status_code == 429: _nastepne = time.monotonic() + BLOKADA # kolejne zapytania czekają continue if r.ok: try: return r.json() except ValueError: pass # HTML zamiast JSON: błąd przejściowy if proba == proby: raise RuntimeError(f"CEIDG: HTTP {r.status_code}, brak poprawnego JSON") time.sleep(2 * 2 ** proba + random.random()) raise RuntimeError("CEIDG: wyczerpane próby") params = [("pkd", "6201Z"), ("pkd", "6210A"), ("pkd", "6210B"), ("miasto", "Kraków"), ("status", "AKTYWNY"), ("dataod", "2026-10-01"), ("datado", "2026-10-31"), ("limit", 25)] firmy, strona = [], 0 while True: lista = ceidg("/firmy", params + [("page", strona)]) if not lista or not lista.get("firmy"): break firmy += lista["firmy"] if len(firmy) >= lista["count"] or len(lista["firmy"]) < 25: break strona += 1 print(len(firmy), "wpisów") if firmy: wpis = (ceidg(f"/firma/{firmy[0]['id']}") or {}).get("firma", [{}])[0] print(wpis.get("pkdGlowny"), wpis.get("rokPkd"), "e-mail jest" if wpis.get("email") else "brak e-maila")
Przykładów nie uruchamialiśmy na produkcyjnym API, bo nasz klucz obsługuje działającą aplikację. Ścieżki błędów (błąd sieci, strona HTML, 429, 204) sprawdziliśmy na podstawionych odpowiedziach; zasady są te same co w naszym kliencie produkcyjnym.
Mapa pól odpowiedzi
Kształt odpowiedzi listy (wartości zastąpione wielokropkiem):
{ "firmy": [ { "id": "…", "nazwa": "…", "adresDzialalnosci": { "ulica": "ul. …", "budynek": "…", "lokal": "…", "miasto": "…", "wojewodztwo": "…", "powiat": "…", "gmina": "…", "kraj": "PL", "kod": "…", "terc": "…", "simc": "…" }, "wlasciciel": { "imie": "…", "nazwisko": "…", "nip": "…", "regon": "…" }, "dataRozpoczecia": "RRRR-MM-DD", "status": "AKTYWNY", "link": "https://dane.biznes.gov.pl/api/ceidg/v3/firma/…" } ], "count": "…", "links": { "first": "…", "prev": "…", "self": "…", "next": "…", "last": "…" }, "properties": { "dc:title": "firmy", "schema:provider": "Ministerstwo Rozwoju i Technologii" } }
Najważniejsze pola:
| Pole | Lista /firmy | Szczegóły /firma | Uwagi |
|---|---|---|---|
id | tak | tak | identyfikator wpisu, klucz do /firma/{id} |
nazwa | tak | tak | firma przedsiębiorcy, zawiera jego imię i nazwisko |
wlasciciel.imie, wlasciciel.nazwisko | tak | tak | dane osoby fizycznej |
wlasciciel.nip, wlasciciel.regon | tak | tak | REGON bywa 9- albo 14-cyfrowy |
status, dataRozpoczecia | tak | tak | data jako RRRR-MM-DD |
dataZawieszenia, dataWznowienia, dataWykreslenia | nie | tak | bywają nieobecne, gdy zdarzenia nie było |
adresDzialalnosci.* | tak | tak | terc, simc i ulic to kody TERYT |
pkdGlowny.kod, pkd[], rokPkd | nie | tak | kod bez kropek, rokPkd to 2007 albo 2025 |
email, telefon, www | nie | tak | od 1.11.2026 tylko za zgodą przedsiębiorcy |
adresDoreczenElektronicznych | nie | tak | adres do e-Doręczeń, nie zwykła skrzynka |
spolki[] | nie | tak | NIP i REGON spółek cywilnych przedsiębiorcy |
upadlosc, zakazy, dataZgonu | nie | tak | do odsiewania firm w upadłości i po śmierci właściciela |
Jak pobrać kod PKD firmy?
Lista go nie zawiera: surowa odpowiedź /firmy z 8.10.2026 miała tylko id, nazwa, adresDzialalnosci, wlasciciel, dataRozpoczecia, status i link. Kod przeważający jest w pkdGlowny.kod szczegółów, wszystkie kody w pkd[] (w naszych odpowiedziach razem z przeważającym), a klasyfikacja w rokPkd. Kody przychodzą bez kropek: 6210B to 62.10.B, co zamienia funkcja pkdZKropkami z przykładu w Node.
Filtr pkd łapie też kody pozostałe, więc firmy, dla których branża jest poboczna, odsiejesz dopiero po szczegółach: jedno zapytanie na firmę.
Pułapki w danych
- Tabela pól w dokumentacji ma literówki. Pisze np.
firma.właściciel.nipifirma.obywatelswto.kraj, a w JSON są kluczewlascicieliobywatelstwa. Mapuj według prawdziwej odpowiedzi, nie według tabeli. - Ulica z przedrostkiem.
ulicaprzychodzi jakoul. Zwierzyniecka(przykład z dokumentacji). Przed porównaniem adresów zdejmijul.. - Różna wielkość liter. W danych są obok siebie
KRAKÓWiKraków(nasz odczyt z 13.10.2026), a województwa przychodzą wielkimi literami. Porównuj bez wielkości liter i polskich znaków. - Puste wartości. Pusty obiekt, pusta lista i pusty napis traktuj jak brak informacji; tak robi nasz klient przy polu
upadlosc. - Jeden NIP, kilka wpisów. Po zamknięciu i ponownym otwarciu działalności ten sam NIP ma osobne wpisy (w przykładzie z dokumentacji dwa wpisy z jednym NIP-em mają różne
idi REGON-y). Kluczem w bazie niech będzieid.
Jaki jest limit zapytań API CEIDG?
Dokumentacja opisuje dwa limity działające naraz: 50 żądań w ciągu 3 minut i 1 000 w ciągu 60 minut. Po przekroczeniu pierwszego API robi 180 sekund przerwy liczonej od ostatniego żądania. Żądania wysłane przed końcem przerwy mogą według dokumentacji skończyć się ciągłym brakiem dostępu. Optymalny odstęp to 3,6 s, czyli dokładnie 1 000 zapytań na godzinę: oba limity spotykają się w jednym tempie.
Czas pracy przy jednym zapytaniu co 3,6 s:
| Zadanie | Zapytania | Czas |
|---|---|---|
liczba wpisów dla filtrów (limit=1, pole count) | 1 | 3,6 s |
| 500 firm z listy, bez szczegółów | 20 stron po 25 | ok. 1 min 12 s |
| 500 firm ze szczegółami (PKD, kontakt) | 20 + 500 | ok. 31 min |
| 5 000 firm ze szczegółami | 200 + 5 000 | ok. 5 h 12 min |
| lista wszystkich aktywnych wpisów (2 649 377 wpisów, odczyt z 10.10.2026) | ok. 106 tys. stron | ok. 106 h, ponad 4 doby |
Szczegóły wszystkich aktywnych wpisów to kolejne 2,65 mln zapytań, czyli ponad 100 dni pracy klucza. Do analiz całego rejestru sprawdź najpierw gotowe raporty Hurtowni (/raporty).
Jeden klucz, jeden limit dla całej aplikacji
Dokumentacja nie precyzuje, czy limit liczy się na klucz, czy na adres IP, ale nasz przypadek pasuje do limitu na klucz. 29.10.2026 o 13:10 skrypt pomiarowy na innym komputerze niż produkcja, z tym samym kluczem, dostał od CEIDG HTTP 429 przy 10 zapytaniach na minutę. Mieścił się w limicie 3-minutowym (30 z 50), ale 10 na minutę to 600 na godzinę, czyli 60% limitu godzinowego, a resztę zużywała produkcja.
Dlatego w OutreachPilot.pl wszystkie procesy z tym kluczem (wyszukiwarka, zadania w tle, skrypty) biorą zapytania z jednego wspólnego licznika: najwyżej 45 na 3 minuty i 900 na godzinę. Zadania w tle mogą zająć najwyżej 60% puli, żeby nie blokować użytkownika czekającego na wynik, a po 429 milkną wszyscy na 190 s. Osobny limiter w każdym procesie nie działa, bo procesy nie wiedzą o sobie nawzajem.
Jak obsłużyć 429, awarie i przerwy serwisowe?
Dokumentacja wymienia kody 200, 204, 400, 401, 403, 404, 429 i 500. Tak je obsługujemy:
| Odpowiedź | Co znaczy | Co zrobić |
|---|---|---|
| 200 z JSON | dane | parsuj |
| 200, ale treść to nie JSON | strona błędu bramki albo przerwy serwisowej (widzieliśmy 10.10 i 29.10.2026) | błąd przejściowy: ponów później, nie zapisuj „brak firmy” |
| 204 | brak danych dla kryteriów | pusta lista; przy /firma?nip= NIP-u nie ma w CEIDG, np. to spółka z KRS |
| 400 | błędne zapytanie, np. limit powyżej 25 | popraw zapytanie, nie ponawiaj |
| 401, 403 | brak klucza, zły klucz albo brak uprawnień | zatrzymaj proces i sprawdź klucz |
| 404 | zasób nie istnieje, np. zły id | traktuj jak brak wpisu |
| 429 | przekroczony limit | wstrzymaj wszystkie zapytania na co najmniej 180 s od ostatniego |
| 500, błąd sieci, timeout | awaria po stronie rejestru | ponów z rosnącym odstępem |
Pomiar własny: 29 i 30.10.2026 pobieraliśmy losowe wpisy do raportu o danych kontaktowych w tempie najwyżej 10 zapytań na minutę: do 3 prób na zapytanie i jeszcze jedna runda po 90 s. Wieczorem 29.10.2026 (od 18:30 do 22:24) nie udało się pobrać 74 ze 182 wpisów, czyli ok. 40%, najczęściej przez zerwane połączenie (fetch failed w Node). Od ok. 21:10 zamiast JSON przychodziła strona przerwy serwisowej, więc pracę wstrzymaliśmy do nocy. Między 2:35 a 7:24 30.10.2026 przepadło 35 z 474 wpisów (7%).
Druga pułapka to głębokie stronicowanie. 10.10.2026 strony z wysokim page na liście wszystkich aktywnych wpisów odpowiadały od 25 do 70 s, a potem kończyły się przekroczeniem czasu. Dziel więc listę na przedziały dataod i datado, sprawdzaj count przedziału zapytaniem z limit=1 i stronicuj w małych przedziałach.
Zasady, które u nas działają:
- Jeden licznik zapytań na klucz dla wszystkich procesów, a każde ponowienie liczy się jak nowe zapytanie.
- Po 429 cisza przez co najmniej 180 s od ostatniego zapytania, bez ponowień w trakcie.
- Twardy limit czasu: u nas 15 s dla listy i 6 s dla szczegółów jednego wpisu.
- Parsowanie w
try: strona HTML i urwany JSON to błąd przejściowy, nie brak danych. - Kolejka zamiast pętli: wpis z błędem wraca do kolejki, a kursor stoi w miejscu.
- Cache: listy i szczegóły trzymamy 24 h, ale status firmy tuż przed wysyłką sprawdzamy bez cache.
- Logi bez NIP-u i REGON-u: maskujemy je, bo to identyfikatory osób fizycznych.
Co zmienia 1 listopada 2026 i co z RODO?
Wpis w CEIDG opisuje osobę fizyczną, więc imię, nazwisko, adres, NIP i dane kontaktowe są danymi osobowymi w rozumieniu RODO. Jawność rejestru tego nie zmienia: kto zapisuje te dane u siebie, ma obowiązki z RODO, m.in. informacyjny z art. 14. Pobranie danych przez API i ich ponowne wykorzystanie, na przykład w marketingu, to osobne kwestie prawne: pierwszą reguluje m.in. ustawa o otwartych danych, a wysyłkę ofert mailem art. 398 Prawa komunikacji elektronicznej (poradnik o art. 398 PKE). Praktykę opisuje RODO w cold mailingu B2B.
Według ustawy z 13.03.2026 (Dz.U. 2026 poz. 507) nowy art. 43 ust. 1 i 1a ustawy o CEIDG pozwala udostępniać e-mail, telefon i stronę www tylko wtedy, gdy wnioskodawca zgodził się na ich udostępnienie. Do 31.10.2026 było odwrotnie: dane były jawne, chyba że przedsiębiorca się sprzeciwił. Wniosek CEIDG-1 w wersji 3.3 (od 14.10.2026) ma pole zgody na publikację telefonu i e-maila (pytania i odpowiedzi ministerstwa z 16.10.2026).
Skala zmiany: w losowej próbie 453 aktywnych wpisów z 10.10.2026 e-mail podawało 19,9% wpisów, telefon 15,9%, a stronę www 3,1% (raport o danych kontaktowych w CEIDG). Ustawa nie ma przepisu przejściowego o danych kontaktowych opublikowanych przed 1.11.2026. Jak API pokazuje wpisy bez zgody po tej dacie, jeszcze nie sprawdziliśmy; na stronach Hurtowni i Akademii Biznes.gov.pl nie znaleźliśmy 1.11.2026 komunikatu o zmianie pól email, telefon i www.
Dla kodu wynika z tego jedno: brak pola email albo www nie oznacza, że firma nie ma maila ani strony. Zapisuj taki stan jako „nie wiadomo”, a nie „brak”, żeby filtr „bez strony” nie łapał firm, które nie zgodziły się na publikację adresu. To informacja o przepisach, nie porada prawna.
Czego API CEIDG nie da?
- Spółek z KRS (API KRS) ani statusu VAT i rachunków (API Białej listy).
- Filtra „tylko kod przeważający”: kod przeważający sprawdzisz w szczegółach, jednym zapytaniem na firmę.
- Pewnego kontaktu: przed zmianą e-mail miał co piąty aktywny wpis, od 1.11.2026 tylko wpisy ze zgodą, a czy adres przyjmuje pocztę, API nie sprawdza (składnię i rekordy MX sprawdzisz w weryfikatorze e-mail).
- Szybkiej pełnej kopii: sama lista aktywnych wpisów to ponad 4 doby pracy klucza, szczegóły ponad 100 dni.
Jeśli budujesz własny produkt na danych z rejestru, API wystarczy, a zasady z tego tekstu oszczędzą Ci blokad. Jeśli potrzebujesz listy firm z branży i miasta, w OutreachPilot.pl to jedna funkcja: wyszukiwarka pobiera firmy z CEIDG po PKD i mieście (limity, cache i szczegóły są po naszej stronie), a aplikacja znajduje i weryfikuje adresy e-mail przed kampanią wysyłaną z Twojej skrzynki. Opis jest na stronie baza firm CEIDG. Plan Free kosztuje 0 zł i daje 50 leadów miesięcznie (cennik), a nowe konto zaczyna od 14 dni planu Pro bez karty.
Najczęstsze pytania
Jak uzyskać token API CEIDG?
Załóż konto na Biznes.gov.pl, złóż e-usługę „Wniosek o dostęp do raportów CEIDG” i zaakceptuj oświadczenie o ochronie danych osobowych. Po rejestracji w Hurtowni danych przychodzi mail z kluczem do API, który wysyłasz w nagłówku Authorization: Bearer. Okresu ważności klucza dokumentacja nie podaje.
Czy API CEIDG jest darmowe?
Tak. Według Akademii Biznes.gov.pl dane z Hurtowni danych CEIDG są udostępniane bezpłatnie, potrzebna jest tylko rejestracja. Ograniczeniem jest limit: 50 zapytań na 3 minuty i 1 000 na godzinę.
Jaki jest limit zapytań API CEIDG?
Dokumentacja (wersja 1.1 z 14.01.2025) podaje dwa limity naraz: 50 żądań na 3 minuty i 1 000 na 60 minut. Po przekroczeniu pierwszego API blokuje dostęp na 180 s od ostatniego żądania, więc ponawianie w trakcie blokady ją przedłuża. Bezpieczne tempo to jedno zapytanie co 3,6 s na cały klucz.
Jak pobrać PKD firmy z CEIDG przez API?
Nie z listy /firmy, bo PKD jest tylko w szczegółach wpisu. Zapytaj /firma/{id} albo /firma?nip=: kod przeważający jest w pkdGlowny.kod, wszystkie kody w pkd[], a klasyfikacja w rokPkd. Kody są bez kropek, np. 6210B to 62.10.B.
Czy API CEIDG zwraca e-mail i telefon po 1 listopada 2026?
Pola email, telefon i www są w szczegółach wpisu, ale od 1.11.2026 rejestr udostępnia te dane tylko za zgodą przedsiębiorcy (art. 43 ust. 1 i 1a ustawy o CEIDG, Dz.U. 2026 poz. 507). Przed zmianą e-mail miało 19,9% aktywnych wpisów (próba 453 wpisów z 10.10.2026). Brak pola znaczy „nie wiadomo”, nie „firma nie ma maila”.
Czym różni się Hurtownia danych CEIDG od API?
Hurtownia danych to serwis dane.biznes.gov.pl z aplikacją raportową i gotowymi raportami, do którego logujesz się Profilem Zaufanym. API v3 to programowy dostęp do tej samej Hurtowni na kluczu z maila rejestracyjnego: wpisy (/firmy, /firma), zmiany (/zmiana) i raporty (/raporty). Konto i wniosek są wspólne.
Stan na 1 listopada 2026. Endpointy, parametry, limity i kody opisaliśmy według dokumentacji dla integratorów API v3 w wersji 1.1 z 14.01.2025 (odczyt 1.11.2026); nowszego archiwum dokumentacji z 22.04.2026 ze strony dla integratorów nie porównywaliśmy. Odpowiedzi bez klucza i z błędnym kluczem sprawdziliśmy 1.11.2026 o 19:25 i 19:33, tego dnia odczytaliśmy też strony dane.biznes.gov.pl, akademia.biznes.gov.pl, biznes.gov.pl i akty w ISAP. Brak PKD na liście (8.10.2026), daty i stronicowanie (10.10.2026), limit 25 na stronę i filtry obszaru (13.10.2026) oraz 429 i awarie (29-30.10.2026) to pomiary własne OutreachPilot.pl; udziały danych kontaktowych i PKD 2025 pochodzą z naszych raportów z 10.10 i 3.10.2026.
Wyszukaj firmy z Twojej branży i miasta.
OutreachPilot szuka firm w Google Maps, PKT.pl i CEIDG, pokazuje dostępne dane kontaktowe i od razu przygotowuje kampanię po polsku.
14 dni Pro bez karty · potem Free 0 zł
Podobne artykuły
API KRS: odpis aktualny w JSON, endpointy, pola i limity
Przewodnik po Open API KRS dla programisty: adresy OdpisAktualny, OdpisPelny i Biuletyn, ścieżki pól JSON, kody błędów, limity i kod w curl, Node i Pythonie.
Ile firm działa w Twojej branży? Liczenie wg PKD
Jak policzyć, ile firm działa w Twojej branży w Polsce: kod PKD, filtr w CEIDG i dane GUS krok po kroku oraz szacunek wielkości rynku (TAM) dla oferty.
Ile jest firm w Polsce w 2026? Liczby z REGON, CEIDG, KRS
Ile jest firm w Polsce w 2026 r.? Zestawienie liczb z REGON, CEIDG i KRS z datami i linkami do źródeł oraz wyjaśnienie, której liczby użyć do czego.
