Якщо ви інженер, якому щойно сказали, що “рахунки мають бути PDF/A-3 with Factur-X до наступного кварталу”, а весь ваш контекст полягає в тому, що юридична команда вимовила ці слова, ця стаття для вас.
Ми відкладемо тон документів зі стандартів і пояснимо, що ці профілі насправді обмежують, чому уряди почали їх вимагати, і який найменший практичний pipeline потрібен, щоб випускати compliant PDF зі structured-data renderer.
PDF/A у двох абзацах
PDF — гнучкий формат. Надто гнучкий: та сама PDF spec дозволяє embed JavaScript, посилатися на зовнішні ресурси, яких може не бути через 50 років, шифрувати content зворотною криптографією, reference external fonts і робити десятки інших речей, які позбавляють документ самодостатності.
PDF/A, де “A” означає Archival, — це профіль PDF, який забороняє частини, що можуть завадити документу render identically через 50 років. Правила високого рівня:
- Усі fonts мають бути embedded.
- Немає JavaScript, зовнішніх links, audio/video.
- Немає encryption.
- Уся transparency має бути flatten або підтримуватися версією профілю.
- Colours мають бути device-independent; потрібен ICC profile.
- Увесь content має бути всередині file; жодних references, що залежать від network.
Є кілька versions, кожна додає tolerance для новіших features:
| Profile | Year | Що додає |
|---|---|---|
| PDF/A-1b | 2005 | Original baseline, найсуворіший |
| PDF/A-2b | 2011 | Дозволяє JPEG2000, transparency, layers |
| PDF/A-3b | 2012 | Дозволяє arbitrary file attachments, основу Factur-X |
| PDF/A-4 | 2020 | База ISO 32000-2 (PDF 2.0), спрощені conformance levels |
Суфікс “b” означає “basic” conformance, тобто visual fidelity. Є також variants “u” для unicode-mapped і “a” для accessibility-tagged. Для більшості invoice/receipt workflows потрібен саме “b”, бо податкова архівація дбає про visual reproducibility, а не про screen-reader semantics.
Практичний висновок: якщо renderer каже, що підтримує PDF/A-3b, це має бути single config flag, наприклад { profile: "PDF/A-3b" } або еквівалент. Якщо доводиться запускати другу tool, таку як Ghostscript, qpdf або Acrobat, щоб конвертувати після render, це workflow gap, який потрібно закласти в ops.
Чому PDF/A-3 особливо важливий: це носій е-рахунків
PDF/A-3 додав одну capability, яка здається буденною, але виявилася фундаментальною: arbitrary file attachments всередині PDF.
Звучить нудно. Насправді ні. Це вся технічна основа e-invoice mandates, які зараз розгортаються в Європі.
Архітектура: один PDF file, який є одночасно:
- Human-readable invoice з visual layout, totals і branding.
- Machine-readable XML invoice, який parse робить software податкового органу.
Обидва всередині одного file, обидва представляють той самий invoice, а PDF/A-3 wrapper гарантує, що file залишиться parseable десятиліттями.
Основні XML formats:
- Factur-X (France), XML profile на базі UN/CEFACT Cross Industry Invoice.
- ZUGFeRD (Germany), по суті ідентичний Factur-X; два стандарти технічно об’єдналися у 2018 році.
- EN 16931, європейська норма, якій відповідають обидві implementations.
Для більшості workflows “Factur-X” і “ZUGFeRD” — взаємозамінні терміни. Вони share schema, share embedding mechanism, і PDF compliant з одним зазвичай compliant з іншим.
Що обов’язкове, де і коли
Невичерпний snapshot для engineers, які планують Q2/Q3 2026 rollouts:
| Country | Status | Required format |
|---|---|---|
| Germany | B2B mandatory для invoice receipt з 2025-01-01; з 2027 також для issuing | EN 16931 (Factur-X / ZUGFeRD / XRechnung) |
| France | mandatory issuing для large enterprises 2026-09; SMEs 2027-09 | Factur-X via Chorus Pro |
| Italy | B2B mandatory since 2019 | FatturaPA via SDI |
| Poland | Mandatory since 2024-07 | KSeF |
| Spain | Mandatory from 2026 (B2B) | Facturae via FACe |
| Belgium | Mandatory from 2026-01 | Peppol BIS 3 |
Патерн такий: кожна EU member state впроваджує певний flavour EN 16931-compliant e-invoicing у timeline 2024-2027. Якщо ваші customers працюють у будь-якому з цих markets, ваш PDF generator має emit attached XML поруч із visual invoice.
Найменший практичний pipeline
Забудьте на мить, що наказують standards documents. Engineering view такий:
┌─────────────────────┐
│ Your invoice data │ (вже десь JSON object)
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Build EN 16931 XML │ (deterministic mapping; tested libs існують)
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Render PDF/A-3b + │
│ attach the XML │ (single API call до gPdf, або two-step elsewhere)
└─────────┬───────────┘
│
▼
┌─────────────────────┐
│ Hand off to │
│ Chorus Pro / SDI / │
│ Peppol / etc │
└─────────────────────┘
Два non-trivial steps:
Step 1: побудуйте XML
Це дратує, але механічно. Ви map invoice data, наприклад lines, taxes, totals і parties, на EN 16931 XML field names. Є кілька Java/Node/Python libraries, які роблять це за вас; шукайте “factur-x library” для вашої language. Не пишіть з нуля, якщо ви справді не любите XML schema specs.
Step 2: render PDF/A-3 і attach XML
Тут має значення вибір renderer.
Без built-in support: ви render ordinary PDF, потім post-process tool’ом, який конвертує в PDF/A-3 і attach XML як embedded file. Common stacks: Ghostscript + qpdf або paid tool на кшталт Aspose. Це два extra steps, дві extra failure points, і потрібно стежити, щоб post-processing не змінив visual layout.
З built-in support (підхід gPdf): one call.
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 invoice-with-einvoice.pdf
Це весь pipeline. Renderer emit PDF/A-3b, attach ваш XML як factur-x.xml або zugferd-invoice.xml, обидва filenames розпізнають consumers, і повертає bytes.
Поширені пастки
Кілька речей, які люди часто вивчають важким шляхом:
“PDF/A” і “з PDF/A-compliant fonts” не те саме
PDF/A-3 file вимагає, щоб усі fonts були embedded з повним character coverage для used glyphs. Якщо invoice містить Japanese customer name, а renderer падає на fallback font, який не fully embeddable, validation tools його reject. Перевірте, що ваш renderer embed CJK fonts у PDF/A mode; багато хто не робить цього by default.
Visual + XML мають збігатися
XML invoice і visual invoice мають представляти той самий invoice. Tax auditors будуть їх diff. Якщо code emit XML з total: 119.00, а visual PDF показує Total: 120.00 через rounding bug або stale template, у вас tax discrepancy у file. Generate обидва з same source-of-truth, ideally в одному code path.
”Profile” levels в EN 16931
Factur-X має profiles: MINIMUM, BASIC, EN 16931, EXTENDED. Вони відрізняються кількістю data в XML. Використовуйте BASIC, якщо customer specifically не вимагає більше; він покриває tax codes, line items, parties і totals, чого достатньо для приблизно 95% B2B invoicing. EN 16931 profile додає further detail для edge cases.
Validation перед submission
Завжди validate generated PDF через PDF/A validator; veraPDF є open-source standard. Також validate XML проти EN 16931 schema перед відправкою до tax authority. Failed submissions до Chorus Pro / SDI впливають на ваші reliability metrics у regulator.
TL;DR
PDF/A — це self-contained-document profile. PDF/A-3 дозволяє attach files. Factur-X / ZUGFeRD означає “EN 16931 XML attached всередині PDF/A-3”. EU e-invoice mandates роблять цю комбінацію de facto B2B invoice format у 2025-2027.
Якщо renderer treats PDF/A-3 + Factur-X як single config flag, migration механічна. Якщо ні, ви будуєте multi-step ops pipeline. /api/v1/e-invoice/render у gPdf — single-flag version; повна schema є в API reference, або спробуйте sample render у Playground.