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:
| Profil | Rok | Co dodaje |
|---|---|---|
| PDF/A-1b | 2005 | Oryginalna baza — najbardziej rygorystyczny |
| PDF/A-2b | 2011 | Pozwala na JPEG2000, przezroczystość, warstwy |
| PDF/A-3b | 2012 | Pozwala na dowolne załączniki plików (fundament Factur-X) |
| PDF/A-4 | 2020 | Baza 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
- Czytelną dla człowieka fakturą (wizualny layout, sumy, branding) — częścią, którą czyta człowiek.
- 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:
| Kraj | Status | Wymagany format |
|---|---|---|
| Polska | B2B obowiązkowy od 2024-07 via KSeF; B2G wcześniej | FA(2) / FA(3) via KSeF |
| Niemcy | B2B obowiązkowy do odbioru od 2025-01-01; emisja od 2027 | EN 16931 (ZUGFeRD / Factur-X / XRechnung) |
| Francja | Emisja obowiązkowa dla dużych przedsiębiorstw 2026-09; MŚP 2027-09 | Factur-X via Chorus Pro |
| Włochy | B2B obowiązkowy od 2019 | FatturaPA via SDI |
| Hiszpania | Obowiązkowy od 2026 (B2B) | Facturae via FACe |
| Belgia | Obowiązkowy od 2026-01 | Peppol 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.