Блог

PDF/A и Factur-X объяснены инженерам (без юридического жаргона)

Что профили PDF/A реально ограничивают, почему Factur-X становится обязательным в ЕС в 2026, и наименьший практический pipeline для соответствия из JSON-renderer.

Если вы инженер, которому только что сказали «счета должны быть PDF/A-3 с Factur-X к следующему кварталу», и ваш единственный контекст в том, что кто-то из юридического отдела произнёс эти слова, этот пост для вас.

Срезаем тон документов стандартизации и объясняем, что эти профили реально ограничивают, почему правительства начали их обязывать, и наименьший практический pipeline для эмиссии compliant PDF из renderer-а структурированных данных.

PDF/A в двух абзацах

PDF — гибкий формат. Слишком гибкий — та же спецификация PDF позволяет встраивать JavaScript, ссылаться на внешние ресурсы, которые могут не существовать через 50 лет, шифровать содержимое обратимой криптографией, ссылаться на внешние шрифты, и сотню других вещей, делающих документ не-самодостаточным.

PDF/A («A» от Archival) — профиль PDF, запрещающий части, которые мешали бы документу рендериться идентично через 50 лет. Высокоуровневые правила:

  • Все шрифты должны быть встроены.
  • Никакого JavaScript, внешних ссылок, аудио/видео.
  • Никакого шифрования.
  • Вся прозрачность должна быть сплющена или поддерживаться версией профиля.
  • Цвета должны быть аппаратно-независимыми (требуется ICC-профиль).
  • Всё содержимое должно быть в файле — никаких ссылок, зависящих от сети.

Существует несколько версий, каждая добавляет толерантность к более новым функциям:

ПрофильГодЧто добавляет
PDF/A-1b2005Изначальный baseline — самый строгий
PDF/A-2b2011Разрешает JPEG2000, прозрачность, слои
PDF/A-3b2012Разрешает произвольные вложения файлов (фундамент Factur-X)
PDF/A-42020База ISO 32000-2 (PDF 2.0), упрощённые уровни соответствия

Суффикс «b» означает «basic» соответствие (визуальная верность). Также есть варианты «u» (Unicode-mapped) и «a» (accessibility-tagged) — для большинства workflow-ов счёт/чек, «b» — то, что вам нужно, потому что фискальное архивирование заботится о визуальной воспроизводимости, а не семантике для screen reader.

Практический вывод: если ваш renderer говорит, что поддерживает PDF/A-3b, это должен быть единственный config-флаг ({ profile: "PDF/A-3b" } или эквивалент). Если приходится запускать второй инструмент (Ghostscript, qpdf, Acrobat) для конвертации потом, это пробел в workflow для учёта в ваших ops.

Почему PDF/A-3 особенно важен: он носитель электронных счетов

PDF/A-3 добавил одну способность, которая оказалась мир-меняющей: произвольные вложения файлов внутри PDF.

Звучит скучно. Это не так. Это вся техническая основа мандатов электронных счетов, разворачивающихся по Европе прямо сейчас.

Архитектура: единственный файл PDF, который одновременно

  1. Человеко-читаемый счёт (визуальный layout, итоги, брендинг) — часть, которую читает человек.
  2. Машинно-читаемый XML-счёт — часть, которую парсит софт налоговой инстанции.

Оба внутри одного файла, оба представляют тот же счёт, и обёртка PDF/A-3 гарантирует, что файл будет parseable десятилетиями.

Два главных XML-формата:

  • Factur-X (Франция) — XML-профиль на основе UN/CEFACT Cross Industry Invoice
  • ZUGFeRD (Германия) — по сути идентичен Factur-X (две стандарта технически слились в 2018)
  • EN 16931 — европейская норма, которой соответствуют обе реализации

Для большинства workflow-ов «Factur-X» и «ZUGFeRD» — взаимозаменяемые термины — делят схему, делят механизм встраивания, и единственный PDF, compliant с одним, обычно compliant с другим.

Что обязательно, где, когда

Неисчерпывающий снимок для инженеров, планирующих rollout-ы Q2/Q3 2026:

СтранаСтатусТребуемый формат
ГерманияB2B обязателен для приёма с 2025-01-01; эмиссия с 2027EN 16931 (ZUGFeRD / Factur-X / XRechnung)
ФранцияЭмиссия обязательна для крупных предприятий 2026-09; МСП 2027-09Factur-X через Chorus Pro
ИталияB2B обязателен с 2019FatturaPA через SDI
ПольшаОбязателен с 2024-07KSeF
ИспанияОбязателен с 2026 (B2B)Facturae через FACe
БельгияОбязателен с 2026-01Peppol BIS 3
РоссияЭДО для счёт-фактур (УПД) с 2014; маркированные товары с 2019XML УПД через операторов ЭДО

Паттерн: каждое государство-член ЕС реализует какой-то вариант EN 16931-compliant электронного счёт-фактуры на timeline 2024–2027. Если ваши клиенты работают в любом из этих рынков, ваш PDF-генератор должен будет эмитировать прикреплённый XML рядом с визуальным счётом.

Для российских команд: российский ЭДО (электронный документооборот) управляется через операторов ЭДО (СКБ Контур, ТАКСКОМ, Тензор и др.) с XML УПД (Универсальный Передаточный Документ). Хотя схема российская и не EN 16931, концепция идентична Factur-X: структурированный XML + визуальное представление. Для интеграции с европейскими партнёрами тот же endpoint gPdf генерирует Factur-X согласно EU стандартам.

Наименьший практический pipeline

Забудьте, что предписывают документы стандартизации. Вот вид инженера:

   ┌─────────────────────┐
   │  Данные счёта       │  (уже JSON-объект где-то)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Построить XML       │  (детерминистичный mapping; проверенные libs существуют)
   │   EN 16931 / УПД    │
   └─────────┬───────────┘


   ┌─────────────────────┐
   │ Рендерить PDF/A-3b  │
   │ + прикрепить XML    │  (один API-вызов к gPdf — или два шага в других)
   └─────────┬───────────┘


   ┌─────────────────────┐
   │  Передать в         │
   │  ЭДО / Chorus Pro / │
   │  SDI / Peppol / etc │
   └─────────────────────┘

Два нетривиальных шага:

Шаг 1: построить XML

Это раздражает, но механически. Вы маппите данные счёта (строки, налоги, итоги, стороны) на имена полей XML EN 16931 (или УПД для России). Несколько Java/Node/Python библиотек делают это за вас — ищите «factur-x library» или «упд library» в вашем языке. Не пишите с нуля, если вы действительно не наслаждаетесь спецификациями XML-схем.

Шаг 2: рендерить PDF/A-3 и прикрепить XML

Здесь имеет значение выбор renderer-а.

Без встроенной поддержки: вы рендерите обычный PDF, затем post-обрабатываете инструментом, который конвертирует в PDF/A-3 и прикрепляет XML как встроенный файл. Распространённые стеки: Ghostscript + qpdf, или платный инструмент типа Aspose. Два дополнительных шага, две дополнительные точки отказа, и нужно убедиться, что post-обработка не сдвигает визуальный layout.

Со встроенной поддержкой (подход gPdf): один вызов.

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 schet-s-factur-x.pdf

Это весь pipeline. Renderer эмитирует PDF/A-3b, прикрепляет ваш XML как factur-x.xml (или zugferd-invoice.xml, оба распознаются каждым потребителем) и возвращает байты.

Распространённые ловушки

Несколько вещей, которые люди узнают тяжёлым путём:

«PDF/A» и «со шрифтами compliant PDF/A» — не одно и то же

PDF/A-3 файл требует, чтобы все шрифты были встроены с полным покрытием используемых глифов. Если в счёте имя иностранного клиента, и renderer падает на шрифт, который не полностью встраиваемый, инструменты валидации отклонят его. Проверьте, встраивает ли ваш renderer CJK-шрифты в режиме PDF/A — многие не делают этого по умолчанию.

Визуальное + XML должны совпадать

XML-счёт и визуальный счёт должны представлять тот же счёт. Налоговые аудиторы будут diff их. Если ваш код эмитирует XML с total: 119,00, а визуальный PDF показывает Итого: 120,00 (из-за бага округления или устаревшего шаблона), у вас расхождение по налогам в файлах. Генерируйте оба из того же source-of-truth, идеально в том же code path.

Уровни «профиля» в EN 16931

Factur-X имеет профили: MINIMUM, BASIC, EN 16931, EXTENDED. Различаются по тому, сколько данных в XML. Используйте BASIC, если ваш клиент специально не требует больше — покрывает налоговые коды, строки, стороны, итоги, что достаточно для ~95% B2B-счёт-фактур.

Валидация перед отправкой

Всегда валидируйте сгенерированный PDF против PDF/A-валидатора (veraPDF — open-source стандарт) и валидируйте XML против схемы EN 16931 / УПД перед отправкой в налоговую инстанцию. Неудачные отправки в Chorus Pro / SDI / ЭДО считают против ваших метрик надёжности у регулятора.

TL;DR

PDF/A — профиль самосодержащегося документа. PDF/A-3 позволяет прикреплять файлы. Factur-X / ZUGFeRD — это «XML EN 16931, прикреплённый внутри PDF/A-3». Мандаты электронного счёт-фактуры по ЕС делают эту комбинацию де-факто B2B-форматом счёта 2025–2027.

Если ваш renderer обращается с PDF/A-3 + Factur-X как с единственным config-флагом, миграция механическая. Если нет, вы строите multi-step ops pipeline. /api/v1/e-invoice/render от gPdf — single-flag версия — API-справочник имеет полную схему, или попробуйте sample-render в Playground.