Blog

PDF/A i Factur-X / KSeF wyjaśnione dla inżynierów (bez prawniczego żargonu)

Co naprawdę ograniczają profile PDF/A, dlaczego KSeF stał się obowiązkowy w Polsce w 2024, i najmniejszy praktyczny pipeline do wydania zgodnego z renderera JSON.

Jeśli jesteś inżynierem, któremu właśnie powiedziano «faktury muszą być PDF/A-3 z Factur-X do następnego kwartału», a twój jedyny kontekst to to, że ktoś z działu prawnego wymówił te słowa, ten post jest dla ciebie.

Tniemy ton dokumentów standaryzacyjnych i wyjaśniamy, co naprawdę ograniczają te profile, dlaczego rządy zaczęły je nakazywać, i najmniejszy praktyczny pipeline do wydania zgodnego PDF z renderera danych strukturyzowanych.

PDF/A w dwóch akapitach

PDF jest elastycznym formatem. Zbyt elastycznym — ta sama specyfikacja PDF pozwala ci embedować JavaScript, linkować do zewnętrznych zasobów, które mogą nie istnieć za 50 lat, szyfrować treść odwracalną kryptografią, odwoływać się do zewnętrznych fontów, i sto innych rzeczy, które czynią dokument nie-samowystarczalnym.

PDF/A («A» od Archival) to profil PDF, który zakazuje części, które uniemożliwiałyby identyczne renderowanie dokumentu za 50 lat. Reguły wysokiego poziomu:

  • Wszystkie fonty muszą być embedded.
  • Bez JavaScript, bez zewnętrznych linków, bez audio/wideo.
  • Bez szyfrowania.
  • Cała przezroczystość musi być spłaszczona lub wspierana przez wersję profilu.
  • Kolory muszą być niezależne od urządzenia (wymagany profil ICC).
  • Cała treść musi być w pliku — bez referencji zależnych od sieci.

Istnieje kilka wersji, każda dodająca tolerancję dla nowszych funkcji:

ProfilRokCo dodaje
PDF/A-1b2005Oryginalna baza — najbardziej rygorystyczny
PDF/A-2b2011Pozwala na JPEG2000, przezroczystość, warstwy
PDF/A-3b2012Pozwala na dowolne załączniki plików (fundament Factur-X)
PDF/A-42020Baza ISO 32000-2 (PDF 2.0), uproszczone poziomy zgodności

Sufiks «b» oznacza zgodność «basic» (wierność wizualna). Istnieją też warianty «u» (mapowane unicode) i «a» (otagowane dla dostępności) — dla większości workflow faktura/paragon, «b» jest tym czego chcesz, bo archiwizacja podatkowa dba o wizualną powtarzalność, nie o semantykę dla czytników ekranowych.

Praktyczna konkluzja: jeśli twój renderer mówi, że obsługuje PDF/A-3b, powinno to być pojedyncze ustawienie konfiguracyjne ({ profile: "PDF/A-3b" } lub odpowiednik). Jeśli musisz uruchomić drugie narzędzie (Ghostscript, qpdf, Acrobat) do konwersji potem, to luka workflow do uwzględnienia w twoich ops.

Dlaczego PDF/A-3 ma znaczenie konkretnie: jest nośnikiem e-faktur

PDF/A-3 dodał możliwość, która okazała się zmieniać świat: załączniki dowolnych plików wewnątrz PDF.

Brzmi nudno. Nie jest. To cała techniczna podstawa mandatów e-faktur rolujących się w Europie właśnie teraz.

Architektura: pojedynczy plik PDF, który jest zarówno

  1. Czytelną dla człowieka fakturą (wizualny layout, sumy, branding) — częścią, którą czyta człowiek.
  2. Czytelną dla maszyny fakturą XML — częścią, którą parsuje oprogramowanie organu podatkowego.

Obie wewnątrz jednego pliku, obie reprezentujące tę samą fakturę, a wrapper PDF/A-3 gwarantuje, że plik nadal będzie parsowalny przez dziesięciolecia.

Dwa główne formaty XML:

  • Factur-X (Francja) — profil XML oparty na UN/CEFACT Cross Industry Invoice
  • ZUGFeRD (Niemcy) — zasadniczo identyczny z Factur-X (oba standardy połączyły się technicznie w 2018)
  • EN 16931 — norma europejska, do której obie implementacje się stosują
  • FA(2) / FA(3) (Polska) — polski format XML KSeF; może współistnieć z EN 16931 dla interoperacyjności EU

Dla większości workflow, «Factur-X» i «ZUGFeRD» to terminy wymienne — dzielą schemat, dzielą mechanizm embeddingu, a pojedynczy PDF zgodny z jednym jest zazwyczaj zgodny z drugim.

Co jest obowiązkowe, gdzie, kiedy

Niewyczerpujący snapshot dla inżynierów planujących rolloutsy Q2/Q3 2026:

KrajStatusWymagany format
PolskaB2B obowiązkowy od 2024-07 via KSeF; B2G wcześniejFA(2) / FA(3) via KSeF
NiemcyB2B obowiązkowy do odbioru od 2025-01-01; emisja od 2027EN 16931 (ZUGFeRD / Factur-X / XRechnung)
FrancjaEmisja obowiązkowa dla dużych przedsiębiorstw 2026-09; MŚP 2027-09Factur-X via Chorus Pro
WłochyB2B obowiązkowy od 2019FatturaPA via SDI
HiszpaniaObowiązkowy od 2026 (B2B)Facturae via FACe
BelgiaObowiązkowy od 2026-01Peppol BIS 3

Wzór: każde państwo członkowskie UE wdraża jakiś wariant e-fakturowania zgodnego z EN 16931 na osi czasu 2024–2027. Jeśli twoi klienci działają w którymkolwiek z tych rynków, twój generator PDF będzie musiał emitować załączony XML obok wizualnej faktury.

Dla polskich zespołów konkretnie: Krajowy System e-Faktur (KSeF) jest obsługiwany przez Ministerstwo Finansów. Każda polska faktura B2B musi być wysłana via KSeF w strukturyzowanym formacie XML FA(2)/FA(3). Przechowywanie 5 lat wymaga plików PDF/A-3 z embedded XML — dokładnie setup Factur-X / ZUGFeRD. Uwaga: aktualnie KSeF wymaga konkretnie polskiego formatu FA, ale wiele systemów ERP utrzymuje zarówno FA jak i równoległe Factur-X dla interoperacyjności EU.

Najmniejszy praktyczny pipeline

Zapomnij, co przepisują dokumenty standaryzacyjne. Oto widok inżyniera:

   ┌─────────────────────┐
   │  Dane twojej        │  (już obiekt JSON gdzieś)
   │      faktury        │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Zbuduj XML          │  (deterministyczne mapowanie; sprawdzone biblioteki istnieją)
   │     EN 16931 / FA   │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Wyrenderuj          │
   │ PDF/A-3b + dołącz   │  (jedno wywołanie API do gPdf — lub dwa kroki gdzie indziej)
   │       XML           │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │  Przekaż do         │
   │  KSeF / Chorus Pro/ │
   │  SDI / Peppol / etc │
   └─────────────────────┘

Dwa nietrywialne kroki:

Krok 1: zbuduj XML

To jest irytujące, ale mechaniczne. Mapujesz dane swojej faktury (linie, podatki, sumy, strony) na nazwy pól XML EN 16931 (lub FA dla KSeF). Kilka bibliotek Java/Node/Python robi to za ciebie — szukaj «factur-x library» lub «ksef library» w swoim języku. Nie pisz tego od zera, chyba że naprawdę cieszysz się specyfikacjami schematów XML.

Krok 2: wyrenderuj PDF/A-3 i dołącz XML

Tu liczy się wybór renderera.

Bez wbudowanego wsparcia: renderujesz zwykły PDF, potem post-processujesz narzędziem konwertującym do PDF/A-3 i dołączającym XML jako embedded plik. Powszechne stacki: Ghostscript + qpdf, lub płatne narzędzie jak Aspose. Dwa dodatkowe kroki, dwa dodatkowe punkty awarii i musisz upewnić się, że post-processing nie przesuwa wizualnego layoutu.

Z wbudowanym wsparciem (podejście gPdf): jedno wywołanie.

curl -X POST https://gpdf.com/api/v1/e-invoice/render \
  -H "Authorization: Bearer $TOKEN" \
  -H "Content-Type: application/json" \
  --data '{
    "document": {
      "pages": [{ "size": "a4", "elements": [...] }]
    },
    "einvoice": {
      "format": "factur-x",
      "profile": "BASIC",
      "xml": "<rsm:CrossIndustryInvoice>...</rsm:CrossIndustryInvoice>"
    }
  }' \
  --output faktura-z-factur-x.pdf

To cały pipeline. Renderer emituje PDF/A-3b, dołącza twoje XML jako factur-x.xml (lub zugferd-invoice.xml, oba rozpoznawane przez każdego konsumenta) i zwraca bajty.

Powszechne pułapki

Kilka rzeczy, których ludzie uczą się na trudnej drodze:

«PDF/A» i «z fontami zgodnymi z PDF/A» to nie to samo

Plik PDF/A-3 wymaga, żeby wszystkie fonty były embedded z pełnym pokryciem użytych glifów. Jeśli twoja faktura ma zagraniczne nazwisko klienta i renderer wraca do fontu, który nie jest w pełni embeddable, narzędzia walidacyjne ją odrzucą. Sprawdź, czy twój renderer embedduje fonty CJK w trybie PDF/A — wiele tego nie robi domyślnie.

Wizualna + XML muszą się zgadzać

Faktura XML i wizualna faktura mają reprezentować tę samą fakturę. Audytorzy podatkowi je zdiff-ują. Jeśli twój kod emituje XML z total: 119,00, a wizualne PDF pokazuje Total: 120,00 (z powodu buga zaokrąglania lub nieaktualnego szablonu), masz rozbieżność podatkową w aktach. Generuj obie z tego samego źródła prawdy, najlepiej w tej samej ścieżce kodu.

Poziomy «profilu» w EN 16931

Factur-X ma profile: MINIMUM, BASIC, EN 16931, EXTENDED. Różnią się tym, ile danych jest w XML. Użyj BASIC, chyba że twój klient konkretnie wymaga więcej — pokrywa kody podatkowe, linie, strony, sumy, co wystarcza dla ~95 % fakturowania B2B.

Walidacja przed wysłaniem

Zawsze waliduj wygenerowany PDF wobec walidatora PDF/A (veraPDF to standard open-source) i waliduj XML wobec schematu EN 16931 / FA przed wysłaniem do organu podatkowego. Nieudane wysyłki do KSeF / Chorus Pro / SDI liczą się przeciw twoim metrykom niezawodności u regulatora.

TL;DR

PDF/A to profil samowystarczalnego dokumentu. PDF/A-3 pozwala dołączać pliki. Factur-X / ZUGFeRD to «XML EN 16931 dołączony wewnątrz PDF/A-3». Mandaty e-faktur w UE czynią tę kombinację de facto formatem B2B w latach 2025–2027.

Jeśli twój renderer traktuje PDF/A-3 + Factur-X jako pojedyncze ustawienie konfiguracyjne, migracja jest mechaniczna. Jeśli nie, budujesz wieloetapowy pipeline ops. /api/v1/e-invoice/render od gPdf to wersja single-flag — referencja API ma pełny schemat, lub spróbuj przykładowego renderowania w Playground.