Blog · KSeF

KSeF API 2.0: jak podłączyć własny system krok po kroku

16 października 2026 · CodePort · 13 min czytania

Jeśli faktury powstają w Twoim własnym systemie, sklepie albo panelu, KSeF API pozwala wysyłać je do KSeF automatycznie, bez ręcznego logowania i przepisywania. Poniżej opisujemy, jak integracja z KSeF API 2.0 wygląda od strony programisty: od pierwszego logowania, przez wysyłkę faktury i UPO, po pobieranie faktur zakupowych, limity i tryb offline.

Opieramy się na oficjalnej dokumentacji Ministerstwa Finansów i na własnej pracy. W październiku 2026 r., budując własny moduł, przeszliśmy na środowisku testowym KSeF podstawową ścieżkę: logowanie podpisem XAdES i tokenem, wysyłkę faktur i korekt w sesji interaktywnej, UPO oraz odbiór faktur zakupowych. Sesji wsadowej, certyfikatu do trybu offline ani środowisk DEMO i PROD w tych testach nie było. To testy, nie wdrożenie produkcyjne u klienta, i tak je tu opisujemy.

Jak wygląda integracja z KSeF API 2.0 w skrócie?

Integracja składa się z sześciu elementów. Każdy da się zbudować i przetestować osobno:

Element Co robi Twój system Wywołania API
Uwierzytelnianie pobiera wyzwanie, podpisuje dokument z wyzwaniem albo szyfruje token, odbiera i odświeża tokeny JWT /auth/challenge, /auth/xades-signature lub /auth/ksef-token, GET /auth/{referenceNumber}, /auth/token/redeem, /auth/token/refresh
Sesja i wysyłka tworzy klucz AES-256, szyfruje go kluczem publicznym MF, otwiera sesję i wysyła zaszyfrowane faktury /security/public-key-certificates, /sessions/online i /sessions/online/{referenceNumber}/invoices albo /sessions/batch
Faktura FA(3) buduje XML z własnych danych i sprawdza go schematem XSD lokalnie, bez API
Status i UPO odczytuje status faktury i numer KSeF, zamyka sesję, pobiera UPO GET /sessions/{referenceNumber}/invoices/..., /sessions/online/{referenceNumber}/close lub /sessions/batch/{referenceNumber}/close, GET /sessions/{referenceNumber} (status sesji i numery zbiorczych UPO), GET /sessions/{referenceNumber}/upo/...
Odbiór faktur zleca eksport nowych faktur zakupowych i zapisuje je we własnej bazie /invoices/exports
Offline i kody QR umieszcza kod QR na fakturze; w trybie offline dodaje drugi kod i później dosyła fakturę do KSeF kody powstają lokalnie; certyfikat offline z /certificates/enrollments; dosłanie z offlineMode: true

Pełna lista wywołań jest w specyfikacji OpenAPI każdego środowiska, a opisy procesów — w oficjalnym repozytorium dokumentacji MF CIRFMF/ksef-api.

Środowiska KSeF API: TEST, DEMO i PROD

Środowisko Adres API Do czego służy
TEST https://api-test.ksef.mf.gov.pl/v2 testy integracji i wersje przedpremierowe; można logować się samopodpisanym certyfikatem
DEMO https://api-demo.ksef.mf.gov.pl/v2 końcowe sprawdzenie w konfiguracji takiej jak produkcyjna
PROD https://api.ksef.mf.gov.pl/v2 faktury o pełnej mocy prawnej

Trzy rzeczy warto wiedzieć przed pierwszym wywołaniem:

  • Dane na TEST nie są odizolowane. Wielu integratorów może zalogować się w kontekście tej samej firmy, dlatego do testów należy używać losowych numerów NIP i nie wprowadzać prawdziwych danych. U nas każdy test działa na wylosowanym NIP.
  • Na TEST nie licz na wyższe limity. Opis limitów w dokumentacji MF nadal mówi o wartościach dziesięciokrotnie wyższych niż na produkcji, ale według dziennika zmian od wersji 2.5.0 (na TEST od 6 maja 2026 r.) domyślne limity na TEST zrównano z produkcyjnymi. Takie same limity jak PROD ma też DEMO. Aktualne wartości dla swojego kontekstu zwraca GET /rate-limits, a na TEST można ustawić własny profil limitów przez POST /testdata/rate-limits.
  • Na środowiskach testowych bywają prace serwisowe w godzinach 16:00–18:00. Test, który sam przestał działać o 16:30, nie musi oznaczać błędu w Twoim kodzie.

Uwierzytelnianie w KSeF API: podpis XAdES albo token KSeF

Każde logowanie zaczyna się od wyzwania: POST /auth/challenge zwraca wyzwanie (challenge) ważne 10 minut i znacznik czasu. Dalej są dwie drogi:

  1. Podpis XAdES. Budujesz dokument AuthTokenRequest z wyzwaniem, identyfikatorem kontekstu (np. NIP firmy) i sposobem identyfikacji podpisującego (SubjectIdentifierType), podpisujesz go w formacie XAdES i wysyłasz na POST /auth/xades-signature. Na produkcji dokument podpisuje się m.in. kwalifikowanym podpisem elektronicznym, kwalifikowaną pieczęcią elektroniczną firmy, podpisem zaufanym (Profil Zaufany) albo certyfikatem KSeF. Na TEST wystarczy certyfikat wygenerowany samodzielnie.
  2. Token KSeF. Szyfrujesz ciąg token|timestampMs kluczem publicznym KSeF (RSA-OAEP z SHA-256) i wysyłasz go na POST /auth/ksef-token. Sam token generuje się przez POST /tokens, a to jest możliwe dopiero po jednorazowym zalogowaniu podpisem XAdES — więc bez podpisu nie zaczniesz integracji. Token ma stały zestaw uprawnień, np. InvoiceRead i InvoiceWrite, a zmiana uprawnień wymaga wygenerowania nowego tokena.

W obu przypadkach odpowiedź zawiera tymczasowy authenticationToken, a status sprawdzasz przez GET /auth/{referenceNumber} do skutku. Przy podpisie XAdES na DEMO i PROD KSeF sprawdza certyfikat u jego wystawcy (OCSP/CRL), więc status „Uwierzytelnianie w toku” przez dłuższą chwilę to normalny stan, a nie błąd. Certyfikat KSeF system weryfikuje u siebie od razu po otrzymaniu podpisu i dlatego MF zaleca logowanie właśnie nim. Na koniec POST /auth/token/redeem zwraca dwa tokeny JWT:

  • accessToken do autoryzacji kolejnych wywołań API (nagłówek Authorization: Bearer) — ważny krótko, do daty w polu exp (dokumentacja podaje przykładowo kilkanaście minut);
  • refreshToken do odświeżania przez POST /auth/token/refresh, ważny do 7 dni.

Szczegół z naszej pracy: w bibliotece xadesjs (Node.js) referencja do podpisywanego dokumentu musi mieć jawnie ustawione uri: ''. Bez tego KSeF odrzuca podpis kodem 9105 („Nieprawidłowy podpis”), a w szczegółach błędu podaje: „Element wskazywany przez referencję 'null' nie został odnaleziony”. Takie drobiazgi potrafią zabrać pół dnia.

Wysyłka faktur do KSeF: sesja interaktywna czy wsadowa?

Faktury wysyła się zawsze w sesji. Przed jej otwarciem tworzysz losowy klucz AES-256 i wektor IV, a klucz szyfrujesz algorytmem RSA-OAEP (SHA-256, MGF1) kluczem publicznym MF o przeznaczeniu (usage) SymmetricKeyEncryption. Klucze pobierasz z GET /security/public-key-certificates. To samo wywołanie zwraca też klucz KsefTokenEncryption do logowania tokenem, więc łatwo je pomylić.

Dalej sesje się różnią:

  • W sesji interaktywnej każdą fakturę szyfrujesz AES-256-CBC z dopełnieniem PKCS#7 i wysyłasz do otwartej sesji razem ze skrótami SHA-256 i rozmiarami pliku przed zaszyfrowaniem i po nim.
  • W sesji wsadowej pakujesz faktury do jednej paczki, dzielisz ją na części do 100 MB przed zaszyfrowaniem i szyfrujesz każdą część. Przy otwarciu sesji podajesz skrót SHA-256 i rozmiar całej, niezaszyfrowanej paczki oraz skrót i rozmiar każdej części już po zaszyfrowaniu, a części wysyłasz na adresy zwrócone w partUploadRequests — bez tokena dostępu w nagłówku.
Krok Wywołanie
Otwarcie sesji interaktywnej POST /sessions/online
Wysłanie faktury POST /sessions/online/{referenceNumber}/invoices
Zamknięcie sesji interaktywnej POST /sessions/online/{referenceNumber}/close
Otwarcie sesji wsadowej POST /sessions/batch
Wysłanie części paczki adresy z partUploadRequests, bez tokena dostępu
Zamknięcie sesji wsadowej POST /sessions/batch/{referenceNumber}/close

Sesja interaktywna żyje 12 godzin. MF zaleca sesję wsadową zawsze, gdy w jednym oknie operacyjnym wysyłasz więcej niż jedną fakturę. Limity otwarcia sesji na PROD i DEMO: interaktywnej 10 na sekundę, 30 na minutę i 120 na godzinę, a wsadowej 10 na sekundę, 20 na minutę i 60 na godzinę.

Dokumentacja podaje przykład sklepu internetowego: osobny proces zbiera wystawione faktury i np. co 5 minut wysyła je paczką, co znacząco ogranicza liczbę żądań. Przy dużych paczkach MF zaleca format tar.gz zamiast domyślnego ZIP, bo lepiej kompresuje powtarzalny XML.

Numer KSeF, UPO i duplikaty: jak nie zgubić faktury

Wysłanie faktury zwraca tylko numer referencyjny, bo przetwarzanie jest kolejkowane. Wynik sprawdzasz osobno, w statusie faktury w tej sesji (wywołania są w tabeli na początku tekstu). Dopiero gdy przetwarzanie zakończy się powodzeniem, status zawiera numer KSeF, który trzeba zapisać przy dokumencie w Twojej bazie. Gdy zamkniesz sesję, KSeF przygotuje zbiorcze UPO, czyli Urzędowe Poświadczenie Odbioru. Warto porównać skrót faktury w UPO ze skrótem wysłanego pliku — nasz moduł robi to przy każdej wysyłce.

Najważniejszy przypadek to zerwane połączenie: faktura poszła, ale odpowiedź nie dotarła, więc system wysyła ją ponownie. KSeF rozpoznaje duplikat po trzech polach: NIP sprzedawcy, rodzaj faktury i numer faktury (P_2), a treści nie porównuje. Unikalności pilnuje przez 10 pełnych lat, liczonych od końca roku, w którym faktura została wystawiona. Duplikat kończy się statusem 440 „Duplikat faktury”, a w polu extensions statusu są numer KSeF faktury przyjętej wcześniej (originalKsefNumber) i numer referencyjny jej sesji (originalSessionReferenceNumber).

Kod 440 oznacza więc tylko, że w KSeF jest już faktura tego samego sprzedawcy, tego samego rodzaju i o tym samym numerze — niekoniecznie ta, którą właśnie wysyłasz. Bezpieczna obsługa wygląda tak: pobierz UPO tej wcześniejszej faktury z jej sesji i porównaj zapisany tam skrót ze skrótem pliku, który wysyłasz. Skróty równe oznaczają tę samą fakturę i wtedy zapisujesz originalKsefNumber przy dokumencie. Skróty różne oznaczają, że pod tym numerem jest w KSeF inny plik — wtedy faktura trafia do ręcznej weryfikacji. Dlatego przy ponowieniu wysyłaj dokładnie ten sam, zapisany wcześniej plik XML, a nie generuj go od nowa: każda zmiana, choćby daty wytworzenia, daje inny skrót. Tak działa nasz moduł. Z tej samej reguły wynika, że oddziały wystawiające faktury w imieniu jednej firmy muszą uzgodnić numerację.

Struktura FA(3) i korekty: co sprawdzić przed wysłaniem

Na produkcji KSeF przyjmuje faktury w strukturze FA(3), a także m.in. w strukturach FA_PEF(3), FA_KOR_PEF(3) i — od 1 kwietnia 2026 r. — FA_RR(1) dla faktur VAT RR. Trzy zasady, które sprawdziły się w naszym module:

  • Sprawdzaj XML schematem XSD przed wysłaniem. Oficjalny schemat FA(3) jest publiczny, a walidacja lokalna (np. narzędziem xmllint) wyłapuje złą kolejność elementów i błędne formaty bez zużywania limitów API.
  • Licz kwoty na liczbach całkowitych w stałej skali. Wartości i sumy mają dwa miejsca po przecinku, więc wystarczą grosze, ale cena jednostkowa (P_9A) może mieć do 8 miejsc po przecinku, a ilość (P_8B) do 6. Liczby zmiennoprzecinkowe to prosta droga do różnicy jednego grosza między sumą pozycji a sumą faktury.
  • Korekty buduj według broszury MF. Faktura korygująca zawiera datę wystawienia i numer faktury korygowanej, a jeśli tamta ma numer KSeF — także ten numer. Zmienione pozycje można pokazać na kilka sposobów opisanych w „Broszurze informacyjnej dotyczącej struktury logicznej FA(3)” (wydanie z sierpnia 2026 r.): jako różnice, jako stan przed korektą (znacznik StanPrzed) i po niej albo metodą storna. My wybraliśmy stan przed i po korekcie. Porównaliśmy układ wierszy, ilości i kwoty z naszego generatora z przykładem 23 z broszury — wszystko się zgadza.

Faktury zaliczkowe, rozliczeniowe i w walucie obcej mają w FA(3) własne pola. Jeśli je wystawiasz, uwzględnij je w projekcie od początku.

Pobieranie faktur z KSeF API: eksport paczek i HWM

Od 1 lutego 2026 r. każda firma odbiera faktury zakupowe w KSeF, więc druga połowa integracji to pobieranie. Dokumentacja MF jest tu wyjątkowo konkretna:

  • Przy większej liczbie faktur pobieraj paczkami. Pobieranie faktur pojedynczo (GET /invoices/ksef/{ksefNumber}, limit 64 na godzinę) wystarcza tylko przy małej liczbie dokumentów. Standardem jest asynchroniczny eksport POST /invoices/exports w zaszyfrowanych częściach.
  • Okna czasowe według daty trwałego zapisu. Eksport z typem daty PermanentStorage i włączonym ograniczeniem do HWM zwraca dane do punktu, w którym KSeF gwarantuje kompletność (High Water Mark). Pola, których potrzebujesz, są w tabeli pod listą.
  • Duplikaty usuwaj po numerze KSeF z pliku _metadata.json, który jest w każdej paczce.
  • Nie częściej niż co 15 minut dla każdego typu podmiotu na fakturze i maksymalnie 20 eksportów na godzinę. Przy małej liczbie faktur MF zaleca pobieranie na żądanie i dodatkowo raz na dobę w nocy.
  • Użytkownicy pracują na Twojej bazie, nie na KSeF. Wyszukiwanie, filtrowanie i podgląd faktur powinny korzystać z lokalnej kopii. MF wymienia wywoływanie API przy każdym kliknięciu wśród błędów, które prowadzą do blokady.
Pole Gdzie Do czego służy
dateType: PermanentStorage żądanie eksportu okna według daty trwałego zapisu faktury
restrictToPermanentStorageHwmDate: true żądanie eksportu ogranicza eksport do punktu kompletności (HWM)
permanentStorageHwmDate odpowiedź, paczka początek następnego okna, gdy paczka jest pełna
isTruncated odpowiedź, paczka paczka obcięta — będzie kolejna część danych
lastPermanentStorageDate odpowiedź, paczka początek następnego okna, gdy paczka jest obcięta

W naszych testach na środowisku TEST świeża faktura pojawiała się w eksporcie po około 2 minutach od przyjęcia. Eksport z HWM zwraca dane tylko do punktu kompletności, więc nowa faktura trafia do paczki dopiero wtedy, gdy ten punkt przesunie się za nią. Integracja, która szuka faktury od razu po wysłaniu, uzna, że jej nie ma. Na produkcji to opóźnienie może być inne.

Stronę biznesową odbioru, czyli dopasowanie do kontrahenta i zamówienia oraz korekty, opisaliśmy w tekście o imporcie faktur zakupowych z KSeF.

Limity, tryb offline i zmiany w KSeF API

Limity i błąd 429

Po przekroczeniu limitu KSeF zwraca HTTP 429 z nagłówkiem Retry-After w sekundach. Blokada jest dynamiczna: powtarzane przekroczenia ją wydłużają, a obchodzenie limitów z wielu adresów IP system może uznać za zagrożenie bezpieczeństwa. Klient API powinien czekać tyle, ile każe Retry-After, i ponawiać z limitem prób, a nie w pętli bez przerwy. W godzinach 20:00–6:00 limity pobierania mają być wyższe, ale MF nie podało jeszcze ich wartości, więc nie opieraj na nich harmonogramu.

Tryb offline i kody QR

Faktura udostępniana poza KSeF, np. jako PDF albo wydruk, ma kod QR z linkiem weryfikacyjnym. Link składa się z kolejnych części oddzielonych ukośnikiem:

  • adres qr.ksef.mf.gov.pl/invoice (przez HTTPS),
  • NIP sprzedawcy,
  • data wystawienia z pola P_1 w formacie DD-MM-RRRR,
  • skrót SHA-256 pliku faktury w Base64URL.

Kod generuje Twój system, lokalnie. W trybie offline dochodzi drugi kod, który potwierdza wystawcę. Do niego potrzebny jest certyfikat KSeF typu Offline, wydawany przez API (/certificates/enrollments) — osobny, bo jeden certyfikat nie może służyć jednocześnie do logowania i do trybu offline. Fakturę wystawioną offline trzeba potem dosłać do KSeF z oznaczeniem offlineMode: true.

Terminy dosłania faktur z trybów offline i to, do kiedy działają tokeny KSeF, zebraliśmy w tekście o karach za KSeF od 2027 roku.

API zmienia się co kilka tygodni

KSeF API 2.0 ma publiczny dziennik zmian. Od połowy września 2026 r. wyszły trzy wersje: 2.8.0 (na TEST 14 września, na PROD 23 września), 2.8.1 (TEST 22 września, PROD 23 września) i 2.9.0 (TEST 13 października, PROD 15 października). Zwykle to rozszerzenia, ale zmieniały się też limity i opisy kodów błędów. Między TEST a PROD bywa tylko jeden dzień, jak przy wersji 2.8.1, więc dziennik zmian trzeba śledzić na bieżąco, a nowe wersje sprawdzać na TEST od razu. Utrzymanie integracji to typowo 5 – 15 godzin miesięcznie.

Ile trwa integracja z KSeF API i kiedy można ją uprościć?

Orientacyjne widełki dla integracji systemów i KSeF, liczone zawsze jako godziny × 200 zł netto:

  • Wysyłka faktur do KSeF: 24 – 60 godzin, czyli 4 800 – 12 000 zł netto.
  • Odbiór faktur zakupowych: 38 – 100 godzin, czyli 7 600 – 20 000 zł netto.
  • Pełny odbiór faktur zakupowych: 78 – 202 godziny, czyli 15 600 – 40 400 zł netto — z obiegiem akceptacji, powiadomieniami o nowych fakturach i o błędach, załącznikami, drugim kanałem na faktury spoza KSeF i archiwum.

Widełki powyżej nie obejmują 12 – 24 godzin na architekturę, logi i wdrożenie całego projektu — kalkulator wyceny dolicza je do wyniku. Sam kalkulator liczy połączenie z KSeF (24 – 60 godzin przy udokumentowanym API), ale nie ma w nim pozycji na dopasowanie faktur, korekty, obieg akceptacji, powiadomienia o nowych fakturach, załączniki, drugi kanał i archiwum — przy odbiorze faktur zakupowych te bloki trzeba doliczyć osobno.

Najwięcej pracy nie wymaga sama wysyłka, tylko wszystko wokół niej: ponowienia po zerwanym połączeniu, duplikaty, okna HWM, limity i tryb offline.

Kiedy można prościej:

  • Wystawiasz faktury w programie do fakturowania albo w ERP z obsługą KSeF. Wtedy wystarczy moduł dostawcy, konfiguracja uprawnień i test trybu offline. Integracja przez API nie jest potrzebna.
  • Twój system jest napisany w .NET albo w Javie. MF udostępnia oficjalne biblioteki klienckie (licencja MIT), które obsługują logowanie XAdES, sesje i kody QR. Zacznij od nich, zamiast pisać wszystko od zera. My pracujemy w TypeScript, dlatego zbudowaliśmy własny moduł, a biblioteki MF traktowaliśmy jako wzór.

Jeśli faktury powstają u Ciebie we własnym systemie, ogólny przebieg projektu i to, co przygotować przed rozmową z programistą, opisaliśmy w tekście o integracji KSeF z własnym systemem, sklepem lub ERP.

Zakres obowiązków podatkowych Twojej firmy potwierdź w swojej księgowości — CodePort odpowiada za stronę techniczną.

Najczęstsze pytania

Czy KSeF ma publiczne API?

Tak. KSeF API 2.0 działa na trzech środowiskach: TEST (api-test.ksef.mf.gov.pl), DEMO i PROD. Specyfikację OpenAPI i opisy procesów publikuje Ministerstwo Finansów, m.in. w repozytorium CIRFMF/ksef-api na GitHubie.

Czy do testów KSeF API potrzebny jest podpis kwalifikowany?

Nie. Na środowisku TEST można logować się samopodpisanym certyfikatem w kontekście wylosowanego numeru NIP. Prawdziwych danych firm nie należy tam wprowadzać, bo dane na TEST nie są odizolowane między integratorami.

Jak długo ważny jest token dostępowy KSeF?

Token dostępowy (accessToken, JWT) jest ważny krótko, do daty w polu exp — dokumentacja podaje przykładowo kilkanaście minut. Bez ponownego logowania odświeża się go tokenem odświeżającym (refreshToken), który jest ważny do 7 dni. To co innego niż token KSeF, którym można się zalogować.

Jak często pobierać faktury zakupowe z KSeF?

Nie częściej niż co 15 minut dla każdego typu podmiotu na fakturze, w ramach limitu 20 eksportów na godzinę. Przy małej liczbie faktur MF zaleca pobieranie na żądanie i dodatkowo raz na dobę w nocy.

Co się stanie, gdy wyślę tę samą fakturę do KSeF drugi raz?

W statusie faktury pojawi się kod 440 „Duplikat faktury” razem z numerem KSeF faktury przyjętej wcześniej. KSeF rozpoznaje duplikat tylko po NIP sprzedawcy, rodzaju i numerze faktury, a treści nie porównuje. Zanim zapiszesz ten numer, porównaj skrót z UPO wcześniejszej faktury ze skrótem swojego pliku: równe skróty oznaczają tę samą fakturę, różne — że numer zajął inny dokument.

Podłączmy Twój system do KSeF

Opisz w briefie, gdzie powstają faktury i w jakiej technologii działa Twój system. Bezpłatne widełki i harmonogram dostaniesz w 2–3 dni robocze.

Wypełnij brief →
← Wróć do bloga